aboutsummaryrefslogtreecommitdiff
path: root/sim/h8300
diff options
context:
space:
mode:
Diffstat (limited to 'sim/h8300')
-rw-r--r--sim/h8300/ChangeLog12
-rw-r--r--sim/h8300/compile.c133
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. */