mirror of https://github.com/bsnes-emu/bsnes.git
778 lines
24 KiB
C++
778 lines
24 KiB
C++
auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
|
static string conditions[] = {
|
|
"eq", "ne", "cs", "cc",
|
|
"mi", "pl", "vs", "vc",
|
|
"hi", "ls", "ge", "lt",
|
|
"gt", "le", "", "nv",
|
|
};
|
|
|
|
static string opcodes[] = {
|
|
"and", "eor", "sub", "rsb",
|
|
"add", "adc", "sbc", "rsc",
|
|
"tst", "teq", "cmp", "cmn",
|
|
"orr", "mov", "bic", "mvn",
|
|
};
|
|
|
|
static string registers[] = {
|
|
"r0", "r1", "r2", "r3",
|
|
"r4", "r5", "r6", "r7",
|
|
"r8", "r9", "r10", "r11",
|
|
"r12", "sp", "lr", "pc",
|
|
};
|
|
|
|
static string indices[] = {
|
|
"da", "ia", "db", "ib",
|
|
};
|
|
|
|
static auto is_move = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
|
|
static auto is_comp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
|
|
static auto is_math = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
|
|
|
|
string output{hex(pc, 8L), " "};
|
|
|
|
uint32 instruction = read(Word | Nonsequential, pc & ~3);
|
|
output.append(hex(instruction, 8L), " ");
|
|
|
|
//multiply()
|
|
//mul{condition}{s} rd,rm,rs
|
|
//mla{condition}{s} rd,rm,rs,rn
|
|
if((instruction & 0x0fc000f0) == 0x00000090) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 accumulate = instruction >> 21;
|
|
uint1 save = instruction >> 20;
|
|
uint4 rd = instruction >> 16;
|
|
uint4 rn = instruction >> 12;
|
|
uint4 rs = instruction >> 8;
|
|
uint4 rm = instruction;
|
|
|
|
output.append(accumulate ? "mla" : "mul", conditions[condition], save ? "s " : " ");
|
|
output.append(registers[rd], ",", registers[rm], ",", registers[rs]);
|
|
if(accumulate) output.append(",", registers[rn]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//multiply_long()
|
|
//(u,s)mull{condition}{s} rdlo,rdhi,rm,rs
|
|
//(u,s)mlal{condition}{s} rdlo,rdhi,rm,rs
|
|
if((instruction & 0x0f8000f0) == 0x00800090) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 signextend = instruction >> 22;
|
|
uint1 accumulate = instruction >> 21;
|
|
uint1 save = instruction >> 20;
|
|
uint4 rdhi = instruction >> 16;
|
|
uint4 rdlo = instruction >> 12;
|
|
uint4 rs = instruction >> 8;
|
|
uint4 rm = instruction;
|
|
|
|
output.append(signextend ? "s" : "u", accumulate ? "mlal" : "mull", conditions[condition], save ? "s " : " ");
|
|
output.append(registers[rdlo], ",", registers[rdhi], ",", registers[rm], ",", registers[rs]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//memory_swap()
|
|
//swp{condition}{b} rd,rm,[rn]
|
|
if((instruction & 0x0fb000f0) == 0x01000090) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 byte = instruction >> 22;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint4 rm = instruction;
|
|
|
|
output.append("swp", conditions[condition], byte ? "b " : " ");
|
|
output.append(registers[rd], ",", registers[rm], "[", registers[rn], "]");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_half_register()
|
|
//(ldr,str){condition}h rd,[rn,rm]{!}
|
|
//(ldr,str){condition}h rd,[rn],rm
|
|
if((instruction & 0x0e4000f0) == 0x000000b0) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 pre = instruction >> 24;
|
|
uint1 up = instruction >> 23;
|
|
uint1 writeback = instruction >> 21;
|
|
uint1 load = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint4 rm = instruction;
|
|
|
|
output.append(load ? "ldr" : "str", conditions[condition], "h ");
|
|
output.append(registers[rd], ",[", registers[rn]);
|
|
if(pre == 0) output.append("]");
|
|
output.append(",", up ? "+" : "-", registers[rm]);
|
|
if(pre == 1) output.append("]");
|
|
if(pre == 0 || writeback == 1) output.append("!");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_half_immediate()
|
|
//(ldr,str){condition}h rd,[rd{,+/-offset}]{!}
|
|
//(ldr,str){condition}h rd,[rn]{,+/-offset}
|
|
if((instruction & 0x0e4000f0) == 0x004000b0) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 pre = instruction >> 24;
|
|
uint1 up = instruction >> 23;
|
|
uint1 writeback = instruction >> 21;
|
|
uint1 load = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint4 ih = instruction >> 8;
|
|
uint4 il = instruction >> 0;
|
|
|
|
uint8 immediate = (ih << 4) + (il << 0);
|
|
|
|
output.append(load ? "ldr" : "str", conditions[condition], "h ");
|
|
output.append(registers[rd], ",[", registers[rn]);
|
|
if(pre == 0) output.append("]");
|
|
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 2L));
|
|
if(pre == 1) output.append("]");
|
|
if(pre == 0 || writeback == 1) output.append("!");
|
|
|
|
if(rn == 15) output.append(" =0x", hex(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 4L));
|
|
return output;
|
|
}
|
|
|
|
//load_register()
|
|
//ldr{condition}s(h,b) rd,[rn,rm]{!}
|
|
//ldr{condition}s(h,b) rd,[rn],rm
|
|
if((instruction & 0x0e5000d0) == 0x001000d0) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 pre = instruction >> 24;
|
|
uint1 up = instruction >> 23;
|
|
uint1 writeback = instruction >> 21;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint1 half = instruction >> 5;
|
|
uint4 rm = instruction;
|
|
|
|
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
|
|
output.append(registers[rd], ",[", registers[rn]);
|
|
if(pre == 0) output.append("]");
|
|
output.append(",", up ? "+" : "-", registers[rm]);
|
|
if(pre == 1) output.append("]");
|
|
if(pre == 0 || writeback == 1) output.append("!");
|
|
|
|
return output;
|
|
}
|
|
|
|
//load_immediate()
|
|
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
|
|
//ldr{condition}s(h,b) rd,[rn]{,+/-offset}
|
|
if((instruction & 0x0e5000b0) == 0x005000b0) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 pre = instruction >> 24;
|
|
uint1 up = instruction >> 23;
|
|
uint1 writeback = instruction >> 21;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint4 ih = instruction >> 8;
|
|
uint1 half = instruction >> 5;
|
|
uint4 il = instruction;
|
|
|
|
uint8 immediate = (ih << 4) + (il << 0);
|
|
|
|
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
|
|
output.append(registers[rd], ",[", registers[rn]);
|
|
if(pre == 0) output.append("]");
|
|
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 2L));
|
|
if(pre == 1) output.append("]");
|
|
if(pre == 0 || writeback == 1) output.append("!");
|
|
|
|
if(rn == 15 && half == 1) output.append(" =0x", hex(read(Half | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 4L));
|
|
if(rn == 15 && half == 0) output.append(" =0x", hex(read(Byte | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 2L));
|
|
return output;
|
|
}
|
|
|
|
//move_to_register_from_status()
|
|
//mrs{condition} rd,(c,s)psr
|
|
if((instruction & 0x0fb000f0) == 0x01000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 psr = instruction >> 22;
|
|
uint4 rd = instruction >> 12;
|
|
|
|
output.append("mrs", conditions[condition], " ");
|
|
output.append(registers[rd], ",", psr ? "spsr" : "cpsr");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_to_status_from_register()
|
|
//msr{condition} (c,s)psr:{fields},rm
|
|
if((instruction & 0x0fb000f0) == 0x01200000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 psr = instruction >> 22;
|
|
uint4 field = instruction >> 16;
|
|
uint4 rm = instruction;
|
|
|
|
output.append("msr", conditions[condition], " ");
|
|
output.append(psr ? "spsr:" : "cpsr:");
|
|
output.append(
|
|
field & 1 ? "c" : "",
|
|
field & 2 ? "x" : "",
|
|
field & 4 ? "s" : "",
|
|
field & 8 ? "f" : ""
|
|
);
|
|
output.append(",", registers[rm]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch_exchange_register()
|
|
//bx{condition} rm
|
|
if((instruction & 0x0ff000f0) == 0x01200010) {
|
|
uint4 condition = instruction >> 28;
|
|
uint4 rm = instruction;
|
|
|
|
output.append("bx", conditions[condition], " ");
|
|
output.append(registers[rm]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_to_status_from_immediate()
|
|
//msr{condition} (c,s)psr:{fields},#immediate
|
|
if((instruction & 0x0fb00000) == 0x03200000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 psr = instruction >> 22;
|
|
uint4 field = instruction >> 16;
|
|
uint4 rotate = instruction >> 8;
|
|
uint8 immediate = instruction;
|
|
|
|
uint32 rm = (immediate >> (rotate * 2)) | (immediate << (32 - (rotate * 2)));
|
|
|
|
output.append("msr", conditions[condition], " ");
|
|
output.append(psr ? "spsr:" : "cpsr:");
|
|
output.append(
|
|
field & 1 ? "c" : "",
|
|
field & 2 ? "x" : "",
|
|
field & 4 ? "s" : "",
|
|
field & 8 ? "f" : ""
|
|
);
|
|
output.append(",#0x", hex(immediate, 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//data_immediate_shift()
|
|
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
|
//{opcode}{condition} rn,rm {shift} #immediate
|
|
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
|
|
if((instruction & 0x0e000010) == 0x00000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint4 opcode = instruction >> 21;
|
|
uint1 save = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint5 shift = instruction >> 7;
|
|
uint2 op = instruction >> 5;
|
|
uint4 rm = instruction;
|
|
|
|
output.append(opcodes[opcode], conditions[condition]);
|
|
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
|
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
|
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
|
output.append(",", registers[rm]);
|
|
if(op == 0 && shift != 0) output.append(" lsl #", shift);
|
|
if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
|
|
if(op == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
|
|
if(op == 3 && shift != 0) output.append(" ror #", shift);
|
|
if(op == 3 && shift == 0) output.append(" rrx");
|
|
|
|
return output;
|
|
}
|
|
|
|
//data_register_shift()
|
|
//{opcode}{condition}{s} rd,rm {shift} rs
|
|
//{opcode}{condition} rn,rm {shift} rs
|
|
//{opcode}{condition}{s} rd,rn,rm {shift} rs
|
|
if((instruction & 0x0e000090) == 0x00000010) {
|
|
uint4 condition = instruction >> 28;
|
|
uint4 opcode = instruction >> 21;
|
|
uint1 save = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint4 rs = instruction >> 8;
|
|
uint2 mode = instruction >> 5;
|
|
uint4 rm = instruction;
|
|
|
|
output.append(opcodes[opcode], conditions[condition]);
|
|
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
|
|
if(is_comp(opcode)) output.append(registers[rn], ",");
|
|
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
|
|
output.append(registers[rm]);
|
|
if(mode == 0) output.append(" lsl ");
|
|
if(mode == 1) output.append(" lsr ");
|
|
if(mode == 2) output.append(" asr ");
|
|
if(mode == 3) output.append(" ror ");
|
|
output.append(registers[rs]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//data_immediate()
|
|
//{opcode}{condition}{s} rd,#immediate
|
|
//{opcode}{condition} rn,#immediate
|
|
//{opcode}{condition}{s} rd,rn,#immediate
|
|
if((instruction & 0x0e000000) == 0x02000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint4 opcode = instruction >> 21;
|
|
uint1 save = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint4 rotate = instruction >> 8;
|
|
uint8 immediate = instruction;
|
|
|
|
uint32 rm = (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)));
|
|
output.append(opcodes[opcode], conditions[condition]);
|
|
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
|
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
|
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
|
output.append(",#0x", hex(rm, 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_immediate_offset()
|
|
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
|
|
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
|
|
if((instruction & 0x0e000000) == 0x04000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 pre = instruction >> 24;
|
|
uint1 up = instruction >> 23;
|
|
uint1 byte = instruction >> 22;
|
|
uint1 writeback = instruction >> 21;
|
|
uint1 load = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint12 immediate = instruction;
|
|
|
|
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
|
|
output.append(registers[rd], ",[", registers[rn]);
|
|
if(pre == 0) output.append("]");
|
|
if(immediate) output.append(",", up ? "+" : "-", "0x", hex(immediate, 3L));
|
|
if(pre == 1) output.append("]");
|
|
if(pre == 0 || writeback == 1) output.append("!");
|
|
|
|
if(rn == 15) output.append(" =0x", hex(read((byte ? Byte : Word) | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 8L));
|
|
return output;
|
|
}
|
|
|
|
//move_register_offset()
|
|
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{1}
|
|
//(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate
|
|
if((instruction & 0x0e000010) == 0x06000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 pre = instruction >> 24;
|
|
uint1 up = instruction >> 23;
|
|
uint1 byte = instruction >> 22;
|
|
uint1 writeback = instruction >> 21;
|
|
uint1 load = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint4 rd = instruction >> 12;
|
|
uint5 shift = instruction >> 7;
|
|
uint2 mode = instruction >> 5;
|
|
uint4 rm = instruction;
|
|
|
|
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
|
|
output.append(registers[rd], ",[", registers[rn]);
|
|
if(pre == 0) output.append("]");
|
|
output.append(",", up ? "+" : "-", registers[rm]);
|
|
if(mode == 0 && shift != 0) output.append(" lsl #", shift);
|
|
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
|
|
if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
|
|
if(mode == 3 && shift != 0) output.append(" ror #", shift);
|
|
if(mode == 3 && shift == 0) output.append(" rrx");
|
|
if(pre == 1) output.append("]");
|
|
if(pre == 0 || writeback == 1) output.append("!");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_multiple()
|
|
//(ldm,stm) {condition}{mode} rn{!},{r...}{^}
|
|
if((instruction & 0x0e000000) == 0x08000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint2 index = instruction >> 23;
|
|
uint1 s = instruction >> 22;
|
|
uint1 writeback = instruction >> 21;
|
|
uint1 load = instruction >> 20;
|
|
uint4 rn = instruction >> 16;
|
|
uint16 list = instruction;
|
|
|
|
output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " ");
|
|
output.append(registers[rn], writeback ? "!" : "", ",{");
|
|
for(unsigned n = 0; n < 16; n++) if(list & (1 << n)) output.append(registers[n], ",");
|
|
output.rtrim(",");
|
|
output.append("}", s ? "^" : "");
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch()
|
|
//b{l}{condition} address
|
|
if((instruction & 0x0e000000) == 0x0a000000) {
|
|
uint4 condition = instruction >> 28;
|
|
uint1 link = instruction >> 24;
|
|
|
|
output.append("b", link ? "l" : "", conditions[condition], " ");
|
|
output.append("0x", hex(pc + 8 + (int24)instruction * 4, 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//software_interrupt()
|
|
//swi #immediate
|
|
if((instruction & 0x0f000000) == 0x0f000000) {
|
|
uint24 immediate = instruction;
|
|
|
|
output.append("swi #0x", hex(immediate, 6L));
|
|
|
|
return output;
|
|
}
|
|
|
|
output.append("???");
|
|
return output;
|
|
}
|
|
|
|
auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
|
static string conditions[] = {
|
|
"eq", "ne", "cs", "cc",
|
|
"mi", "pl", "vs", "vc",
|
|
"hi", "ls", "ge", "lt",
|
|
"gt", "le", "", "",
|
|
};
|
|
|
|
static string registers[] = {
|
|
"r0", "r1", "r2", "r3",
|
|
"r4", "r5", "r6", "r7",
|
|
"r8", "r9", "r10", "r11",
|
|
"r12", "sp", "lr", "pc",
|
|
};
|
|
|
|
string output{hex(pc, 8L), " "};
|
|
|
|
uint16 instruction = read(Half | Nonsequential, pc & ~1);
|
|
output.append(hex(instruction, 4L), " ");
|
|
|
|
//adjust_register()
|
|
//(add,sub) rd,rn,rm
|
|
if((instruction & 0xfc00) == 0x1800) {
|
|
uint1 opcode = instruction >> 9;
|
|
uint3 rm = instruction >> 6;
|
|
uint3 rn = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(opcode == 0 ? "add" : "sub", " ", registers[rd], ",", registers[rn], ",", registers[rm]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//adjust_immediate()
|
|
//(add,sub) rd,rn,#immediate
|
|
if((instruction & 0xfc00) == 0x1c00) {
|
|
uint1 opcode = instruction >> 9;
|
|
uint3 immediate = instruction >> 6;
|
|
uint3 rn = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(opcode == 0 ? "add" : "sub", " ", registers[rd], ",", registers[rn], ",#", hex(immediate, 1L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//shift_immediate()
|
|
//(lsl,lsr,asar) rd,rm,#immmediate
|
|
if((instruction & 0xe000) == 0x0000) {
|
|
static string opcodes[] = { "lsl", "lsr", "asr", "" };
|
|
|
|
uint2 opcode = instruction >> 11;
|
|
uint5 immediate = instruction >> 6;
|
|
uint3 rm = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(opcodes[opcode], " ", registers[rd], ",", registers[rm], ",#", immediate);
|
|
|
|
return output;
|
|
}
|
|
|
|
//immediate()
|
|
//(mov,cmp,add,sub) (rd,rn),#immediate
|
|
if((instruction & 0xe000) == 0x2000) {
|
|
static string opcodes[] = { "mov", "cmp", "add", "sub" };
|
|
|
|
uint2 opcode = instruction >> 11;
|
|
uint3 rd = instruction >> 8;
|
|
uint8 immediate = instruction;
|
|
|
|
output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex(immediate, 2L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//alu()
|
|
//{opcode} rd,rm
|
|
if((instruction & 0xfc00) == 0x4000) {
|
|
static string opcodes[] = {
|
|
"and", "eor", "lsl", "lsr",
|
|
"asr", "adc", "sbc", "ror",
|
|
"tst", "neg", "cmp", "cmn",
|
|
"orr", "mul", "bic", "mvn",
|
|
};
|
|
|
|
uint4 opcode = instruction >> 6;
|
|
uint3 rm = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(opcodes[opcode], " ", registers[rd], ",", registers[rm]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch_exchange()
|
|
//bx rm
|
|
if((instruction & 0xff80) == 0x4700) {
|
|
uint4 rm = instruction >> 3;
|
|
|
|
output.append("bx ", registers[rm]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//alu_hi()
|
|
//{opcode} rd,rm
|
|
if((instruction & 0xfc00) == 0x4400) {
|
|
static string opcodes[] = { "add", "sub", "mov", "" };
|
|
|
|
uint2 opcode = instruction >> 8;
|
|
uint4 rm = instruction >> 3;
|
|
uint4 rd = ((uint1)(instruction >> 7) << 3) + (uint3)instruction;
|
|
|
|
if(opcode == 2 && rm == 8 && rd == 8) {
|
|
output.append("nop");
|
|
return output;
|
|
}
|
|
|
|
output.append(opcodes[opcode], " ", registers[rd], ",", registers[rm]);
|
|
|
|
return output;
|
|
}
|
|
|
|
//load_literal()
|
|
//ldr rd,[pc,#+/-offset]
|
|
if((instruction & 0xf800) == 0x4800) {
|
|
uint3 rd = instruction >> 8;
|
|
uint8 displacement = instruction;
|
|
|
|
unsigned rm = ((pc + 4) & ~3) + displacement * 4;
|
|
output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 3L), "]");
|
|
output.append(" =0x", hex(read(Word | Nonsequential, rm), 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_register_offset()
|
|
//(ld(r,s),str){b,h} rd,[rn,rm]
|
|
if((instruction & 0xf000) == 0x5000) {
|
|
static string opcodes[] = {
|
|
"str", "strh", "strb", "ldsb",
|
|
"ldr", "ldrh", "ldrb", "ldsh",
|
|
};
|
|
|
|
uint3 opcode = instruction >> 9;
|
|
uint3 rm = instruction >> 6;
|
|
uint3 rn = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(opcodes[opcode], " ", registers[rd], ",[", registers[rn], ",", registers[rm], "]");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_word_immediate()
|
|
//(ldr,str) rd,[rn,#offset]
|
|
if((instruction & 0xf000) == 0x6000) {
|
|
uint1 load = instruction >> 11;
|
|
uint5 offset = instruction >> 6;
|
|
uint3 rn = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(load ? "ldr " : "str ", registers[rd], ",[", registers[rn], ",#0x", hex(offset * 4, 2L), "]");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_byte_immediate()
|
|
//(ldr,str)b rd,[rn,#offset]
|
|
if((instruction & 0xf000) == 0x7000) {
|
|
uint1 load = instruction >> 11;
|
|
uint5 offset = instruction >> 6;
|
|
uint3 rn = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(load ? "ldrb " : "strb ", registers[rd], ",[", registers[rn], ",#0x", hex(offset, 2L), "]");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_half_immediate()
|
|
//(ldr,str)h rd,[rn,#offset]
|
|
if((instruction & 0xf000) == 0x8000) {
|
|
uint1 load = instruction >> 11;
|
|
uint5 offset = instruction >> 6;
|
|
uint3 rn = instruction >> 3;
|
|
uint3 rd = instruction >> 0;
|
|
|
|
output.append(load ? "ldrh " : "strh ", registers[rd], ",[", registers[rn], ",#0x", hex(offset * 2, 2L), "]");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_stack()
|
|
//(ldr,str) rd,[sp,#relative]
|
|
if((instruction & 0xf000) == 0x9000) {
|
|
uint1 opcode = instruction >> 11;
|
|
uint3 rd = instruction >> 8;
|
|
int8 relative = instruction;
|
|
|
|
output.append(opcode ? "ldr" : "str", " ", registers[rd], ",[sp,#0x", hex(relative * 4, 3L), "]");
|
|
|
|
return output;
|
|
}
|
|
|
|
//add_register_hi()
|
|
//add rd,{pc,sp},#immediate
|
|
if((instruction & 0xf000) == 0xa000) {
|
|
uint1 sp = instruction >> 11;
|
|
uint3 rd = instruction >> 8;
|
|
uint8 immediate = instruction;
|
|
|
|
output.append("add ", registers[rd], ",", sp ? "sp" : "pc", ",#0x", hex(immediate, 2L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//adjust_stack()
|
|
//(add,sub) sp,#immediate
|
|
if((instruction & 0xff00) == 0xb000) {
|
|
uint1 opcode = instruction >> 7;
|
|
uint7 immediate = instruction;
|
|
|
|
output.append(opcode == 0 ? "add" : "sub", " sp,#0x", hex(immediate * 4, 3L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//stack_multiple()
|
|
//push {r...{,lr}}
|
|
//pop {r...{,pc}}
|
|
if((instruction & 0xf600) == 0xb400) {
|
|
uint1 load = instruction >> 11;
|
|
uint1 branch = instruction >> 8;
|
|
uint8 list = instruction;
|
|
|
|
output.append(load == 0 ? "push" : "pop", " {");
|
|
for(unsigned l = 0; l < 8; l++) {
|
|
if(list & (1 << l)) output.append(registers[l], ",");
|
|
}
|
|
if(branch) output.append(load == 0 ? "lr," : "pc,");
|
|
output.rtrim(",");
|
|
output.append("}");
|
|
|
|
return output;
|
|
}
|
|
|
|
//move_multiple()
|
|
//(ldmia,stmia) rn,{r...}
|
|
if((instruction & 0xf000) == 0xc000) {
|
|
uint1 load = instruction >> 11;
|
|
uint3 rn = instruction >> 8;
|
|
uint8 list = instruction;
|
|
|
|
output.append(load ? "ldmia " : "stmia ", registers[rn], "!,{");
|
|
for(unsigned l = 0; l < 8; l++) {
|
|
if(list & (1 << l)) output.append(registers[l], ",");
|
|
}
|
|
output.rtrim(",");
|
|
output.append("}");
|
|
|
|
return output;
|
|
}
|
|
|
|
//software_interrupt()
|
|
//swi #immediate
|
|
if((instruction & 0xff00) == 0xdf00) {
|
|
uint8 immediate = instruction;
|
|
|
|
output.append("swi #0x", hex(immediate, 2L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch_conditional()
|
|
//b{condition} address
|
|
if((instruction & 0xf000) == 0xd000) {
|
|
uint4 condition = instruction >> 8;
|
|
int8 displacement = instruction;
|
|
|
|
uint32 offset = pc + 4 + displacement * 2;
|
|
output.append("b", conditions[condition], " 0x", hex(offset, 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch_short()
|
|
//b address
|
|
if((instruction & 0xf800) == 0xe000) {
|
|
int11 displacement = instruction;
|
|
|
|
output.append("b 0x", hex(pc + 4 + displacement * 2, 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch_long_prefix()
|
|
//bl address
|
|
if((instruction & 0xf800) == 0xf000) {
|
|
uint11 offsethi = instruction;
|
|
instruction = read(Half | Nonsequential, (pc & ~1) + 2);
|
|
uint11 offsetlo = instruction;
|
|
|
|
int22 displacement = (offsethi << 11) | (offsetlo << 0);
|
|
output.append("bl 0x", hex(pc + 4 + displacement * 2, 8L));
|
|
|
|
return output;
|
|
}
|
|
|
|
//branch_long_suffix()
|
|
//bl address
|
|
if((instruction & 0xf800) == 0xf800) {
|
|
output.append("...");
|
|
|
|
return output;
|
|
}
|
|
|
|
output.append("???");
|
|
return output;
|
|
}
|
|
|
|
auto ARM::disassemble_registers() -> string {
|
|
string output;
|
|
output.append( "r0:", hex(r( 0), 8L), " r1:", hex(r( 1), 8L), " r2:", hex(r( 2), 8L), " r3:", hex(r( 3), 8L), " ");
|
|
output.append( "r4:", hex(r( 4), 8L), " r5:", hex(r( 5), 8L), " r6:", hex(r( 6), 8L), " r7:", hex(r( 7), 8L), " ");
|
|
output.append("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v");
|
|
output.append("/", cpsr().i ? "I" : "i", cpsr().f ? "F" : "f", cpsr().t ? "T" : "t");
|
|
output.append("/", hex(cpsr().m, 2L), "\n");
|
|
output.append( "r8:", hex(r( 8), 8L), " r9:", hex(r( 9), 8L), " r10:", hex(r(10), 8L), " r11:", hex(r(11), 8L), " ");
|
|
output.append("r12:", hex(r(12), 8L), " sp:", hex(r(13), 8L), " lr:", hex(r(14), 8L), " pc:", hex(r(15), 8L), " ");
|
|
output.append("spsr:");
|
|
if(mode() == Processor::Mode::USR || mode() == Processor::Mode::SYS) { output.append("----/---/--"); return output; }
|
|
output.append( spsr().n ? "N" : "n", spsr().z ? "Z" : "z", spsr().c ? "C" : "c", spsr().v ? "V" : "v");
|
|
output.append("/", spsr().i ? "I" : "i", spsr().f ? "F" : "f", spsr().t ? "T" : "t");
|
|
output.append("/", hex(spsr().m, 2L));
|
|
return output;
|
|
}
|