dis/sim: fix handling of opcodes with two indexed operands.
If the source operand is indexed, and the destination is symbolic (PC + index), then the base for the destination index is the program counter *after* having fetched the source index. Also, the addition of the index is done modulo 2^16 if the base points within the lower 64 kB of memory.
This commit is contained in:
parent
72e781d0eb
commit
e9b6a77414
|
@ -100,10 +100,10 @@ static int fetch_operand(struct sim_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = MEM_GETW(dev, dev->regs[MSP430_REG_PC]);
|
addr = MEM_GETW(dev, dev->regs[MSP430_REG_PC]);
|
||||||
dev->regs[MSP430_REG_PC] += 2;
|
|
||||||
|
|
||||||
if (reg != MSP430_REG_SR)
|
if (reg != MSP430_REG_SR)
|
||||||
addr += dev->regs[reg];
|
addr += dev->regs[reg];
|
||||||
|
|
||||||
|
dev->regs[MSP430_REG_PC] += 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSP430_AMODE_INDIRECT:
|
case MSP430_AMODE_INDIRECT:
|
||||||
|
|
58
util/dis.c
58
util/dis.c
|
@ -32,6 +32,14 @@
|
||||||
/* Disassembler
|
/* Disassembler
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static address_t add_index(address_t reg_base, uint16_t index)
|
||||||
|
{
|
||||||
|
if (reg_base >> 16)
|
||||||
|
return reg_base + index;
|
||||||
|
|
||||||
|
return (reg_base + index) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_00xx(const uint8_t *code, address_t len,
|
static int decode_00xx(const uint8_t *code, address_t len,
|
||||||
struct msp430_instruction *insn)
|
struct msp430_instruction *insn)
|
||||||
{
|
{
|
||||||
|
@ -286,7 +294,8 @@ static int decode_single(const uint8_t *code, address_t offset,
|
||||||
if (size < 4)
|
if (size < 4)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
insn->dst_addr += (code[3] << 8) | code[2];
|
insn->dst_addr = add_index(insn->dst_addr,
|
||||||
|
(code[3] << 8) | code[2]);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +315,7 @@ static int decode_double(const uint8_t *code, address_t offset,
|
||||||
int need_dst = 0;
|
int need_dst = 0;
|
||||||
int ret = 2;
|
int ret = 2;
|
||||||
|
|
||||||
|
/* Decode and consume opcode */
|
||||||
insn->itype = MSP430_ITYPE_DOUBLE;
|
insn->itype = MSP430_ITYPE_DOUBLE;
|
||||||
insn->op = op & 0xf000;
|
insn->op = op & 0xf000;
|
||||||
insn->dsize = (op & 0x0040) ? MSP430_DSIZE_BYTE : MSP430_DSIZE_WORD;
|
insn->dsize = (op & 0x0040) ? MSP430_DSIZE_BYTE : MSP430_DSIZE_WORD;
|
||||||
|
@ -316,21 +326,11 @@ static int decode_double(const uint8_t *code, address_t offset,
|
||||||
insn->dst_mode = (op >> 7) & 0x1;
|
insn->dst_mode = (op >> 7) & 0x1;
|
||||||
insn->dst_reg = op & 0xf;
|
insn->dst_reg = op & 0xf;
|
||||||
|
|
||||||
switch (insn->dst_mode) {
|
offset += 2;
|
||||||
case MSP430_AMODE_REGISTER: break;
|
code += 2;
|
||||||
case MSP430_AMODE_INDEXED:
|
size -= 2;
|
||||||
need_dst = 1;
|
|
||||||
|
|
||||||
if (insn->dst_reg == MSP430_REG_PC) {
|
|
||||||
insn->dst_mode = MSP430_AMODE_SYMBOLIC;
|
|
||||||
insn->dst_addr = offset + 2;
|
|
||||||
} else if (insn->dst_reg == MSP430_REG_SR)
|
|
||||||
insn->dst_mode = MSP430_AMODE_ABSOLUTE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Decode and consume source operand */
|
||||||
switch (insn->src_mode) {
|
switch (insn->src_mode) {
|
||||||
case MSP430_AMODE_REGISTER: break;
|
case MSP430_AMODE_REGISTER: break;
|
||||||
case MSP430_AMODE_INDEXED:
|
case MSP430_AMODE_INDEXED:
|
||||||
|
@ -338,7 +338,7 @@ static int decode_double(const uint8_t *code, address_t offset,
|
||||||
|
|
||||||
if (insn->src_reg == MSP430_REG_PC) {
|
if (insn->src_reg == MSP430_REG_PC) {
|
||||||
insn->src_mode = MSP430_AMODE_SYMBOLIC;
|
insn->src_mode = MSP430_AMODE_SYMBOLIC;
|
||||||
insn->dst_addr = offset + 2;
|
insn->dst_addr = offset;
|
||||||
} else if (insn->src_reg == MSP430_REG_SR)
|
} else if (insn->src_reg == MSP430_REG_SR)
|
||||||
insn->src_mode = MSP430_AMODE_ABSOLUTE;
|
insn->src_mode = MSP430_AMODE_ABSOLUTE;
|
||||||
else if (insn->src_reg == MSP430_REG_R3)
|
else if (insn->src_reg == MSP430_REG_R3)
|
||||||
|
@ -357,26 +357,40 @@ static int decode_double(const uint8_t *code, address_t offset,
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += 2;
|
|
||||||
code += 2;
|
|
||||||
size -= 2;
|
|
||||||
|
|
||||||
if (need_src) {
|
if (need_src) {
|
||||||
if (size < 2)
|
if (size < 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
insn->src_addr += (code[1] << 8) | code[0];
|
insn->src_addr = add_index(insn->src_addr,
|
||||||
|
((code[1] << 8) | code[0]));
|
||||||
offset += 2;
|
offset += 2;
|
||||||
code += 2;
|
code += 2;
|
||||||
size -= 2;
|
size -= 2;
|
||||||
ret += 2;
|
ret += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Decode and consume destination operand */
|
||||||
|
switch (insn->dst_mode) {
|
||||||
|
case MSP430_AMODE_REGISTER: break;
|
||||||
|
case MSP430_AMODE_INDEXED:
|
||||||
|
need_dst = 1;
|
||||||
|
|
||||||
|
if (insn->dst_reg == MSP430_REG_PC) {
|
||||||
|
insn->dst_mode = MSP430_AMODE_SYMBOLIC;
|
||||||
|
insn->dst_addr = offset;
|
||||||
|
} else if (insn->dst_reg == MSP430_REG_SR)
|
||||||
|
insn->dst_mode = MSP430_AMODE_ABSOLUTE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
if (need_dst) {
|
if (need_dst) {
|
||||||
if (size < 2)
|
if (size < 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
insn->dst_addr += (code[1] << 8) | code[0];
|
insn->dst_addr = add_index(insn->dst_addr,
|
||||||
|
(code[1] << 8) | code[0]);
|
||||||
ret += 2;
|
ret += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue