diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 7bc21c87..385863b4 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -const char Version[] = "086.09"; +const char Version[] = "086.10"; #include #include diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp index d74b722c..4dfd1ca9 100755 --- a/bsnes/snes/chip/armdsp/armdsp.cpp +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -3,6 +3,8 @@ #define ARMDSP_CPP namespace SNES { +static bool trace = 0; + #include "opcodes.cpp" #include "memory.cpp" #include "disassembler.cpp" @@ -42,12 +44,17 @@ void ArmDSP::enter() { pipeline.prefetch.opcode = bus_read<4>(r[15]); r[15].step(); - //print("\n", disassemble_registers(), "\n"); - //print(disassemble_opcode(pipeline.instruction.address), "\n"); + //if(pipeline.instruction.address == 0x00000208) trace = 1; + if(trace) { + print("\n", disassemble_registers(), "\n"); + print(disassemble_opcode(pipeline.instruction.address), "\n"); + usleep(200000); + } instruction = pipeline.instruction.opcode; if((instruction & 0x0fb000f0) == 0x01200000) { op_move_status_register_to_register(); continue; } if((instruction & 0x0e000010) == 0x00000000) { op_data_immediate_shift(); continue; } + if((instruction & 0x0e000090) == 0x00000010) { op_data_register_shift(); continue; } if((instruction & 0x0e000000) == 0x02000000) { op_data_immediate(); continue; } if((instruction & 0x0e000000) == 0x04000000) { op_move_immediate_offset(); continue; } if((instruction & 0x0e000000) == 0x08000000) { op_move_multiple(); continue; } @@ -58,21 +65,27 @@ void ArmDSP::enter() { } uint8 ArmDSP::mmio_read(unsigned addr) { - addr &= 0xffff; - if(addr == 0x3800) return armport[0]; - if(addr == 0x3802) return armport[1]; - if(addr == 0x3804) return armport[3]; + uint8 data = 0x00; + switch(addr & 0xffff) { + case 0x3800: data = w40000000; break; + case 0x3802: data = r3802; break; + case 0x3804: data = r3804; break; + } - print("* r", hex<4>(addr), "\n"); - return 0x00; + print("* r", hex<6>(addr), " = ", hex<2>(data), "\n"); + usleep(200000); + return data; } void ArmDSP::mmio_write(unsigned addr, uint8 data) { - addr &= 0xffff; - if(addr == 0x3802) cpuport[1] = data; - if(addr == 0x3804) cpuport[0] = data; + print("* w", hex<6>(addr), " = ", hex<2>(data), "\n"); + usleep(200000); - print("* w", hex<4>(addr), "w = ", hex<2>(data), "\n"); + switch(addr & 0xffff) { + case 0x3800: w3800 = data; break; + case 0x3802: w3802 = data; trace = 0; cputoarm = true; break; + case 0x3804: w3804 = data; break; + } } void ArmDSP::init() { @@ -96,6 +109,13 @@ void ArmDSP::reset() { pipeline.reload = true; r[15].write = [&] { pipeline.reload = true; }; + +r3800=r3802=r3804=0; +w3800=w3802=w3804=0; +r40000000=r40000010=r40000020=r40000024=r40000028=r4000002c=0; +w40000000=w40000010=w40000020=w40000024=w40000028=w4000002c=0; +cputoarm=0; +armtocpu=0; } } diff --git a/bsnes/snes/chip/armdsp/armdsp.hpp b/bsnes/snes/chip/armdsp/armdsp.hpp index b46fcc48..f084de33 100755 --- a/bsnes/snes/chip/armdsp/armdsp.hpp +++ b/bsnes/snes/chip/armdsp/armdsp.hpp @@ -6,8 +6,17 @@ struct ArmDSP : public Coprocessor { #include "registers.hpp" - uint8 cpuport[4]; - uint8 armport[4]; + //CPU + uint8 r3800, r3802, r3804; + uint8 w3800, w3802, w3804; + + //ARM + uint32 r40000000, r40000010, r40000020, r40000024, r40000028, r4000002c; + uint32 w40000000, w40000010, w40000020, w40000024, w40000028, w4000002c; + + //Status + bool cputoarm; + bool armtocpu; static void Enter(); void enter(); @@ -24,11 +33,11 @@ struct ArmDSP : public Coprocessor { //opcodes.cpp bool condition(); void opcode(uint32 data); - void flags(uint32 rd); void op_branch(); void op_data_immediate(); void op_data_immediate_shift(); + void op_data_register_shift(); void op_move_immediate_offset(); void op_move_status_register_to_register(); void op_move_multiple(); diff --git a/bsnes/snes/chip/armdsp/disassembler.cpp b/bsnes/snes/chip/armdsp/disassembler.cpp index fe0612e8..eb089a39 100755 --- a/bsnes/snes/chip/armdsp/disassembler.cpp +++ b/bsnes/snes/chip/armdsp/disassembler.cpp @@ -6,6 +6,10 @@ string ArmDSP::disassemble_opcode(uint32 pc) { 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<8>(pc), " "}; uint32 instruction = bus_read<4>(pc); @@ -31,45 +35,65 @@ string ArmDSP::disassemble_opcode(uint32 pc) { } //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 & 0x0e000000) == 0x00000000) { uint4 condition = instruction >> 28; uint4 opcode = instruction >> 21; uint1 save = instruction >> 20; - uint4 rd = instruction >> 16; - uint4 rn = instruction >> 12; - uint8 rm = instruction; + uint4 rn = instruction >> 16; + uint4 rd = instruction >> 12; uint5 shift = instruction >> 7; - uint2 op = instruction >> 2; + uint2 op = instruction >> 5; + uint4 rm = instruction; - output.append(opcodes[opcode], conditions[condition], save ? "s " : " "); - output.append(registers[rd], ","); - output.append(registers[rn], ","); - output.append(registers[rm], " "); - if(op == 0) output.append("lsl #", shift); - if(op == 1) output.append("lsr #", 1 + shift); - if(op == 2) output.append("asr #", 1 + shift); - if(op == 3 && shift != 0) output.append("ror #", shift); - if(op == 3 && shift == 0) output.append("rrx"); + 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 immediate + //{opcode}{condition}{s} rd,#immediate + //{opcode}{condition} rn,#immediate + //{opcode}{condition}{s} rd,rn,#immediate if((instruction & 0x0e000000) == 0x02000000) { - uint5 rotate = 2 * (uint4)(instruction >> 8); - uint32 immediate = (uint8)instruction; - immediate = (immediate >> rotate) | (immediate << (32 - rotate)); - output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex<8>(immediate)); + 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 shifter = (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<8>(shifter)); + return output; } //move immediate offset + //(ldr,str){condition}{b} rd,[rn{+offset}] //todo: support W flag if((instruction & 0x0e000000) == 0x04000000) { uint1 u = instruction >> 23; uint1 load = instruction >> 20; uint12 immediate = instruction; output.append(load ? "ldr" : "str", conditions[condition]); + if(instruction & 0x00400000) output.append("b"); output.append(" ", registers[rd], ",[", registers[rn]); if(immediate) output.append(u ? "+" : "-", "0x", hex<3>((uint12)instruction)); output.append("]"); @@ -77,6 +101,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) { } //move multiple + //(ldm,stm){condition}{mode} rn{!},{r...} if((instruction & 0x0e000000) == 0x08000000) { output.append(instruction & 0x00100000 ? "ldm" : "stm", conditions[condition], indices[(uint2)(instruction >> 23)]); output.append(" ", registers[rn], instruction & 0x00200000 ? "!" : "", ",{"); @@ -87,6 +112,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) { } //branch + //b{l}{condition} address if((instruction & 0x0e000000) == 0x0a000000) { uint1 l = instruction >> 24; output.append("b", l ? "l" : "", conditions[condition]); diff --git a/bsnes/snes/chip/armdsp/memory.cpp b/bsnes/snes/chip/armdsp/memory.cpp index acedc2af..59641188 100755 --- a/bsnes/snes/chip/armdsp/memory.cpp +++ b/bsnes/snes/chip/armdsp/memory.cpp @@ -5,52 +5,70 @@ uint8 ArmDSP::bus_iread(uint32 addr) { return programROM[addr & 0x0001ffff]; } - if(addr >= 0x40000020 && addr <= 0x4000002f) { - if(addr == 0x40000020) return cpuport[0]; - if(addr == 0x40000024) return cpuport[1]; - if(addr == 0x40000028) return cpuport[2]; - if(addr == 0x4000002c) return cpuport[3]; + if(addr >= 0x40000000 && addr <= 0x400000ff) { + if(addr == 0x40000000) { return r40000000; } + if(addr == 0x40000010) { return w3802; } + if(addr == 0x40000020) { return (cputoarm << 3); } + if(addr == 0x40000024) { return r40000024; } + if(addr == 0x40000028) { return r40000028; } + if(addr == 0x4000002c) { return r4000002c; } } if(addr >= 0xe0000000 && addr <= 0xe0003fff) { return programRAM[addr & 0x00003fff]; } -//print("* ARM r", hex<8>(addr), "\n"); return 0x00; } void ArmDSP::bus_iwrite(uint32 addr, uint8 data) { - if(addr >= 0x40000020 && addr <= 0x4000002f) { - if(addr == 0x40000020) armport[0] = data; - if(addr == 0x40000024) armport[1] = data; - if(addr == 0x40000028) armport[2] = data; - if(addr == 0x4000002c) armport[3] = data; -if(data) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n"); + if(addr >= 0x40000000 && addr <= 0x400000ff) { + if(addr == 0x40000000) { w40000000 = data; } + if(addr == 0x40000020) { w40000020 = data; } + if(addr == 0x40000024) { w40000024 = data; } + if(addr == 0x40000028) { w40000028 = data; } + if(addr == 0x4000002c) { w4000002c = data; if(data & 2) r3804 = 0x80; } } if(addr >= 0xe0000000 && addr <= 0xe0003fff) { programRAM[addr & 0x00003fff] = data; return; } - -//print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n"); } template uint32 ArmDSP::bus_read(uint32 addr) { - uint32 result = 0; - result |= bus_iread(addr + 0) << 0; - result |= bus_iread(addr + 1) << 8; - result |= bus_iread(addr + 2) << 16; - result |= bus_iread(addr + 3) << 24; - if(size == 1) return result & 0xff; - if(size == 2) return result & 0xffff; - return result; + uint32 data = 0; + data |= bus_iread(addr + 0) << 0; + data |= bus_iread(addr + 1) << 8; + data |= bus_iread(addr + 2) << 16; + data |= bus_iread(addr + 3) << 24; + + if(addr >= 0x40000000 && addr <= 0x400000ff) { + if(data) { + if(size == 1) print("* ARM r", hex<8>(addr), " = ", hex<2>(data), "\n"); + if(size == 2) print("* ARM r", hex<8>(addr), " = ", hex<4>(data), "\n"); + if(size == 4) print("* ARM r", hex<8>(addr), " = ", hex<8>(data), "\n"); + usleep(20000); + } + } + + if(size == 1) return data & 0xff; + if(size == 2) return data & 0xffff; + return data; } template void ArmDSP::bus_write(uint32 addr, uint32 data) { + if(addr >= 0x40000000 && addr <= 0x400000ff) { + if(0||data) { + if(size == 1) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n"); + if(size == 2) print("* ARM w", hex<8>(addr), " = ", hex<4>(data), "\n"); + if(size == 4) print("* ARM w", hex<8>(addr), " = ", hex<8>(data), "\n"); + usleep(20000); + } + } + if(size == 1) data = (bus_read<1>(addr) & 0xffffff00) | (data & 0x000000ff); if(size == 2) data = (bus_read<2>(addr) & 0xffff0000) | (data & 0x0000ffff); bus_iwrite(addr + 0, data >> 0); diff --git a/bsnes/snes/chip/armdsp/opcodes.cpp b/bsnes/snes/chip/armdsp/opcodes.cpp index dc318919..a6bc8462 100755 --- a/bsnes/snes/chip/armdsp/opcodes.cpp +++ b/bsnes/snes/chip/armdsp/opcodes.cpp @@ -1,7 +1,7 @@ #ifdef ARMDSP_CPP bool ArmDSP::condition() { - switch((uint4)(instruction >> 28)) { default: + switch((uint4)(instruction >> 28)) { 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) @@ -53,15 +53,15 @@ void ArmDSP::opcode(uint32 rm) { switch(opcode) { case 0: rd = rn & rm; nz(rd); break; //AND (logical and) case 1: rd = rn ^ rm; nz(rd); break; //EOR (logical exclusive or) - case 2: rd = rn +~rm; nzcv(rd); break; //SUB (subtract) - case 3: rd = rm +~rn; nzcv(rd); break; //RSB (reverse subtract) + case 2: rd = rn +~rm + 1; nzcv(rd); break; //SUB (subtract) + case 3: rd = rm +~rn + 1; nzcv(rd); break; //RSB (reverse subtract) case 4: rd = rn + rm; nzcv(rd); break; //ADD (add) case 5: rd = rn + rm + cpsr.c; nzcv(rd); break; //ADC (add with carry) case 6: rd = rn +~rm + cpsr.c; nzcv(rd); break; //SBC (subtract with carry) case 7: rd = rm +~rn + cpsr.c; nzcv(rd); break; //RSC (reverse subtract with carry) case 8: ro = rn & rm; nz(ro); break; //TST (test) case 9: ro = rn ^ rm; nz(ro); break; //TEQ (test equivalence) - case 10: ro = rn +~rm; nzcv(ro); break; //CMP (compare) + case 10: ro = rn +~rm + 1; nzcv(ro); break; //CMP (compare) case 11: ro = rn + rm; nzcv(ro); break; //CMN (compare negated) case 12: rd = rn | rm; nz(rd); break; //ORR (logical inclusive or) case 13: rd = rm; nz(rd); break; //MOV (move) @@ -70,11 +70,6 @@ void ArmDSP::opcode(uint32 rm) { } } -void ArmDSP::flags(uint32 rd) { - cpsr.n = rd & 0x80000000; - cpsr.z = rd == 0; -} - //CCCC 101L DDDD DDDD DDDD DDDD DDDD DDDD //C = condition //L = link @@ -89,6 +84,9 @@ void ArmDSP::op_branch() { r[15] += displacement * 4; } +//{opcode}{condition}{s} rd,#immediate +//{opcode}{condition} rn,#immediate +//{opcode}{condition}{s} rd,rn,#immediate //CCCC 001O OOOS NNNN DDDD RRRR IIII IIII //C = condition //O = opcode @@ -100,16 +98,18 @@ void ArmDSP::op_branch() { void ArmDSP::op_data_immediate() { if(!condition()) return; - uint4 rotate = instruction >> 8; - uint8 immediate = instruction >> 0; + uint4 shift = instruction >> 8; + uint8 immediate = instruction; - opcode( - (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1))) - ); + uint32 rs = shift << 1; + uint32 rm = (immediate >> rs) | (immediate << (32 - rs)); - //todo: set carry for non-add/sub opcodes here + opcode(rm); } +//{opcode}{condition}{s} rd,rm {shift} #immediate +//{opcode}{condition} rn,rm {shift} #immediate +//{opcode}{condition}{s} rd,rn,rm {shift} #immediate //CCCC 000O OOOS NNNN DDDD LLLL LSS0 MMMM //C = condition //O = opcode @@ -123,34 +123,66 @@ void ArmDSP::op_data_immediate_shift() { if(!condition()) return; uint5 shift = instruction >> 7; - uint2 op = instruction >> 5; - uint32 rm = r[(uint4)instruction]; + uint2 mode = instruction >> 5; + uint4 m = instruction; - if(op == 0) { //LSL (logical shift left) - rm = rm << shift; - } + uint32 rs = shift; + uint32 rm = r[m]; - if(op == 1) { //LSR (logical shift right) - rm = rm >> (1 + shift); - } + switch(mode) { + case 0: //LSL + rm = rm << rs; + break; - if(op == 2) { //ASR (arithmetic shift right) - rm = (int32)rm >> (1 + shift); - } + case 1: //LSR + if(rs == 0) rs = 32; + rm = rm >> rs; + break; - if(op == 3) { //ROR (rotate right) - if(shift == 0) { //RRX (rorate right with extend) - rm = (cpsr.c << 31) | (rm >> 1); - } else { - rm = (rm >> shift) + (rm << (32 - shift)); - } + case 2: //ASR + if(rs == 0) rs = 32; + rm = (int32)rm >> rs; + break; + + case 3: //ROR + RRX + if(rs == 0) rm = (cpsr.c << 31) | (rm >> 1); //RRX + if(rs != 0) rm = (rm >> rs) + (rm << (32 - rs)); //ROR + break; } opcode(rm); - - //todo: set carry } +//cccc 000o ooos nnnn dddd ssss 0ss1 mmmm +//c = condition +//o = opcode +//s = save flags +//n = rn +//d = rd +//s = rs +//s = shift +//m = rm +void ArmDSP::op_data_register_shift() { + if(!condition()) return; + + uint4 s = instruction >> 8; + uint2 mode = instruction >> 5; + uint4 m = instruction >> 0; + + uint32 rs = r[s]; + uint32 rm = r[m]; + + switch(mode) { + case 0: rm = rm << rs; break; //LSL + case 1: rm = rm >> rs; break; //LSR + case 2: rm = (int32)rm >> rs; break; //ASR + case 3: rm = (rm >> rs) + (rm << (32 - rs)); break; //ROR + } + + opcode(rm); +} + +//(ldr,str){condition}{b} rd,[rn{+offset}] //CCCC 010P UBWL NNNN DDDD IIII IIII IIII //C = condition //P = pre (0 = post-indexed addressing) @@ -256,6 +288,8 @@ void ArmDSP::op_move_multiple() { if(u == 1) r[n] = r[n] + bit::count(list) * 4; //IA, IB if(u == 0) r[n] = r[n] - bit::count(list) * 4; //DA, DB } + +//if(l)exception=true; } #endif