diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 385863b4..5278a08f 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.10"; +const char Version[] = "086.11"; #include #include diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp index 4dfd1ca9..64d49980 100755 --- a/bsnes/snes/chip/armdsp/armdsp.cpp +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -52,11 +52,13 @@ void ArmDSP::enter() { } instruction = pipeline.instruction.opcode; - if((instruction & 0x0fb000f0) == 0x01200000) { op_move_status_register_to_register(); continue; } + if((instruction & 0x0fb000f0) == 0x01000000) { op_move_to_register_from_status_register(); continue; } + if((instruction & 0x0fb000f0) == 0x01200000) { op_move_to_status_register_from_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 & 0x0e000010) == 0x06000000) { op_move_register_offset(); continue; } if((instruction & 0x0e000000) == 0x08000000) { op_move_multiple(); continue; } if((instruction & 0x0e000000) == 0x0a000000) { op_branch(); continue; } @@ -65,27 +67,50 @@ void ArmDSP::enter() { } uint8 ArmDSP::mmio_read(unsigned addr) { + cpu.synchronize_coprocessors(); + uint8 data = 0x00; - switch(addr & 0xffff) { - case 0x3800: data = w40000000; break; - case 0x3802: data = r3802; break; - case 0x3804: data = r3804; break; + addr &= 0xffff; + + if(addr == 0x3800) { + if(bridge.armtocpu.ready) { + bridge.armtocpu.ready = false; + data = bridge.armtocpu.data; + print("* r3800 = ", hex<2>(data), "\n"); + } + } + + if(addr == 0x3802); + + if(addr == 0x3804) { + data = bridge.status(); + } + + if(0) { + print("* r", hex<6>(addr), " = ", hex<2>(data), "\n"); + usleep(200000); } - print("* r", hex<6>(addr), " = ", hex<2>(data), "\n"); - usleep(200000); return data; } void ArmDSP::mmio_write(unsigned addr, uint8 data) { - print("* w", hex<6>(addr), " = ", hex<2>(data), "\n"); - usleep(200000); + cpu.synchronize_coprocessors(); - switch(addr & 0xffff) { - case 0x3800: w3800 = data; break; - case 0x3802: w3802 = data; trace = 0; cputoarm = true; break; - case 0x3804: w3804 = data; break; + if(0) { + print("* w", hex<6>(addr), " = ", hex<2>(data), "\n"); + usleep(200000); } + + addr &= 0xffff; + + if(addr == 0x3802) { + bridge.cputoarm.ready = true; + bridge.cputoarm.data = data; + print("* w3802 = ", hex<2>(data), "\n"); + } + + if(addr == 0x3804); } void ArmDSP::init() { @@ -98,6 +123,12 @@ void ArmDSP::unload() { } void ArmDSP::power() { + string filename = interface->path(Cartridge::Slot::Base, "st0018d.rom"); + file fp; + if(fp.open(filename, file::mode::read)) { + fp.read(aoRAM, 32 * 1024); + fp.close(); + } } void ArmDSP::reset() { @@ -109,13 +140,6 @@ 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 f084de33..548ebd55 100755 --- a/bsnes/snes/chip/armdsp/armdsp.hpp +++ b/bsnes/snes/chip/armdsp/armdsp.hpp @@ -3,21 +3,10 @@ struct ArmDSP : public Coprocessor { uint8 programROM[128 * 1024]; uint8 programRAM[16 * 1024]; + uint8 aoRAM[32 * 1024]; #include "registers.hpp" - //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(); @@ -34,13 +23,15 @@ struct ArmDSP : public Coprocessor { bool condition(); void opcode(uint32 data); - void op_branch(); - void op_data_immediate(); + void op_move_to_status_register_from_register(); + void op_move_to_register_from_status_register(); void op_data_immediate_shift(); void op_data_register_shift(); + void op_data_immediate(); void op_move_immediate_offset(); - void op_move_status_register_to_register(); + void op_move_register_offset(); void op_move_multiple(); + void op_branch(); //memory.cpp uint8 bus_iread(uint32 addr); diff --git a/bsnes/snes/chip/armdsp/disassembler.cpp b/bsnes/snes/chip/armdsp/disassembler.cpp index eb089a39..bec656b1 100755 --- a/bsnes/snes/chip/armdsp/disassembler.cpp +++ b/bsnes/snes/chip/armdsp/disassembler.cpp @@ -15,13 +15,15 @@ string ArmDSP::disassemble_opcode(uint32 pc) { uint32 instruction = bus_read<4>(pc); output.append(hex<8>(instruction), " "); - uint4 condition = instruction >> 28; - uint4 opcode = instruction >> 21; - uint4 rn = instruction >> 16; - uint4 rd = instruction >> 12; - uint4 rs = instruction >> 8; + //move to register from status register + if((instruction & 0x0fb000f0) == 0x01000000) { + uint1 psr = instruction >> 22; + uint4 rd = instruction >> 12; + output.append("mrs ", registers[rd], ",", psr ? "spsr" : "cpsr"); + return output; + } - //move status register to register + //move to status register from register if((instruction & 0x0fb000f0) == 0x01200000) { uint1 psr = instruction >> 22; uint4 field = instruction >> 16; @@ -89,34 +91,46 @@ string ArmDSP::disassemble_opcode(uint32 pc) { //(ldr,str){condition}{b} rd,[rn{+offset}] //todo: support W flag if((instruction & 0x0e000000) == 0x04000000) { + uint4 condition = instruction >> 28; uint1 u = instruction >> 23; uint1 load = instruction >> 20; + uint4 rn = instruction >> 16; + uint4 rd = instruction >> 12; 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("]"); + return output; } //move multiple //(ldm,stm){condition}{mode} rn{!},{r...} if((instruction & 0x0e000000) == 0x08000000) { + uint4 condition = instruction >> 28; + uint4 rn = instruction >> 16; + output.append(instruction & 0x00100000 ? "ldm" : "stm", conditions[condition], indices[(uint2)(instruction >> 23)]); output.append(" ", registers[rn], instruction & 0x00200000 ? "!" : "", ",{"); for(unsigned n = 0; n < 16; n++) if(instruction & (1 << n)) output.append(registers[n], ","); output.rtrim<1>(","); output.append("}"); + return output; } //branch //b{l}{condition} address if((instruction & 0x0e000000) == 0x0a000000) { + uint4 condition = instruction >> 28; uint1 l = instruction >> 24; + output.append("b", l ? "l" : "", conditions[condition]); output.append(" 0x", hex<8>(pc + 8 + (int24)instruction * 4)); + return output; } diff --git a/bsnes/snes/chip/armdsp/memory.cpp b/bsnes/snes/chip/armdsp/memory.cpp index 59641188..dcd5f16e 100755 --- a/bsnes/snes/chip/armdsp/memory.cpp +++ b/bsnes/snes/chip/armdsp/memory.cpp @@ -6,34 +6,59 @@ uint8 ArmDSP::bus_iread(uint32 addr) { } 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 == 0x40000000) return 0x00; + + if(addr == 0x40000010) { + if(bridge.cputoarm.ready) { + bridge.cputoarm.ready = false; + return bridge.cputoarm.data; + } + } + + if(addr == 0x40000020) { + return bridge.status(); + } + + if(addr == 0x40000024) return 0x00; + if(addr == 0x40000028) return 0x00; + if(addr == 0x4000002c) return 0x00; + } + + if(addr >= 0xa0000000 && addr <= 0xa0007fff) { + return aoRAM[addr & 0x00007fff]; } if(addr >= 0xe0000000 && addr <= 0xe0003fff) { return programRAM[addr & 0x00003fff]; } + if((addr & 3) == 0) print("* ARM r", hex<8>(addr), "\n"); return 0x00; } void ArmDSP::bus_iwrite(uint32 addr, uint8 data) { 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 == 0x40000000) { + bridge.armtocpu.ready = true; + bridge.armtocpu.data = data; + return; + } + + if(addr == 0x40000020) return; + if(addr == 0x40000024) return; + if(addr == 0x40000028) return; + if(addr == 0x4000002c) return print("* w4000002c = ", hex<2>(data), "\n"); + } + + if(addr >= 0xa0000000 && addr <= 0xa0007fff) { } if(addr >= 0xe0000000 && addr <= 0xe0003fff) { programRAM[addr & 0x00003fff] = data; return; } + + if((addr & 3) == 0) print("* ARM w", hex<8>(addr), " = ", hex<2>(data), "\n"); } template @@ -44,7 +69,8 @@ uint32 ArmDSP::bus_read(uint32 addr) { data |= bus_iread(addr + 2) << 16; data |= bus_iread(addr + 3) << 24; - if(addr >= 0x40000000 && addr <= 0x400000ff) { + if(0&&addr >= 0x40000000 && addr <= 0x400000ff) { + if(addr != 0x40000020 || data != 0x80) 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"); @@ -60,8 +86,8 @@ uint32 ArmDSP::bus_read(uint32 addr) { template void ArmDSP::bus_write(uint32 addr, uint32 data) { - if(addr >= 0x40000000 && addr <= 0x400000ff) { - if(0||data) { + if(0&&addr >= 0x40000000 && addr <= 0x400000ff) { + if(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"); diff --git a/bsnes/snes/chip/armdsp/opcodes.cpp b/bsnes/snes/chip/armdsp/opcodes.cpp index a6bc8462..99abdf4c 100755 --- a/bsnes/snes/chip/armdsp/opcodes.cpp +++ b/bsnes/snes/chip/armdsp/opcodes.cpp @@ -34,7 +34,7 @@ void ArmDSP::opcode(uint32 rm) { uint32 ri = rd, ro; //comparison opcodes always update flags - if(opcode >= 8 && opcode <= 11) s = 1; + if(opcode >= 8 && opcode <= 11) assert(s == 1); static auto nz = [&](uint32 ro) { if(!s) return; @@ -70,65 +70,237 @@ void ArmDSP::opcode(uint32 rm) { } } -//CCCC 101L DDDD DDDD DDDD DDDD DDDD DDDD -//C = condition -//L = link -//D = displacement (24-bit signed) -void ArmDSP::op_branch() { +//mrs{condition} rd,(c,s)psr +//cccc 0001 0r00 ++++ dddd ---- 0000 ---- +//c = condition +//r = SPSR (0 = CPSR) +//d = rd +void ArmDSP::op_move_to_register_from_status_register() { if(!condition()) return; - uint1 l = instruction >> 24; - int24 displacement = instruction; + uint1 source = instruction >> 22; + uint4 d = instruction >> 12; - if(l) r[14] = r[15] - 4; - r[15] += displacement * 4; + r[d] = source ? spsr : cpsr; } -//{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 -//S = update flags -//N = Rn -//D = Rd -//R = rotate -//I = immediate -void ArmDSP::op_data_immediate() { +//msr{condition} (c,s)psr:{fields},rm +//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm +//c = condition +//r = SPSR (0 = CPSR) +//f = field mask +//m = rm +void ArmDSP::op_move_to_status_register_from_register() { if(!condition()) return; - uint4 shift = instruction >> 8; - uint8 immediate = instruction; + uint1 source = instruction >> 22; + uint4 field = instruction >> 16; + uint4 m = instruction; - uint32 rs = shift << 1; - uint32 rm = (immediate >> rs) | (immediate << (32 - rs)); - - opcode(rm); + PSR &psr = source ? spsr : cpsr; + if(field & 1) psr.setc(r[m]); + if(field & 2) psr.setx(r[m]); + if(field & 4) psr.sets(r[m]); + if(field & 8) psr.setf(r[m]); } //{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 -//S = update flags -//N = Rn -//D = Rd -//L = shift amount -//S = shift -//M = Rm +//cccc 000o ooos nnnn dddd llll lss0 mmmm +//c = condition +//o = opcode +//s = save flags +//n = rn +//d = rd +//l = shift immmediate +//s = shift +//m = rm void ArmDSP::op_data_immediate_shift() { if(!condition()) return; + uint1 save = instruction >> 20; uint5 shift = instruction >> 7; uint2 mode = instruction >> 5; uint4 m = instruction; + bool carry = cpsr.c; uint32 rs = shift; uint32 rm = r[m]; + switch(mode) { + case 0: //LSL + rm = rm << rs; + if(rs) carry = rm & (1 << (32 - rs)); + break; + + case 1: //LSR + if(rs == 0) rs = 32; + rm = rm >> rs; + carry = rm & (1 << (rs - 1)); + break; + + 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; + } + + if(save) cpsr.c = carry; + opcode(rm); +} + +//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; + + uint1 save = instruction >> 20; + uint4 s = instruction >> 8; + uint2 mode = instruction >> 5; + uint4 m = instruction >> 0; + + bool carry = cpsr.c; + uint32 rs = (uint8)r[s]; + uint32 rm = r[m]; + + switch(mode) { + case 0: //LSL + rm = rm << rs; + if(rs) carry = rm & (1 << (32 - rs)); + break; + + case 1: //LSR + if(rs == 0) break; + rm = rm >> rs; + carry = rm & (1 << (rs - 1)); + break; + + case 2: //ASR + rm = (int32)rm >> rs; + break; + + case 3: //ROR + rm = (rm >> rs) + (rm << (32 - rs)); + break; + } + + if(save) cpsr.c = carry; + opcode(rm); +} + +//{opcode}{condition}{s} rd,#immediate +//{opcode}{condition} rn,#immediate +//{opcode}{condition}{s} rd,rn,#immediate +//cccc 001o ooos nnnn dddd llll iiii iiii +//c = condition +//o = opcode +//s = save flags +//n = rn +//d = rd +//l = shift immediate +//i = immediate +void ArmDSP::op_data_immediate() { + if(!condition()) return; + + uint1 save = instruction >> 20; + uint4 shift = instruction >> 8; + uint8 immediate = instruction; + + bool carry = cpsr.c; + uint32 rs = shift << 1; + uint32 rm = (immediate >> rs) | (immediate << (32 - rs)); + if(rs) carry = immediate & 0x80000000; + + if(save) cpsr.c = carry; + 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) +//u = up (add/sub offset to base) +//b = byte (1 = 32-bit) +//w = writeback +//l = load (0 = save) +//n = rn +//d = rd +//i = immediate +void ArmDSP::op_move_immediate_offset() { + if(!condition()) return; + + uint1 p = instruction >> 24; + uint1 u = instruction >> 23; + uint1 b = instruction >> 22; + uint1 w = instruction >> 21; + uint1 l = instruction >> 20; + uint4 n = instruction >> 16; + uint4 d = instruction >> 12; + uint12 rm = instruction; + + uint32 rn = r[n]; + auto &rd = r[d]; + + if(l) { + if(p == 1) rn = u ? rn + rm : rn - rm; + if(b) rd = bus_read<1>(rn); + else rd = bus_read<4>(rn); + if(p == 0) rn = u ? rn + rm : rn - rm; + } else { + if(p == 1) rn = u ? rn + rm : rn - rm; + if(b) bus_write<1>(rn, rd); + else bus_write<4>(rn, rd); + if(p == 0) rn = u ? rn + rm : rn - rm; + } + + if(p == 0 || w == 1) r[n] = rn; +} + +//(ldr)(str){condition}{b} rd,rn,rm {mode} #immediate +//cccc 011p ubwl nnnn dddd llll lss0 mmmm +//c = condition +//p = pre (0 = post-indexed addressing) +//u = up +//b = byte (1 = 32-bit) +//w = writeback +//l = load (0 = save) +//n = rn +//d = rd +//l = shift immediate +//s = shift mode +//m = rm +void ArmDSP::op_move_register_offset() { + if(!condition()) return; + + uint1 p = instruction >> 24; + uint1 u = instruction >> 23; + uint1 b = instruction >> 22; + uint1 w = instruction >> 21; + uint1 l = instruction >> 20; + uint4 n = instruction >> 16; + uint4 d = instruction >> 12; + uint5 immediate = instruction >> 7; + uint2 mode = instruction >> 5; + uint4 m = instruction; + + uint32 rn = r[n]; + auto &rd = r[d]; + uint32 rs = immediate; + uint32 rm = r[m]; + switch(mode) { case 0: //LSL rm = rm << rs; @@ -150,107 +322,30 @@ void ArmDSP::op_data_immediate_shift() { break; } - opcode(rm); -} - -//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) -//U = up (add/sub offset to base) -//B = byte (1 = 32-bit) -//W = writeback -//L = load (0 = save) -//N = Rn -//D = Rd -//I = immediate -void ArmDSP::op_move_immediate_offset() { - if(!condition()) return; - - uint1 p = instruction >> 24; - uint1 u = instruction >> 23; - uint1 b = instruction >> 22; - uint1 w = instruction >> 21; - uint1 l = instruction >> 20; - uint4 n = instruction >> 16; - auto &rd = r[(uint4)(instruction >> 12)]; - uint12 immediate = instruction; - - uint32 rn = r[n]; - if(l) { - if(p == 1) rn = u ? rn + immediate : rn - immediate; + if(p == 1) rn = u ? rn + rm : rn - rm; if(b) rd = bus_read<1>(rn); else rd = bus_read<4>(rn); - if(p == 0) rn = u ? rn + immediate : rn - immediate; + if(p == 0) rn = u ? rn + rm : rn - rm; } else { - if(p == 1) rn = u ? rn + immediate : rn - immediate; + if(p == 1) rn = u ? rn + rm : rn - rm; if(b) bus_write<1>(rn, rd); else bus_write<4>(rn, rd); - if(p == 0) rn = u ? rn + immediate : rn - immediate; + if(p == 0) rn = u ? rn + rm : rn - rm; } - if(p == 1 && w == 1) r[n] = rn; + if(p == 0 || w == 1) r[n] = rn; } -//CCCC 0001 0R10 FFFF ++++ ---- 0000 MMMM -//C = condition -//R = SPSR (0 = CPSR) -//F = field mask -//M = Rm -void ArmDSP::op_move_status_register_to_register() { - if(!condition()) return; - - uint1 source = instruction >> 22; - uint4 field = instruction >> 16; - - auto &rm = r[(uint4)instruction]; - PSR &psr = source ? spsr : cpsr; - - if(field & 1) psr.setc(rm); - if(field & 2) psr.setx(rm); - if(field & 4) psr.sets(rm); - if(field & 8) psr.setf(rm); -} - -//CCCC 100P USWL NNNN LLLL LLLL LLLL LLLL -//C = condition -//P = pre (0 = post-indexed addressing) -//U = up (add/sub offset to base) -//S = ??? -//W = writeback -//L = load (0 = save) -//N = Rn -//L = register list +//cccc 100p uswl nnnn llll llll llll llll +//c = condition +//p = pre (0 = post-indexed addressing) +//u = up (add/sub offset to base) +//s = ??? +//w = writeback +//l = load (0 = save) +//n = rn +//l = register list void ArmDSP::op_move_multiple() { if(!condition()) return; @@ -262,11 +357,11 @@ void ArmDSP::op_move_multiple() { uint4 n = instruction >> 16; uint16 list = instruction; - uint32 rn; - if(p == 0 && u == 1) rn = r[n] + 0; //IA - if(p == 1 && u == 1) rn = r[n] + 4; //IB - if(p == 1 && u == 0) rn = r[n] - bit::count(list) * 4 + 0; //DB - if(p == 0 && u == 0) rn = r[n] - bit::count(list) * 4 + 4; //DA + uint32 rn = r[n]; + if(p == 0 && u == 1) rn = rn + 0; //IA + if(p == 1 && u == 1) rn = rn + 4; //IB + if(p == 1 && u == 0) rn = rn - bit::count(list) * 4 + 0; //DB + if(p == 0 && u == 0) rn = rn - bit::count(list) * 4 + 4; //DA if(l) { for(unsigned n = 0; n < 16; n++) { @@ -288,8 +383,21 @@ 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; +//b{l}{condition} address +//cccc 101l dddd dddd dddd dddd dddd dddd +//c = condition +//l = link +//d = displacement (24-bit signed) +void ArmDSP::op_branch() { + if(!condition()) return; + + uint1 l = instruction >> 24; + int24 displacement = instruction; + + if(l) r[14] = r[15] - 4; + r[15] += displacement * 4; } #endif diff --git a/bsnes/snes/chip/armdsp/registers.hpp b/bsnes/snes/chip/armdsp/registers.hpp index a48ede8b..d9600e04 100755 --- a/bsnes/snes/chip/armdsp/registers.hpp +++ b/bsnes/snes/chip/armdsp/registers.hpp @@ -7,6 +7,19 @@ //00000018 = IRQ (interrupt) //0000001c = FIQ (fast interrupt) +struct Bridge { + struct Buffer { + bool ready; + uint8 data; + }; + Buffer cputoarm; + Buffer armtocpu; + + uint8 status() const { + return 0x80 | (cputoarm.ready << 3) | (armtocpu.ready << 0); + } +} bridge; + struct PSR { bool n; bool z;