diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 0c087923..0b8489bf 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -static const char Version[] = "087.09"; +static const char Version[] = "087.10"; #include #include diff --git a/bsnes/gba/cartridge/cartridge.cpp b/bsnes/gba/cartridge/cartridge.cpp index a77ad522..959b37d0 100755 --- a/bsnes/gba/cartridge/cartridge.cpp +++ b/bsnes/gba/cartridge/cartridge.cpp @@ -6,8 +6,10 @@ Cartridge cartridge; bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { if(cartridge.rom.data) delete[] cartridge.rom.data; - cartridge.rom.data = new uint8[cartridge.rom.size = size]; - memcpy(cartridge.rom.data, data, size); + cartridge.rom.data = new uint8[cartridge.rom.size = 32 * 1024 * 1024]; + for(unsigned addr = 0; addr < 32 * 1024 * 1024; addr++) { + cartridge.rom.data[addr] = data[Bus::mirror(addr, size)]; + } if(cartridge.ram.data) delete[] cartridge.ram.data; cartridge.ram.data = new uint8[cartridge.ram.size = 64 * 1024](); diff --git a/bsnes/gba/cpu/cpu.cpp b/bsnes/gba/cpu/cpu.cpp index 38fe4432..e58fe827 100755 --- a/bsnes/gba/cpu/cpu.cpp +++ b/bsnes/gba/cpu/cpu.cpp @@ -12,6 +12,7 @@ void CPU::enter() { print(cpsr().t ? disassemble_thumb_instruction(pipeline.execute.address) : disassemble_arm_instruction(pipeline.execute.address), "\n"); print(disassemble_registers(), "\n"); + print("Executed: ", instructions, "\n"); while(true) step(frequency); } cpsr().t ? thumb_step() : arm_step(); diff --git a/bsnes/gba/memory/memory.cpp b/bsnes/gba/memory/memory.cpp index aa36a122..9aba9b2c 100755 --- a/bsnes/gba/memory/memory.cpp +++ b/bsnes/gba/memory/memory.cpp @@ -5,8 +5,8 @@ namespace GBA { Bus bus; struct UnmappedMemory : Memory { - uint32 read(uint32 addr, uint32 size) { print(hex<8>(addr), ":", decimal<2>(size), "\n"); return 0u; } - void write(uint32 addr, uint32 size, uint32 word) { print(hex<8>(addr), ":", decimal<2>(size), "=", hex<8>(word), "\n"); } + uint32 read(uint32 addr, uint32 size) { return 0u; } + void write(uint32 addr, uint32 size, uint32 word) {} }; static UnmappedMemory unmappedMemory; @@ -66,6 +66,24 @@ StaticMemory::~StaticMemory() { // +uint32 Bus::mirror(uint32 addr, uint32 size) { + uint32 base = 0; + if(size) { + uint32 mask = 1 << 27; //28-bit bus + while(addr >= size) { + while(!(addr & mask)) mask >>= 1; + addr -= mask; + if(size > mask) { + size -= mask; + base += mask; + } + mask >>= 1; + } + base += addr; + } + return base; +} + uint32 Bus::read(uint32 addr, uint32 size) { switch(addr & 0x0f000000) { case 0x00000000: return system.bios.read(addr & 0x3fff, size); diff --git a/bsnes/gba/memory/memory.hpp b/bsnes/gba/memory/memory.hpp index c39e700a..c9a761fe 100755 --- a/bsnes/gba/memory/memory.hpp +++ b/bsnes/gba/memory/memory.hpp @@ -15,6 +15,7 @@ struct StaticMemory : Memory { struct Bus : Memory { Memory *mmio[0x400]; + static uint32 mirror(uint32 addr, uint32 size); uint32 read(uint32 addr, uint32 size); void write(uint32 addr, uint32 size, uint32 word); diff --git a/bsnes/nall/bit.hpp b/bsnes/nall/bit.hpp index 0ceb2b8a..66ab7b33 100755 --- a/bsnes/nall/bit.hpp +++ b/bsnes/nall/bit.hpp @@ -27,6 +27,24 @@ namespace nall { } namespace bit { + constexpr inline uintmax_t mask(const char *s, uintmax_t sum = 0) { + return ( + *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : + *s == ' ' || *s == '_' ? mask(s + 1, sum) : + *s ? mask(s + 1, sum << 1) : + sum + ); + } + + constexpr inline uintmax_t test(const char *s, uintmax_t sum = 0) { + return ( + *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : + *s == ' ' || *s == '_' ? test(s + 1, sum) : + *s ? test(s + 1, sum << 1) : + sum + ); + } + //lowest(0b1110) == 0b0010 constexpr inline uintmax_t lowest(const uintmax_t x) { return x & -x; diff --git a/bsnes/nall/udl.hpp b/bsnes/nall/udl.hpp index 40bceba0..30ceefb3 100755 --- a/bsnes/nall/udl.hpp +++ b/bsnes/nall/udl.hpp @@ -4,6 +4,7 @@ //user-defined literals #include +#include namespace nall { constexpr inline uintmax_t operator"" _b(const char *n) { return binary(n); } diff --git a/bsnes/processor/arm/algorithms.cpp b/bsnes/processor/arm/algorithms.cpp new file mode 100755 index 00000000..b4c3c35d --- /dev/null +++ b/bsnes/processor/arm/algorithms.cpp @@ -0,0 +1,20 @@ +bool ARM::condition(uint4 condition) { + switch(condition) { + case 0: return cpsr().z == 1; //EQ (equal) + case 1: return cpsr().z == 0; //NE (not equal) + case 2: return cpsr().c == 1; //CS (carry set) + case 3: return cpsr().c == 0; //CC (carry clear) + case 4: return cpsr().n == 1; //MI (negative) + case 5: return cpsr().n == 0; //PL (positive) + case 6: return cpsr().v == 1; //VS (overflow) + case 7: return cpsr().v == 0; //VC (no overflow) + case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher) + case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same) + case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal) + case 11: return cpsr().n != cpsr().v; //LT (signed less than) + case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than) + case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal) + case 14: return true; //AL (always) + case 15: return false; //NV (never) + } +} diff --git a/bsnes/processor/arm/arm.cpp b/bsnes/processor/arm/arm.cpp index 17ba12a9..efadd0ee 100755 --- a/bsnes/processor/arm/arm.cpp +++ b/bsnes/processor/arm/arm.cpp @@ -4,6 +4,7 @@ namespace Processor { #include "registers.cpp" +#include "algorithms.cpp" #include "instructions-arm.cpp" #include "instructions-thumb.cpp" #include "disassembler.cpp" @@ -17,6 +18,9 @@ void ARM::power() { pipeline.reload = true; r(15).data &= cpsr().t ? ~1 : ~3; }; + + trace = false; + instructions = 0; } void ARM::vector(uint32 addr, Processor::Mode mode) { diff --git a/bsnes/processor/arm/arm.hpp b/bsnes/processor/arm/arm.hpp index a4baf75e..070006e0 100755 --- a/bsnes/processor/arm/arm.hpp +++ b/bsnes/processor/arm/arm.hpp @@ -17,8 +17,12 @@ struct ARM { void power(); void vector(uint32 addr, Processor::Mode mode); + bool condition(uint4 condition); void serialize(serializer&); + + bool trace; + uintmax_t instructions; }; } diff --git a/bsnes/processor/arm/disassembler.cpp b/bsnes/processor/arm/disassembler.cpp index 69f7514b..b7a706c7 100755 --- a/bsnes/processor/arm/disassembler.cpp +++ b/bsnes/processor/arm/disassembler.cpp @@ -54,19 +54,6 @@ string ARM::disassemble_arm_instruction(uint32 pc) { 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; - } - //memory_swap() //swp{condition}{b} rd,rm,[rn] if((instruction & 0x0fb000f0) == 0x01000090) { @@ -82,6 +69,120 @@ string ARM::disassemble_arm_instruction(uint32 pc) { 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<2>(immediate)); + if(pre == 1) output.append("]"); + if(pre == 0 || writeback == 1) output.append("!"); + + if(rn == 15) output.append(" =0x", hex<4>(bus_read(pc + 8 + (up ? +immediate : -immediate), Half))); + return output; + } + + //load_register() + //ldr{condition}s(h,b) rd,[rn,rm]{!} + //ldr{condition}s(h,b) rd,[rn],rm + if((instruction & 0x0e5000d0) == 0x001000b0) { + 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<2>(immediate)); + if(pre == 1) output.append("]"); + if(pre == 0 || writeback == 1) output.append("!"); + + if(rn == 15 && half == 1) output.append(" =0x", hex<4>(bus_read(pc + 8 + (up ? +immediate : -immediate), Half))); + if(rn == 15 && half == 0) output.append(" =0x", hex<2>(bus_read(pc + 8 + (up ? +immediate : -immediate), Byte))); + 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) { diff --git a/bsnes/processor/arm/instructions-arm.cpp b/bsnes/processor/arm/instructions-arm.cpp index 486a19f4..78387d13 100755 --- a/bsnes/processor/arm/instructions-arm.cpp +++ b/bsnes/processor/arm/instructions-arm.cpp @@ -21,53 +21,45 @@ void ARM::arm_step() { pipeline.fetch.instruction = bus_read(r(15), Word); step(2); -//print(disassemble_registers(), "\n"); -//print(disassemble_arm_instruction(pipeline.execute.address), "\n"); + instructions++; + if(trace) { + print(disassemble_registers(), "\n"); + print(disassemble_arm_instruction(pipeline.execute.address), "\n"); + } - if(arm_condition() == false) return; + if(condition(instruction() >> 28) == false) return; - if((instruction() & 0x0fc000f0) == 0x00000090) { arm_op_multiply(); return; } - if((instruction() & 0x0fb000f0) == 0x01000000) { arm_op_move_to_register_from_status(); return; } - if((instruction() & 0x0fb000f0) == 0x01000090) { arm_op_memory_swap(); return; } - if((instruction() & 0x0fb000f0) == 0x01200000) { arm_op_move_to_status_from_register(); return; } - if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; } //ARMv4+ - if((instruction() & 0x0fb00000) == 0x03200000) { arm_op_move_to_status_from_immediate(); return; } + #define decode(pattern, execute) if( \ + (instruction() & std::integral_constant::value) \ + == std::integral_constant::value \ + ) return arm_op_ ## execute() - if((instruction() & 0x0e000010) == 0x00000000) { arm_op_data_immediate_shift(); return; } - if((instruction() & 0x0e000090) == 0x00000010) { arm_op_data_register_shift(); return; } - if((instruction() & 0x0e000000) == 0x02000000) { arm_op_data_immediate(); return; } - if((instruction() & 0x0e000000) == 0x04000000) { arm_op_move_immediate_offset(); return; } - if((instruction() & 0x0e000010) == 0x06000000) { arm_op_move_register_offset(); return; } - if((instruction() & 0x0e000000) == 0x08000000) { arm_op_move_multiple(); return; } - if((instruction() & 0x0e000000) == 0x0a000000) { arm_op_branch(); return; } - if((instruction() & 0x0f000000) == 0x0f000000) { arm_op_software_interrupt(); return; } + decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply); + decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap); + decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register); + decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate); + decode("???? 000? ?0?1 ???? ???? ---- 11?1 ????", load_register); + decode("???? 000? ?1?1 ???? ???? ???? 11?1 ????", load_immediate); + + decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status); + decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register); + decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register); + + decode("???? 000? ???? ???? ???? ???? ???0 ????", data_immediate_shift); + decode("???? 000? ???? ???? ???? ???? 0??1 ????", data_register_shift); + decode("???? 001? ???? ???? ???? ???? ???? ????", data_immediate); + decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_immediate); + decode("???? 010? ???? ???? ???? ???? ???? ????", move_immediate_offset); + decode("???? 011? ???? ???? ???? ???? ???0 ????", move_register_offset); + decode("???? 100? ???? ???? ???? ???? ???? ????", move_multiple); + decode("???? 101? ???? ???? ???? ???? ???? ????", branch); + decode("???? 1111 ???? ???? ???? ???? ???? ????", software_interrupt); + + #undef decode exception = true; } -bool ARM::arm_condition() { - uint4 condition = instruction() >> 28; - - switch(condition) { - case 0: return cpsr().z == 1; //EQ (equal) - case 1: return cpsr().z == 0; //NE (not equal) - case 2: return cpsr().c == 1; //CS (carry set) - case 3: return cpsr().c == 0; //CC (carry clear) - case 4: return cpsr().n == 1; //MI (negative) - case 5: return cpsr().n == 0; //PL (positive) - case 6: return cpsr().v == 1; //VS (overflow) - case 7: return cpsr().v == 0; //VC (no overflow) - case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher) - case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same) - case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal) - case 11: return cpsr().n != cpsr().v; //LT (signed less than) - case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than) - case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal) - case 14: return true; //AL (always) - case 15: return false; //NV (never) - } -} - void ARM::arm_opcode(uint32 rm) { uint4 opcode = instruction() >> 21; uint1 save = instruction() >> 20; @@ -235,23 +227,6 @@ void ARM::arm_op_multiply() { } } -//mrs{condition} rd,(c,s)psr -//cccc 0001 0r00 ++++ dddd ---- 0000 ---- -//c = condition -//r = SPSR (0 = CPSR) -//d = rd -void ARM::arm_op_move_to_register_from_status() { - uint1 source = instruction() >> 22; - uint4 d = instruction() >> 12; - - if(source) { - if(mode() == Processor::Mode::USR) return; - if(mode() == Processor::Mode::SYS) return; - } - - r(d) = source ? spsr() : cpsr(); -} - //swp{condition}{b} rd,rm,[rn] //cccc 0001 0b00 nnnn dddd ---- 1001 mmmm //c = condition @@ -270,6 +245,151 @@ void ARM::arm_op_memory_swap() { r(d) = word; } +//(ldr,str){condition}h rd,[rn,rm]{!} +//(ldr,str){condition}h rd,[rn],rm +//cccc 000p u0wl nnnn dddd ---- 1011 mmmm +//c = condition +//p = pre (0 = post) +//u = up +//w = writeback +//l = load (0 = save) +//n = rn +//d = rd +//m = rm +void ARM::arm_op_move_half_register() { + uint1 pre = instruction() >> 24; + uint1 up = instruction() >> 23; + uint1 writeback = instruction() >> 21; + uint1 load = instruction() >> 20; + uint4 n = instruction() >> 16; + uint4 d = instruction() >> 12; + uint4 m = instruction(); + + uint32 rn = r(n); + uint32 rm = r(m); + + if(pre == 1) rn = up ? rn + rm : rn - rm; + if(load == 1) r(d) = bus_read(rn, Word); + if(load == 0) bus_write(rn, Word, r(d)); + if(pre == 0) rn = up ? rn + rm : rn - rm; + + if(pre == 0 || writeback == 1) r(n) = rn; +} + +//(ldr,str){condition}h rd,[rn{,+/-offset}]{!} +//(ldr,str){condition}h rd,[rn]{,+/-offset} +//cccc 000p u1wl nnnn dddd iiii 1011 iiii +//c = condition +//p = pre (0 = post) +//u = up +//w = writeback +//l = load (0 = save) +//n = rn +//d = rd +//i = immediate hi +//i = immediate lo +void ARM::arm_op_move_half_immediate() { + uint1 pre = instruction() >> 24; + uint1 up = instruction() >> 23; + uint1 writeback = instruction() >> 21; + uint1 load = instruction() >> 20; + uint4 n = instruction() >> 16; + uint4 d = instruction() >> 12; + uint4 ih = instruction() >> 8; + uint4 il = instruction(); + + uint32 rn = r(n); + uint8 immediate = (ih << 4) + (il << 0); + + if(pre == 1) rn = up ? rn + immediate : rn - immediate; + if(load == 1) r(d) = bus_read(rn, Word); + if(load == 0) bus_write(rn, Word, r(d)); + if(pre == 0) rn = up ? rn + immediate : rn - immediate; + + if(pre == 0 || writeback == 1) r(n) = rn; +} + +//ldr{condition}s(h,b) rd,[rn,rm]{!} +//ldr{condition}s(h,b) rd,[rn],rm +//cccc 000p u0w1 nnnn dddd ---- 11h1 mmmm +//c = condition +//p = pre (0 = post) +//u = up +//w = writeback +//n = rn +//d = rd +//h = half (0 = byte) +//m = rm +void ARM::arm_op_load_register() { + uint1 pre = instruction() >> 24; + uint1 up = instruction() >> 23; + uint1 writeback = instruction() >> 21; + uint4 n = instruction() >> 16; + uint4 d = instruction() >> 12; + uint1 half = instruction() >> 5; + uint4 m = instruction(); + + uint32 rn = r(n); + uint32 rm = r(m); + + if(pre == 1) rn = up ? rn + rm : rn - rm; + uint32 word = bus_read(rn, half ? Half : Byte); + r(d) = half ? (int16)word : (int8)word; + if(pre == 0) rm = up ? rn + rm : rn - rm; + + if(pre == 0 || writeback == 1) r(n) = rn; +} + +//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!} +//ldr{condition}s(h,b) rd,[rn]{,+/-offset} +//cccc 000p u1w1 nnnn dddd iiii 11h1 iiii +//c = condition +//p = pre (0 = post) +//u = up +//w = writeback +//n = rn +//d = rd +//i = immediate hi +//h = half (0 = byte) +//i = immediate lo +void ARM::arm_op_load_immediate() { + uint1 pre = instruction() >> 24; + uint1 up = instruction() >> 23; + uint1 writeback = instruction() >> 21; + uint4 n = instruction() >> 16; + uint4 d = instruction() >> 12; + uint4 ih = instruction() >> 8; + uint1 half = instruction() >> 5; + uint4 il = instruction(); + + uint32 rn = r(n); + uint8 immediate = (ih << 4) + (il << 0); + + if(pre == 1) rn = up ? rn + immediate : rn - immediate; + uint32 word = bus_read(rn, half ? Half : Byte); + r(d) = half ? (int16)word : (int8)word; + if(pre == 0) rn = up ? rn + immediate : rn - immediate; + + if(pre == 0 || writeback == 1) r(n) = rn; +} + +//mrs{condition} rd,(c,s)psr +//cccc 0001 0r00 ++++ dddd ---- 0000 ---- +//c = condition +//r = SPSR (0 = CPSR) +//d = rd +void ARM::arm_op_move_to_register_from_status() { + uint1 source = instruction() >> 22; + uint4 d = instruction() >> 12; + + if(source) { + if(mode() == Processor::Mode::USR) return; + if(mode() == Processor::Mode::SYS) return; + } + + r(d) = source ? spsr() : cpsr(); +} + //msr{condition} (c,s)psr:{fields},rm //cccc 0001 0r10 ffff ++++ ---- 0000 mmmm //c = condition @@ -432,7 +552,7 @@ void ARM::arm_op_move_immediate_offset() { if(pre == 0 || writeback == 1) r(n) = rn; } -//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{1} +//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!} //(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate //cccc 011p ubwl nnnn dddd llll lss0 mmmm //c = condition diff --git a/bsnes/processor/arm/instructions-arm.hpp b/bsnes/processor/arm/instructions-arm.hpp index 035e8863..ea0dc83c 100755 --- a/bsnes/processor/arm/instructions-arm.hpp +++ b/bsnes/processor/arm/instructions-arm.hpp @@ -11,10 +11,16 @@ void ror(bool &c, uint32 &rm, uint32 rs); void rrx(bool &c, uint32 &rm); void arm_op_multiply(); -void arm_op_move_to_register_from_status(); void arm_op_memory_swap(); +void arm_op_move_half_register(); +void arm_op_move_half_immediate(); +void arm_op_load_register(); +void arm_op_load_immediate(); + +void arm_op_move_to_register_from_status(); void arm_op_move_to_status_from_register(); void arm_op_branch_exchange_register(); + void arm_op_move_to_status_from_immediate(); void arm_op_data_immediate_shift(); void arm_op_data_register_shift(); diff --git a/bsnes/processor/arm/instructions-thumb.cpp b/bsnes/processor/arm/instructions-thumb.cpp index 00b8d727..58e67993 100755 --- a/bsnes/processor/arm/instructions-thumb.cpp +++ b/bsnes/processor/arm/instructions-thumb.cpp @@ -21,54 +21,45 @@ void ARM::thumb_step() { pipeline.fetch.instruction = bus_read(r(15), Half); step(1); -//print(disassemble_registers(), "\n"); -//print(disassemble_thumb_instruction(pipeline.execute.address), "\n"); + instructions++; + if(trace) { + print(disassemble_registers(), "\n"); + print(disassemble_thumb_instruction(pipeline.execute.address), "\n"); + } - if((instruction() & 0xfc00) == 0x1800) { thumb_op_adjust_register(); return; } - if((instruction() & 0xfc00) == 0x1c00) { thumb_op_adjust_immediate(); return; } - if((instruction() & 0xe000) == 0x0000) { thumb_op_shift_immediate(); return; } - if((instruction() & 0xe000) == 0x2000) { thumb_op_immediate(); return; } - if((instruction() & 0xfc00) == 0x4000) { thumb_op_alu(); return; } - if((instruction() & 0xff80) == 0x4700) { thumb_op_branch_exchange(); return; } - if((instruction() & 0xfc00) == 0x4400) { thumb_op_alu_hi(); return; } - if((instruction() & 0xf800) == 0x4800) { thumb_op_load_literal(); return; } - if((instruction() & 0xf000) == 0x5000) { thumb_op_move_register_offset(); return; } - if((instruction() & 0xf000) == 0x6000) { thumb_op_move_word_immediate(); return; } - if((instruction() & 0xf000) == 0x7000) { thumb_op_move_byte_immediate(); return; } - if((instruction() & 0xf000) == 0x8000) { thumb_op_move_half_immediate(); return; } - if((instruction() & 0xf000) == 0x9000) { thumb_op_move_stack(); return; } - if((instruction() & 0xf000) == 0xa000) { thumb_op_add_register_hi(); return; } - if((instruction() & 0xff00) == 0xb000) { thumb_op_adjust_stack(); return; } - if((instruction() & 0xf600) == 0xb400) { thumb_op_stack_multiple(); return; } - if((instruction() & 0xf000) == 0xc000) { thumb_op_move_multiple(); return; } - if((instruction() & 0xff00) == 0xdf00) { thumb_op_software_interrupt(); return; } - if((instruction() & 0xf000) == 0xd000) { thumb_op_branch_conditional(); return; } - if((instruction() & 0xf800) == 0xe000) { thumb_op_branch_short(); return; } - if((instruction() & 0xf800) == 0xf000) { thumb_op_branch_long_prefix(); return; } - if((instruction() & 0xf800) == 0xf800) { thumb_op_branch_long_suffix(); return; } + #define decode(pattern, execute) if( \ + (instruction() & std::integral_constant::value) \ + == std::integral_constant::value \ + ) return thumb_op_ ## execute() + + decode("0001 10?? ???? ????", adjust_register); + decode("0001 11?? ???? ????", adjust_immediate); + decode("000? ???? ???? ????", shift_immediate); + decode("001? ???? ???? ????", immediate); + decode("0100 00?? ???? ????", alu); + decode("0100 0111 0??? ?---", branch_exchange); + decode("0100 01?? ???? ????", alu_hi); + decode("0100 1??? ???? ????", load_literal); + decode("0101 ???? ???? ????", move_register_offset); + decode("0110 ???? ???? ????", move_word_immediate); + decode("0111 ???? ???? ????", move_byte_immediate); + decode("1000 ???? ???? ????", move_half_immediate); + decode("1001 ???? ???? ????", move_stack); + decode("1010 ???? ???? ????", add_register_hi); + decode("1011 0000 ???? ????", adjust_stack); + decode("1011 ?10? ???? ????", stack_multiple); + decode("1100 ???? ???? ????", move_multiple); + decode("1101 1111 ???? ????", software_interrupt); + decode("1101 ???? ???? ????", branch_conditional); + decode("1110 0??? ???? ????", branch_short); + decode("1111 0??? ???? ????", branch_long_prefix); + decode("1111 1??? ???? ????", branch_long_suffix); + + #undef decode exception = true; } -bool ARM::thumb_condition(uint4 condition) { - switch(condition) { - case 0: return cpsr().z == 1; //EQ (equal) - case 1: return cpsr().z == 0; //NE (not equal) - case 2: return cpsr().c == 1; //CS (carry set) - case 3: return cpsr().c == 0; //CC (carry clear) - case 4: return cpsr().n == 1; //MI (negative) - case 5: return cpsr().n == 0; //PL (positive) - case 6: return cpsr().v == 1; //VS (overflow) - case 7: return cpsr().v == 0; //VC (no overflow) - case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher) - case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same) - case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal) - case 11: return cpsr().n != cpsr().v; //LT (signed less than) - case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than) - case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal) - } -} - void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) { switch(opcode) { case 0: r(d) = thumb_tst(r(d) & r(m)); break; //AND @@ -381,8 +372,8 @@ void ARM::thumb_op_add_register_hi() { uint3 d = instruction() >> 8; uint8 immediate = instruction(); - if(sp == 0) r(d) = (r(15) & ~2) + immediate; - if(sp == 1) r(d) = r(13) + immediate; + if(sp == 0) r(d) = (r(15) & ~2) + immediate * 4; + if(sp == 1) r(d) = r(13) + immediate * 4; } //(add,sub) sp,#immediate @@ -464,10 +455,10 @@ void ARM::thumb_op_software_interrupt() { //c = condition //d = displacement void ARM::thumb_op_branch_conditional() { - uint4 condition = instruction() >> 8; + uint4 flagcondition = instruction() >> 8; int8 displacement = instruction(); - if(thumb_condition(condition) == false) return; + if(condition(flagcondition) == false) return; r(15) = r(15) + displacement * 2; } diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp index e955bb87..9744734e 100755 --- a/bsnes/snes/chip/armdsp/armdsp.cpp +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -28,7 +28,9 @@ void ArmDSP::enter() { } if(exception) { - print("* ARM unknown instruction\n"); + print(disassemble_arm_instruction(pipeline.execute.address), "\n"); + print(disassemble_registers(), "\n"); + print("Executed: ", instructions, "\n"); while(true) step(frequency); }