diff options
Diffstat (limited to 'sim/h8300')
-rw-r--r-- | sim/h8300/ChangeLog | 12 | ||||
-rw-r--r-- | sim/h8300/compile.c | 133 |
2 files changed, 109 insertions, 36 deletions
diff --git a/sim/h8300/ChangeLog b/sim/h8300/ChangeLog index 1ff3d42..3bd23ec 100644 --- a/sim/h8300/ChangeLog +++ b/sim/h8300/ChangeLog @@ -1,3 +1,15 @@ +2003-07-18 Michael Snyder <msnyder@redhat.com> + + * compile.c (decode): Enhancements for mova. + Initialize cst, reg, and rdisp inside the loop, for each + new instruction. Defer correction of the disp2 values until + later, and then adjust them by the size of the first operand, + rather than the size of the instruction. + (sim_resume): For mova, adjust the size of the second operand + according to the type of the first operand (INDEXB vs. INDEXW). + In cases where there is only one operand, the other two must + both be composed on the fly. + 2003-07-22 Michael Snyder <msnyder@redhat.com> * compile.c (sim_resume): Revert 6-24 change, it does not diff --git a/sim/h8300/compile.c b/sim/h8300/compile.c index 904bdf7..a799d2b 100644 --- a/sim/h8300/compile.c +++ b/sim/h8300/compile.c @@ -606,6 +606,10 @@ decode (SIM_DESC sd, int addr, unsigned char *data, decoded_inst *dst) (q->available == AV_H8H && !h8300hmode)) continue; + cst[0] = cst[1] = cst[2] = 0; + reg[0] = reg[1] = reg[2] = 0; + rdisp[0] = rdisp[1] = rdisp[2] = 0; + while (1) { op_type looking_for = *nib; @@ -770,26 +774,11 @@ decode (SIM_DESC sd, int addr, unsigned char *data, decoded_inst *dst) (looking_for & MODE) == INDEXB || (looking_for & MODE) == INDEXW || (looking_for & MODE) == INDEXL) - { switch (looking_for & SIZE) { case L_2: cst[opnum] = thisnib & 3; - - /* DISP2 special treatment. */ - if ((looking_for & MODE) == DISP) - { - switch (OP_SIZE (q->how)) { - default: break; - case SW: - cst[opnum] *= 2; - break; - case SL: - cst[opnum] *= 4; - break; - } - } break; case L_8: cst[opnum] = SEXTCHAR (data[len / 2]); @@ -1072,31 +1061,64 @@ decode (SIM_DESC sd, int addr, unsigned char *data, decoded_inst *dst) p->type = X (OP_IMM, SP); p->literal = cst[opnum]; } - else if ((x & MODE) == INDEXB || - (x & MODE) == INDEXW || - (x & MODE) == INDEXL || - (x & MODE) == DISP) + else if ((x & MODE) == INDEXB) { - /* Use the instruction to determine - the operand size. */ - switch (x & MODE) { - case INDEXB: - p->type = X (OP_INDEXB, OP_SIZE (q->how)); - break; - case INDEXW: - p->type = X (OP_INDEXW, OP_SIZE (q->how)); - break; - case INDEXL: - p->type = X (OP_INDEXL, OP_SIZE (q->how)); - break; - case DISP: - p->type = X (OP_DISP, OP_SIZE (q->how)); - break; - } - + p->type = X (OP_INDEXB, OP_SIZE (q->how)); + p->literal = cst[opnum]; + p->reg = rdisp[opnum]; + } + else if ((x & MODE) == INDEXW) + { + p->type = X (OP_INDEXW, OP_SIZE (q->how)); p->literal = cst[opnum]; p->reg = rdisp[opnum]; } + else if ((x & MODE) == INDEXL) + { + p->type = X (OP_INDEXL, OP_SIZE (q->how)); + p->literal = cst[opnum]; + p->reg = rdisp[opnum]; + } + else if ((x & MODE) == DISP) + { + /* Yuck -- special for mova args. */ + if (strncmp (q->name, "mova", 4) == 0 && + (x & SIZE) == L_2) + { + /* Mova can have a DISP2 dest, with an + INDEXB or INDEXW src. The multiplier + for the displacement value is determined + by the src operand, not by the insn. */ + + switch (OP_KIND (dst->src.type)) + { + case OP_INDEXB: + p->type = X (OP_DISP, SB); + p->literal = cst[opnum]; + break; + case OP_INDEXW: + p->type = X (OP_DISP, SW); + p->literal = cst[opnum] * 2; + break; + default: + goto fail; + } + } + else + { + p->type = X (OP_DISP, OP_SIZE (q->how)); + p->literal = cst[opnum]; + /* DISP2 is special. */ + if ((x & SIZE) == L_2) + switch (OP_SIZE (q->how)) + { + case SB: break; + case SW: p->literal *= 2; break; + case SL: p->literal *= 4; break; + } + } + p->reg = rdisp[opnum]; + } else if (x & CTRL) { switch (reg[opnum]) @@ -1979,8 +2001,44 @@ sim_resume (SIM_DESC sd, int step, int siggnal) (mova/b, mova/w, mova/l). 4) Add literal value of 1st argument (src). 5) Store result in 3rd argument (op3). + */ + + /* Alas, since this is the only instruction with 3 arguments, + decode doesn't handle them very well. Some fix-up is required. + + a) The size of dst is determined by whether src is + INDEXB or INDEXW. */ + if (OP_KIND (code->src.type) == OP_INDEXB) + code->dst.type = X (OP_KIND (code->dst.type), SB); + else if (OP_KIND (code->src.type) == OP_INDEXW) + code->dst.type = X (OP_KIND (code->dst.type), SW); + + /* b) If op3 == null, then this is the short form of the insn. + Dst is the dispreg of src, and op3 is the 32-bit form + of the same register. */ + + if (code->op3.type == 0) + { + /* Short form: src == INDEXB/INDEXW, dst == op3 == 0. + We get to compose dst and op3 as follows: + + op3 is a 32-bit register, ID == src.reg. + dst is the same register, but 8 or 16 bits + depending on whether src is INDEXB or INDEXW. + */ + + code->op3.type = X (OP_REG, SL); + code->op3.reg = code->src.reg; + code->op3.literal = 0; + + if (OP_KIND (code->src.type) == OP_INDEXB) + code->dst.type = X (OP_REG, SB); + else + code->dst.type = X (OP_REG, SW); + } + if (fetch (sd, &code->dst, &ea)) goto end; @@ -3578,6 +3636,9 @@ sim_resume (SIM_DESC sd, int step, int siggnal) SIM_WEXITSTATUS (h8_get_reg (sd, 0))); } #if 0 + /* Unfortunately this won't really work, because + when we take a breakpoint trap, R0 has a "random", + user-defined value. Don't see any immediate solution. */ else if (SIM_WIFSTOPPED (h8_get_reg (sd, 0))) { /* Pass the stop signal up to gdb. */ |