diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 5278a08f..0088df18 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.11"; +const char Version[] = "086.12"; #include #include diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp index 64d49980..4fde7ee4 100755 --- a/bsnes/snes/chip/armdsp/armdsp.cpp +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -52,6 +52,7 @@ void ArmDSP::enter() { } instruction = pipeline.instruction.opcode; + if((instruction & 0x0fc000f0) == 0x00000090) { op_multiply(); 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; } @@ -126,7 +127,7 @@ 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.read(dataROM, 32 * 1024); fp.close(); } } diff --git a/bsnes/snes/chip/armdsp/armdsp.hpp b/bsnes/snes/chip/armdsp/armdsp.hpp index 548ebd55..7718a345 100755 --- a/bsnes/snes/chip/armdsp/armdsp.hpp +++ b/bsnes/snes/chip/armdsp/armdsp.hpp @@ -3,7 +3,7 @@ struct ArmDSP : public Coprocessor { uint8 programROM[128 * 1024]; uint8 programRAM[16 * 1024]; - uint8 aoRAM[32 * 1024]; + uint8 dataROM[32 * 1024]; #include "registers.hpp" @@ -23,6 +23,7 @@ struct ArmDSP : public Coprocessor { bool condition(); void opcode(uint32 data); + void op_multiply(); void op_move_to_status_register_from_register(); void op_move_to_register_from_status_register(); void op_data_immediate_shift(); diff --git a/bsnes/snes/chip/armdsp/disassembler.cpp b/bsnes/snes/chip/armdsp/disassembler.cpp index bec656b1..71a94fcb 100755 --- a/bsnes/snes/chip/armdsp/disassembler.cpp +++ b/bsnes/snes/chip/armdsp/disassembler.cpp @@ -40,7 +40,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) { //{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) { + if((instruction & 0x0e000010) == 0x00000000) { uint4 condition = instruction >> 28; uint4 opcode = instruction >> 21; uint1 save = instruction >> 20; diff --git a/bsnes/snes/chip/armdsp/memory.cpp b/bsnes/snes/chip/armdsp/memory.cpp index dcd5f16e..3eab5ddd 100755 --- a/bsnes/snes/chip/armdsp/memory.cpp +++ b/bsnes/snes/chip/armdsp/memory.cpp @@ -25,7 +25,7 @@ uint8 ArmDSP::bus_iread(uint32 addr) { } if(addr >= 0xa0000000 && addr <= 0xa0007fff) { - return aoRAM[addr & 0x00007fff]; + return dataROM[addr & 0x00007fff]; } if(addr >= 0xe0000000 && addr <= 0xe0003fff) { @@ -50,9 +50,6 @@ void ArmDSP::bus_iwrite(uint32 addr, uint8 data) { 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; @@ -64,10 +61,19 @@ void ArmDSP::bus_iwrite(uint32 addr, uint8 data) { template uint32 ArmDSP::bus_read(uint32 addr) { 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(size == 1) { + uint32 mask = 255u << ((addr & ~3) << 3); + data |= bus_iread(addr) & mask; + } + + if(size == 4) { + addr &= ~3; + 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(0&&addr >= 0x40000000 && addr <= 0x400000ff) { if(addr != 0x40000020 || data != 0x80) @@ -95,12 +101,18 @@ void ArmDSP::bus_write(uint32 addr, uint32 data) { } } - 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); - bus_iwrite(addr + 1, data >> 8); - bus_iwrite(addr + 2, data >> 16); - bus_iwrite(addr + 3, data >> 24); + if(size == 1) { + uint32 mask = 255u << ((addr & ~3) << 3); + bus_iwrite(addr, data); + } + + if(size == 4) { + addr &= ~3; + bus_iwrite(addr + 0, data >> 0); + bus_iwrite(addr + 1, data >> 8); + bus_iwrite(addr + 2, data >> 16); + bus_iwrite(addr + 3, data >> 24); + } } #endif diff --git a/bsnes/snes/chip/armdsp/opcodes.cpp b/bsnes/snes/chip/armdsp/opcodes.cpp index 99abdf4c..8ff6b1e7 100755 --- a/bsnes/snes/chip/armdsp/opcodes.cpp +++ b/bsnes/snes/chip/armdsp/opcodes.cpp @@ -36,13 +36,13 @@ void ArmDSP::opcode(uint32 rm) { //comparison opcodes always update flags if(opcode >= 8 && opcode <= 11) assert(s == 1); - static auto nz = [&](uint32 ro) { + static auto bit = [&](uint32 ro) { if(!s) return; cpsr.n = ro & 0x80000000; cpsr.z = ro == 0; }; - static auto nzcv = [&](uint32 ro) { + static auto add = [&](uint32 ro) { if(!s) return; cpsr.n = ro & 0x80000000; cpsr.z = ro == 0; @@ -50,23 +50,58 @@ void ArmDSP::opcode(uint32 rm) { cpsr.v = ~(ri ^ rm) & (ri ^ ro) & 0x80000000; }; + static auto sub = [&](uint32 ro) { + if(!s) return; + cpsr.n = ro & 0x80000000; + cpsr.z = ro == 0; + cpsr.c = ro > ri; + cpsr.v = (ri ^ rm) & (ri ^ ro) & 0x80000000; + }; + 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 + 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 + 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) - case 14: rd = rn &~rm; nz(rd); break; //BIC (bit clear) - case 15: rd =~rm; nz(rd); break; //MVN (move not) + case 0: rd = rn & rm; bit(rd); break; //AND (logical and) + case 1: rd = rn ^ rm; bit(rd); break; //EOR (logical exclusive or) + case 2: rd = rn - rm; sub(rd); break; //SUB (subtract) + case 3: rd = rm - rn; sub(rd); break; //RSB (reverse subtract) + case 4: rd = rn + rm; add(rd); break; //ADD (add) + case 5: rd = rn + rm + cpsr.c; add(rd); break; //ADC (add with carry) + case 6: rd = rn - rm -!cpsr.c; sub(rd); break; //SBC (subtract with carry) + case 7: rd = rm - rn -!cpsr.c; sub(rd); break; //RSC (reverse subtract with carry) + case 8: ro = rn & rm; bit(ro); break; //TST (test) + case 9: ro = rn ^ rm; bit(ro); break; //TEQ (test equivalence) + case 10: ro = rn - rm; sub(ro); break; //CMP (compare) + case 11: ro = rn + rm; add(ro); break; //CMN (compare negated) + case 12: rd = rn | rm; bit(rd); break; //ORR (logical inclusive or) + case 13: rd = rm; bit(rd); break; //MOV (move) + case 14: rd = rn &~rm; bit(rd); break; //BIC (bit clear) + case 15: rd =~rm; bit(rd); break; //MVN (move not) + } +} + +//(mul,mla){condition}{s} +//cccc 0000 00as dddd nnnn ssss 1001 mmmm +//c = condition +//a = accumulate +//s = save flags +//d = rd +//n = rn +//s = rs +//n = rm +void ArmDSP::op_multiply() { + if(!condition()) return; + + uint1 accumulate = instruction >> 21; + uint1 save = instruction >> 20; + uint4 d = instruction >> 16; + uint4 n = instruction >> 12; + uint4 s = instruction >> 8; + uint4 m = instruction >> 0; + + r[d] = r[m] * r[s]; + if(accumulate) r[d] += r[n]; + if(save) { + cpsr.n = r[d] & 0x80000000; + cpsr.z = r[d] == 0; } }