bsnes/higan/processor/arm/disassembler.cpp

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;
}