diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 0b8489bf..30ff4f74 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.10"; +static const char Version[] = "087.11"; #include #include diff --git a/bsnes/gba/cpu/cpu.cpp b/bsnes/gba/cpu/cpu.cpp index e58fe827..f9447b66 100755 --- a/bsnes/gba/cpu/cpu.cpp +++ b/bsnes/gba/cpu/cpu.cpp @@ -2,20 +2,23 @@ namespace GBA { +#include "registers.cpp" CPU cpu; void CPU::Enter() { cpu.enter(); } void CPU::enter() { while(true) { - if(exception) { + if(crash) { 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(); + + processor.irqline = regs.ime && regs.irq_flag; + exec(); } } @@ -44,17 +47,57 @@ void CPU::power() { for(unsigned n = 0; n < iwram.size; n++) iwram.data[n] = 0; for(unsigned n = 0; n < ewram.size; n++) ewram.data[n] = 0; - bus.mmio[0x0300] = this; - bus.mmio[0x0301] = this; - bus.mmio[0x0302] = this; - bus.mmio[0x0303] = this; + regs.ime = 0; + regs.irq_enable = 0; + regs.irq_flag = 0; + + bus.mmio[0x130] = this; + bus.mmio[0x200] = this; + bus.mmio[0x202] = this; + bus.mmio[0x208] = this; } uint32 CPU::read(uint32 addr, uint32 size) { + uint32 result = 0; + + switch(addr & 0x0ffffffc) { + + case 0x04000130: //KEYINPUT + for(unsigned n = 0; n < 10; n++) result |= (interface->inputPoll(n) == false) << n; + if((result & 0xc0) == 0xc0) result &= ~0xc0; //up+down cannot be pressed simultaneously + if((result & 0x30) == 0x30) result &= ~0x30; //left+right cannot be pressed simultaneously + return result; + + case 0x04000200: //IE + return regs.irq_enable; + + case 0x04000202: //IF + return regs.irq_flag; + + case 0x04000208: //IME + return regs.ime; + + } + return 0u; } void CPU::write(uint32 addr, uint32 size, uint32 word) { + switch(addr & 0x0ffffffc) { + + case 0x04000200: //IE + regs.irq_enable = word; + return; + + case 0x04000202: //IF + regs.irq_flag = regs.irq_flag & ~word; + return; + + case 0x04000208: //IME + regs.ime = word & 1; + return; + + } } CPU::CPU() { diff --git a/bsnes/gba/cpu/cpu.hpp b/bsnes/gba/cpu/cpu.hpp index f46cf90e..86f9b5bb 100755 --- a/bsnes/gba/cpu/cpu.hpp +++ b/bsnes/gba/cpu/cpu.hpp @@ -1,6 +1,7 @@ struct CPU : Processor::ARM, Thread, Memory { StaticMemory iwram; StaticMemory ewram; + #include "registers.hpp" static void Enter(); void enter(); diff --git a/bsnes/gba/cpu/registers.cpp b/bsnes/gba/cpu/registers.cpp new file mode 100755 index 00000000..03e80866 --- /dev/null +++ b/bsnes/gba/cpu/registers.cpp @@ -0,0 +1,35 @@ +CPU::Registers::Interrupt::operator uint16() const { + return ( + (vblank << 0) + || (hblank << 1) + || (vcoincidence << 2) + || (timer0 << 3) + || (timer1 << 4) + || (timer2 << 5) + || (timer3 << 6) + || (serial << 7) + || (dma0 << 8) + || (dma1 << 9) + || (dma2 << 10) + || (dma3 << 11) + || (keypad << 12) + || (cartridge << 13) + ); +} + +CPU::Registers::Interrupt& CPU::Registers::Interrupt::operator=(uint16 source) { + vblank = source & (1 << 0); + hblank = source & (1 << 1); + vcoincidence = source & (1 << 2); + timer0 = source & (1 << 3); + timer1 = source & (1 << 4); + timer2 = source & (1 << 5); + timer3 = source & (1 << 6); + serial = source & (1 << 7); + dma0 = source & (1 << 8); + dma1 = source & (1 << 9); + dma2 = source & (1 << 10); + dma3 = source & (1 << 11); + keypad = source & (1 << 12); + cartridge = source & (1 << 13); +} diff --git a/bsnes/gba/cpu/registers.hpp b/bsnes/gba/cpu/registers.hpp new file mode 100755 index 00000000..9666355e --- /dev/null +++ b/bsnes/gba/cpu/registers.hpp @@ -0,0 +1,23 @@ +struct Registers { + bool ime; + + struct Interrupt { + bool vblank; + bool hblank; + bool vcoincidence; + bool timer0; + bool timer1; + bool timer2; + bool timer3; + bool serial; + bool dma0; + bool dma1; + bool dma2; + bool dma3; + bool keypad; + bool cartridge; + + operator uint16() const; + Interrupt& operator=(uint16 source); + } irq_enable, irq_flag; +} regs; diff --git a/bsnes/gba/ppu/ppu.cpp b/bsnes/gba/ppu/ppu.cpp index 42dc6248..500b2fce 100755 --- a/bsnes/gba/ppu/ppu.cpp +++ b/bsnes/gba/ppu/ppu.cpp @@ -8,7 +8,7 @@ //vdraw: 160 scanlines (197120 cycles) //vblank: 68 scanlines ( 83776 cycles) -//frame: 208 scanlines (280896 cycles) +//frame: 228 scanlines (280896 cycles) namespace GBA { @@ -18,8 +18,8 @@ void PPU::Enter() { ppu.enter(); } void PPU::enter() { while(true) { - frame(); - step(280896); + step(1232); + scanline(); } } @@ -34,6 +34,27 @@ void PPU::power() { for(unsigned n = 0; n < vram.size; n++) vram.data[n] = 0; for(unsigned n = 0; n < oam.size; n++) oam.data[n] = 0; for(unsigned n = 0; n < pram.size; n++) pram.data[n] = 0; + + regs.scanline = 0; + + bus.mmio[0x006] = this; +} + +void PPU::scanline() { + regs.scanline++; + + if(regs.scanline == 160) { + if(cpu.regs.ime && cpu.regs.irq_enable.vblank) { + cpu.regs.irq_flag.vblank = 1; + } + } + + if(regs.scanline == 228) { + regs.scanline = 0; + frame(); + } + + if(regs.scanline >= 160) return; } void PPU::frame() { @@ -57,6 +78,11 @@ void PPU::frame() { } uint32 PPU::read(uint32 addr, uint32 size) { + if(addr == 0x04000006) { + //VCOUNT + return regs.scanline; + } + return 0u; } diff --git a/bsnes/gba/ppu/ppu.hpp b/bsnes/gba/ppu/ppu.hpp index 68c4178a..c9f3e70f 100755 --- a/bsnes/gba/ppu/ppu.hpp +++ b/bsnes/gba/ppu/ppu.hpp @@ -3,11 +3,16 @@ struct PPU : Thread, Memory { StaticMemory oam; StaticMemory pram; + struct Registers { + unsigned scanline; + } regs; + static void Enter(); void enter(); void step(unsigned clocks); void power(); + void scanline(); void frame(); uint32 read(uint32 addr, uint32 size); diff --git a/bsnes/processor/arm/algorithms.cpp b/bsnes/processor/arm/algorithms.cpp index b4c3c35d..34d562cf 100755 --- a/bsnes/processor/arm/algorithms.cpp +++ b/bsnes/processor/arm/algorithms.cpp @@ -18,3 +18,121 @@ bool ARM::condition(uint4 condition) { case 15: return false; //NV (never) } } + +uint32 ARM::bit(uint32 result) { + if(cpsr().t || instruction() & (1 << 20)) { + cpsr().n = result >> 31; + cpsr().z = result == 0; + cpsr().c = carryout(); + } + return result; +} + +uint32 ARM::add(uint32 source, uint32 modify, bool carry) { + uint32 result = source + modify + carry; + if(cpsr().t || instruction() & (1 << 20)) { + uint32 overflow = ~(source ^ modify) & (source ^ result); + cpsr().n = result >> 31; + cpsr().z = result == 0; + cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result); + cpsr().v = (1u << 31) & (overflow); + } + return result; +} + +uint32 ARM::sub(uint32 source, uint32 modify, bool carry) { + return add(source, ~modify, carry); +} + +uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) { + //Modified Booth Encoding + bool carry = 0; + unsigned place = 0; + + do { + step(1); + signed factor = (int2)multiplier + carry; + + if(factor == -2) product -= multiplicand << (place + 1); + if(factor == -1) product -= multiplicand << (place + 0); + if(factor == +1) product += multiplicand << (place + 0); + if(factor == +2) product += multiplicand << (place + 1); + + carry = multiplier & 2; + place += 2; + multiplier >>= 2; + } while(multiplier + carry && place < 32); + + if(cpsr().t || instruction() & (1 << 20)) { + cpsr().n = product >> 31; + cpsr().z = product == 0; + cpsr().c = carry; + } + + return product; +} + +uint32 ARM::lsl(uint32 source, uint32 shift) { + while(shift--) { + carryout() = source >> 31; + source <<= 1; + } + + if(cpsr().t) { + cpsr().n = source >> 31; + cpsr().z = source == 0; + cpsr().c = carryout(); + } + + return source; +} + +uint32 ARM::lsr(uint32 source, uint32 shift) { + while(shift--) { + carryout() = source & 1; + source >>= 1; + } + + if(cpsr().t) { + cpsr().n = source >> 31; + cpsr().z = source == 0; + cpsr().c = carryout(); + } + + return source; +} + +uint32 ARM::asr(uint32 source, uint32 shift) { + while(shift--) { + carryout() = source & 1; + source = (int32)source >> 1; + } + + if(cpsr().t) { + cpsr().n = source >> 31; + cpsr().z = source == 0; + cpsr().c = carryout(); + } + + return source; +} + +uint32 ARM::ror(uint32 source, uint32 shift) { + while(shift--) { + carryout() = source & 1; + source = (source << 31) | (source >> 1); + } + + if(cpsr().t) { + cpsr().n = source >> 31; + cpsr().z = source == 0; + cpsr().c = carryout(); + } + + return source; +} + +uint32 ARM::rrx(uint32 source) { + carryout() = source & 1; + source = (cpsr().c << 31) | (source >> 1); +} diff --git a/bsnes/processor/arm/arm.cpp b/bsnes/processor/arm/arm.cpp index efadd0ee..74ababe5 100755 --- a/bsnes/processor/arm/arm.cpp +++ b/bsnes/processor/arm/arm.cpp @@ -13,7 +13,7 @@ void ARM::power() { processor.power(); vector(0x00000000, Processor::Mode::SVC); pipeline.reload = true; - exception = false; + crash = false; r(15).modify = [&] { pipeline.reload = true; r(15).data &= cpsr().t ? ~1 : ~3; @@ -23,6 +23,15 @@ void ARM::power() { instructions = 0; } +void ARM::exec() { + if(processor.irqline && cpsr().i == 0) { + vector(0x00000018, Processor::Mode::IRQ); + r(14) += 4; + } + + cpsr().t ? thumb_step() : arm_step(); +} + void ARM::vector(uint32 addr, Processor::Mode mode) { auto psr = cpsr(); processor.setMode(mode); diff --git a/bsnes/processor/arm/arm.hpp b/bsnes/processor/arm/arm.hpp index 070006e0..98f69b7a 100755 --- a/bsnes/processor/arm/arm.hpp +++ b/bsnes/processor/arm/arm.hpp @@ -16,8 +16,19 @@ struct ARM { virtual void bus_write(uint32 addr, uint32 size, uint32 word) = 0; void power(); + void exec(); void vector(uint32 addr, Processor::Mode mode); + bool condition(uint4 condition); + uint32 bit(uint32 result); + uint32 add(uint32 source, uint32 modify, bool carry); + uint32 sub(uint32 source, uint32 modify, bool carry); + uint32 mul(uint32 product, uint32 multiplicand, uint32 multiplier); + uint32 lsl(uint32 source, uint32 shift); + uint32 lsr(uint32 source, uint32 shift); + uint32 asr(uint32 source, uint32 shift); + uint32 ror(uint32 source, uint32 shift); + uint32 rrx(uint32 source); void serialize(serializer&); diff --git a/bsnes/processor/arm/disassembler.cpp b/bsnes/processor/arm/disassembler.cpp index b7a706c7..9d827686 100755 --- a/bsnes/processor/arm/disassembler.cpp +++ b/bsnes/processor/arm/disassembler.cpp @@ -746,12 +746,14 @@ string ARM::disassemble_registers() { string output; output.append( "r0:", hex<8>(r( 0)), " r1:", hex<8>(r( 1)), " r2:", hex<8>(r( 2)), " r3:", hex<8>(r( 3)), " "); output.append( "r4:", hex<8>(r( 4)), " r5:", hex<8>(r( 5)), " r6:", hex<8>(r( 6)), " r7:", hex<8>(r( 7)), " "); - output.append("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v", "\n"); + output.append("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v"); + output.append("/", hex<2>(cpsr().m), "\n"); output.append( "r8:", hex<8>(r( 8)), " r9:", hex<8>(r( 9)), " r10:", hex<8>(r(10)), " r11:", hex<8>(r(11)), " "); output.append("r12:", hex<8>(r(12)), " sp:", hex<8>(r(13)), " lr:", hex<8>(r(14)), " pc:", hex<8>(r(15)), " "); output.append("spsr:"); - if(mode() == Processor::Mode::USR || mode() == Processor::Mode::SYS) { output.append("----"); return output; } + 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("/", hex<2>(spsr().m)); return output; } diff --git a/bsnes/processor/arm/instructions-arm.cpp b/bsnes/processor/arm/instructions-arm.cpp index 78387d13..bd5c3a1d 100755 --- a/bsnes/processor/arm/instructions-arm.cpp +++ b/bsnes/processor/arm/instructions-arm.cpp @@ -7,18 +7,11 @@ void ARM::arm_step() { pipeline.fetch.address = r(15); pipeline.fetch.instruction = bus_read(r(15), Word); - r(15).data += 4; - pipeline.decode = pipeline.fetch; - pipeline.fetch.address = r(15); - pipeline.fetch.instruction = bus_read(r(15), Word); + pipeline_step(); step(2); } - r(15).data += 4; - pipeline.execute = pipeline.decode; - pipeline.decode = pipeline.fetch; - pipeline.fetch.address = r(15); - pipeline.fetch.instruction = bus_read(r(15), Word); + pipeline_step(); step(2); instructions++; @@ -34,21 +27,19 @@ void ARM::arm_step() { == std::integral_constant::value \ ) return arm_op_ ## execute() + decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register); decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply); + decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status); decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap); - decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register); - decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate); + decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register); + decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_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?? ???? ???? ---- 1011 ????", move_half_register); + decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate); 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); @@ -57,7 +48,7 @@ void ARM::arm_step() { #undef decode - exception = true; + crash = true; } void ARM::arm_opcode(uint32 rm) { @@ -68,44 +59,28 @@ void ARM::arm_opcode(uint32 rm) { uint32 rn = r(n); - auto test = [&](uint32 result) { - if(save) { - cpsr().n = result >> 31; - cpsr().z = result == 0; - cpsr().c = carryout(); - } - return result; - }; - - auto math = [&](uint32 source, uint32 modify, bool carry) { - uint32 result = source + modify + carry; - if(save) { - uint32 overflow = ~(source ^ modify) & (source ^ result); - cpsr().n = result >> 31; - cpsr().z = result == 0; - cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result); - cpsr().v = (1u << 31) & (overflow); - } - return result; - }; - switch(opcode) { - case 0: r(d) = test(rn & rm); break; //AND - case 1: r(d) = test(rn ^ rm); break; //EOR - case 2: r(d) = math(rn, ~rm, 1); break; //SUB - case 3: r(d) = math(rm, ~rn, 1); break; //RSB - case 4: r(d) = math(rn, rm, 0); break; //ADD - case 5: r(d) = math(rn, rm, cpsr().c); break; //ADC - case 6: r(d) = math(rn, ~rm, cpsr().c); break; //SBC - case 7: r(d) = math(rm, ~rn, cpsr().c); break; //RSC - case 8: test(rn & rm); break; //TST - case 9: test(rn ^ rm); break; //TEQ - case 10: math(rn, ~rm, 1); break; //CMP - case 11: math(rn, rm, 0); break; //CMN - case 12: r(d) = test(rn | rm); break; //ORR - case 13: r(d) = test(rm); break; //MOV - case 14: r(d) = test(rn &~rm); break; //BIC - case 15: r(d) = test(~rm); break; //MVN + case 0: r(d) = bit(rn & rm); break; //AND + case 1: r(d) = bit(rn ^ rm); break; //EOR + case 2: r(d) = sub(rn, rm, 1); break; //SUB + case 3: r(d) = sub(rm, rn, 1); break; //RSB + case 4: r(d) = add(rn, rm, 0); break; //ADD + case 5: r(d) = add(rn, rm, cpsr().c); break; //ADC + case 6: r(d) = sub(rn, rm, cpsr().c); break; //SBC + case 7: r(d) = sub(rm, rn, cpsr().c); break; //RSC + case 8: bit(rn & rm); break; //TST + case 9: bit(rn ^ rm); break; //TEQ + case 10: sub(rn, rm, 1); break; //CMP + case 11: add(rn, rm, 0); break; //CMN + case 12: r(d) = bit(rn | rm); break; //ORR + case 13: r(d) = bit(rm); break; //MOV + case 14: r(d) = bit(rn & ~rm); break; //BIC + case 15: r(d) = bit(~rm); break; //MVN + } + + if(exceptionmode() && d == 15 && save) { + cpsr() = spsr(); + processor.setMode((Processor::Mode)cpsr().m); } } @@ -121,7 +96,7 @@ void ARM::arm_move_to_status(uint32 rm) { PSR &psr = source ? spsr() : cpsr(); if(field & 1) { - if(source == 1 || (Processor::Mode)cpsr().m != Processor::Mode::USR) { + if(source == 1 || privilegedmode()) { psr.i = rm & 0x00000080; psr.f = rm & 0x00000040; psr.t = rm & 0x00000020; @@ -138,45 +113,6 @@ void ARM::arm_move_to_status(uint32 rm) { } } -//logical shift left -void ARM::lsl(bool &c, uint32 &rm, uint32 rs) { - while(rs--) { - c = rm >> 31; - rm <<= 1; - } -} - -//logical shift right -void ARM::lsr(bool &c, uint32 &rm, uint32 rs) { - while(rs--) { - c = rm & 1; - rm >>= 1; - } -} - -//arithmetic shift right -void ARM::asr(bool &c, uint32 &rm, uint32 rs) { - while(rs--) { - c = rm & 1; - rm = (int32)rm >> 1; - } -} - -//rotate right -void ARM::ror(bool &c, uint32 &rm, uint32 rs) { - while(rs--) { - c = rm & 1; - rm = (rm << 31) | (rm >> 1); - } -} - -//rotate right with extend -void ARM::rrx(bool &c, uint32 &rm) { - bool carry = c; - c = rm & 1; - rm = (carry << 31) | (rm >> 1); -} - //mul{condition}{s} rd,rm,rs //mla{condition}{s} rd,rm,rs,rn //cccc 0000 00as dddd nnnn ssss 1001 mmmm @@ -189,42 +125,14 @@ void ARM::rrx(bool &c, uint32 &rm) { //n = rm void ARM::arm_op_multiply() { uint1 accumulate = instruction() >> 21; - uint1 save = instruction() >> 20; uint4 d = instruction() >> 16; uint4 n = instruction() >> 12; uint4 s = instruction() >> 8; uint4 m = instruction() >> 0; - auto &rd = r(d); - uint32 rs = r(s); - auto &rm = r(m); - - rd = accumulate ? r(n) : 0u; + r(d) = accumulate ? r(n) : 0u; step(1); - - //Modified Booth Encoding - bool carry = 0; - unsigned place = 0; - - do { - step(1); - signed factor = (int2)rs + carry; - - if(factor == -2) rd -= rm << (place + 1); - if(factor == -1) rd -= rm << (place + 0); - if(factor == +1) rd += rm << (place + 0); - if(factor == +2) rd += rm << (place + 1); - - carry = rs & 2; - place += 2; - rs >>= 2; - } while(rs + carry && place < 32); - - if(save) { - cpsr().n = r(d) >> 31; - cpsr().z = r(d) == 0; - cpsr().c = carry; - } + r(d) = mul(r(d), r(m), r(s)); } //swp{condition}{b} rd,rm,[rn] @@ -269,8 +177,8 @@ void ARM::arm_op_move_half_register() { 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(load == 1) r(d) = bus_read(rn, Half); + if(load == 0) bus_write(rn, Half, r(d)); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; @@ -302,8 +210,8 @@ void ARM::arm_op_move_half_immediate() { 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(load == 1) r(d) = bus_read(rn, Half); + if(load == 0) bus_write(rn, Half, r(d)); if(pre == 0) rn = up ? rn + immediate : rn - immediate; if(pre == 0 || writeback == 1) r(n) = rn; @@ -335,7 +243,7 @@ void ARM::arm_op_load_register() { 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) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; } @@ -425,8 +333,7 @@ void ARM::arm_op_move_to_status_from_immediate() { uint8 immediate = instruction(); uint32 rm = immediate; - bool c = cpsr().c; - if(rotate) ror(c, rm, 2 * rotate); + if(rotate) rm = ror(rm, 2 * rotate); arm_move_to_status(rm); } @@ -451,14 +358,12 @@ void ARM::arm_op_data_immediate_shift() { uint32 rs = shift; uint32 rm = r(m); - bool c = cpsr().c; - if(mode == 0) lsl(c, rm, rs); - if(mode == 1) lsr(c, rm, rs ? rs : 32); - if(mode == 2) asr(c, rm, rs ? rs : 32); - if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm); + if(mode == 0) rm = lsl(rm, rs); + if(mode == 1) rm = lsr(rm, rs ? rs : 32); + if(mode == 2) rm = asr(rm, rs ? rs : 32); + if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm); - carryout() = c; arm_opcode(rm); } @@ -482,14 +387,12 @@ void ARM::arm_op_data_register_shift() { uint8 rs = r(s); uint32 rm = r(m); - bool c = cpsr().c; - if(mode == 0) lsl(c, rm, rs < 33 ? rs : 33); - if(mode == 1) lsr(c, rm, rs < 33 ? rs : 33); - if(mode == 2) asr(c, rm, rs < 32 ? rs : 32); - if(mode == 3 && rs) ror(c, rm, rs & 31 == 0 ? 32 : rs & 31); + if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : 33); + if(mode == 1 ) rm = lsr(rm, rs < 33 ? rs : 33); + if(mode == 2 ) rm = asr(rm, rs < 32 ? rs : 32); + if(mode == 3 && rs) rm = ror(rm, rs & 31 == 0 ? 32 : rs & 31); - carryout() = c; arm_opcode(rm); } @@ -584,10 +487,10 @@ void ARM::arm_op_move_register_offset() { uint32 rm = r(m); bool c = cpsr().c; - if(mode == 0) lsl(c, rm, rs); - if(mode == 1) lsr(c, rm, rs ? rs : 32); - if(mode == 2) asr(c, rm, rs ? rs : 32); - if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm); + if(mode == 0) rm = lsl(rm, rs); + if(mode == 1) rm = lsr(rm, rs ? rs : 32); + if(mode == 2) rm = asr(rm, rs ? rs : 32); + if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm); if(pre == 1) rn = up ? rn + rm : rn - rm; if(load) { diff --git a/bsnes/processor/arm/instructions-arm.hpp b/bsnes/processor/arm/instructions-arm.hpp index ea0dc83c..efd9a8b1 100755 --- a/bsnes/processor/arm/instructions-arm.hpp +++ b/bsnes/processor/arm/instructions-arm.hpp @@ -1,15 +1,8 @@ void arm_step(); -bool arm_condition(); void arm_opcode(uint32 rm); void arm_move_to_status(uint32 rm); -void lsl(bool &c, uint32 &rm, uint32 rs); -void lsr(bool &c, uint32 &rm, uint32 rs); -void asr(bool &c, uint32 &rm, uint32 rs); -void ror(bool &c, uint32 &rm, uint32 rs); -void rrx(bool &c, uint32 &rm); - void arm_op_multiply(); void arm_op_memory_swap(); void arm_op_move_half_register(); diff --git a/bsnes/processor/arm/instructions-thumb.cpp b/bsnes/processor/arm/instructions-thumb.cpp index 58e67993..5327cc3e 100755 --- a/bsnes/processor/arm/instructions-thumb.cpp +++ b/bsnes/processor/arm/instructions-thumb.cpp @@ -7,18 +7,11 @@ void ARM::thumb_step() { pipeline.fetch.address = r(15); pipeline.fetch.instruction = bus_read(r(15), Half); - r(15).data += 2; - pipeline.decode = pipeline.fetch; - pipeline.fetch.address = r(15); - pipeline.fetch.instruction = bus_read(r(15), Half); + pipeline_step(); step(1); } - r(15).data += 2; - pipeline.execute = pipeline.decode; - pipeline.decode = pipeline.fetch; - pipeline.fetch.address = r(15); - pipeline.fetch.instruction = bus_read(r(15), Half); + pipeline_step(); step(1); instructions++; @@ -57,98 +50,30 @@ void ARM::thumb_step() { #undef decode - exception = true; + crash = true; } void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) { switch(opcode) { - case 0: r(d) = thumb_tst(r(d) & r(m)); break; //AND - case 1: r(d) = thumb_tst(r(d) ^ r(m)); break; //EOR - case 2: r(d) = thumb_lsl(r(d), r(m) & 0xff); break; //LSL - case 3: r(d) = thumb_lsr(r(d), r(m) & 0xff); break; //LSR - case 4: r(d) = thumb_asr(r(d), r(m) & 0xff); break; //ASR - case 5: r(d) = thumb_add(r(d), r(m), cpsr().c); break; //ADC - case 6: r(d) = thumb_sub(r(d), r(m), cpsr().c); break; //SBC - case 7: r(d) = thumb_ror(r(d), r(m) & 0xff); break; //ROR - case 8: thumb_tst(r(d) & r(m)); break; //TST - case 9: r(d) = thumb_sub(0, r(m)); break; //NEG - case 10: thumb_sub(r(d), r(m)); break; //CMP - case 11: thumb_add(r(d), r(m)); break; //CMN - case 12: r(d) = thumb_tst(r(d) | r(m)); break; //ORR - case 13: r(d) = thumb_mul(r(d), r(m)); break; //MUL - case 14: r(d) = thumb_tst(r(d) & ~r(m)); break; //BIC - case 15: r(d) = thumb_tst(~r(m)); break; //MVN + case 0: r(d) = bit(r(d) & r(m)); break; //AND + case 1: r(d) = bit(r(d) ^ r(m)); break; //EOR + case 2: r(d) = lsl(r(d), r(m) & 0xff); break; //LSL + case 3: r(d) = lsr(r(d), r(m) & 0xff); break; //LSR + case 4: r(d) = asr(r(d), r(m) & 0xff); break; //ASR + case 5: r(d) = add(r(d), r(m), cpsr().c); break; //ADC + case 6: r(d) = sub(r(d), r(m), cpsr().c); break; //SBC + case 7: r(d) = ror(r(d), r(m) & 0xff); break; //ROR + case 8: bit(r(d) & r(m)); break; //TST + case 9: r(d) = sub(0, r(m), 1); break; //NEG + case 10: sub(r(d), r(m), 1); break; //CMP + case 11: add(r(d), r(m), 0); break; //CMN + case 12: r(d) = bit(r(d) | r(m)); break; //ORR + case 13: r(d) = mul(0, r(d), r(m)); break; //MUL + case 14: r(d) = bit(r(d) & ~r(m)); break; //BIC + case 15: r(d) = bit(~r(m)); break; //MVN } } -uint32 ARM::thumb_tst(uint32 modify) { - cpsr().n = modify >> 31; - cpsr().z = modify == 0; - return modify; -} - -uint32 ARM::thumb_add(uint32 source, uint32 modify, bool carry) { - uint32 result = source + modify + carry; - uint32 overflow = ~(source ^ modify) & (source ^ result); - cpsr().n = result >> 31; - cpsr().z = result == 0; - cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result); - cpsr().v = (1u << 31) & (overflow); - return result; -} - -uint32 ARM::thumb_sub(uint32 source, uint32 modify, bool carry) { - thumb_add(source, ~modify, carry); -} - -uint32 ARM::thumb_lsl(uint32 source, uint32 modify) { - while(modify--) { - cpsr().c = source >> 31; - source <<= 1; - } - cpsr().n = source >> 31; - cpsr().z = source == 0; - return source; -} - -uint32 ARM::thumb_lsr(uint32 source, uint32 modify) { - while(modify--) { - cpsr().c = source & 1; - source >>= 1; - } - cpsr().n = source >> 31; - cpsr().z = source == 0; - return source; -} - -uint32 ARM::thumb_asr(uint32 source, uint32 modify) { - while(modify--) { - cpsr().c = source & 1; - source = (int32)source >> 1; - } - cpsr().n = source >> 31; - cpsr().z = source == 0; - return source; -} - -uint32 ARM::thumb_ror(uint32 source, uint32 modify) { - while(modify--) { - cpsr().c = source & 1; - source = (source << 31) | (source >> 1); - } - cpsr().n = source >> 31; - cpsr().z = source == 0; - return source; -} - -uint32 ARM::thumb_mul(uint32 source, uint32 modify) { - source = source * modify; - cpsr().n = source >> 31; - cpsr().z = source == 0; - cpsr().c = 0; - return source; -} - //(add,sub) rd,rn,rm //0001 10om mmnn nddd //o = opcode @@ -162,8 +87,8 @@ void ARM::thumb_op_adjust_register() { uint3 d = instruction() >> 0; switch(opcode) { - case 0: r(d) = thumb_add(r(n), r(m)); break; - case 1: r(d) = thumb_sub(r(n), r(m)); break; + case 0: r(d) = add(r(n), r(m), 0); break; + case 1: r(d) = sub(r(n), r(m), 1); break; } } @@ -180,8 +105,8 @@ void ARM::thumb_op_adjust_immediate() { uint3 d = instruction() >> 0; switch(opcode) { - case 0: r(d) = thumb_add(r(n), immediate); break; - case 1: r(d) = thumb_sub(r(n), immediate); break; + case 0: r(d) = add(r(n), immediate, 0); break; + case 1: r(d) = sub(r(n), immediate, 1); break; } } @@ -198,9 +123,9 @@ void ARM::thumb_op_shift_immediate() { uint3 d = instruction() >> 0; switch(opcode) { - case 0: r(d) = thumb_lsl(r(m), immediate); break; - case 1: r(d) = thumb_lsr(r(m), immediate); break; - case 2: r(d) = thumb_asr(r(m), immediate); break; + case 0: r(d) = lsl(r(m), immediate); break; + case 1: r(d) = lsr(r(m), immediate); break; + case 2: r(d) = asr(r(m), immediate); break; } } @@ -215,10 +140,10 @@ void ARM::thumb_op_immediate() { uint8 immediate = instruction(); switch(opcode) { - case 0: r(d) = thumb_tst( immediate); break; - case 1: thumb_sub(r(d), immediate); break; - case 2: r(d) = thumb_add(r(d), immediate); break; - case 3: r(d) = thumb_sub(r(d), immediate); break; + case 0: r(d) = bit( immediate ); break; + case 1: sub(r(d), immediate, 1); break; + case 2: r(d) = add(r(d), immediate, 0); break; + case 3: r(d) = sub(r(d), immediate, 1); break; } } @@ -258,9 +183,9 @@ void ARM::thumb_op_alu_hi() { uint4 d = (dh << 3) + (dl << 0); switch(opcode) { - case 0: r(d) = thumb_add(r(d), r(m)); break; //ADD - case 1: thumb_sub(r(d), r(m)); break; //SUB - case 2: r(d) = thumb_tst( r(m)); break; //MOV + case 0: r(d) = r(d) + r(m); break; //ADD (does not modify flags) + case 1: sub(r(d), r(m), 1); break; //SUB + case 2: r(d) = r(m); break; //MOV (does not modify flags) } } @@ -313,7 +238,7 @@ void ARM::thumb_op_move_word_immediate() { uint3 d = instruction() >> 0; if(load == 1) r(d) = bus_read(r(n) + offset * 4, Word); - if(load == 0) bus_write(r(d) + offset * 4, Word, r(n)); + if(load == 0) bus_write(r(n) + offset * 4, Word, r(d)); } //(ldr,str)b rd,[rn,#offset] @@ -326,10 +251,10 @@ void ARM::thumb_op_move_byte_immediate() { uint1 load = instruction() >> 11; uint5 offset = instruction() >> 6; uint3 n = instruction() >> 3; - uint4 d = instruction() >> 0; + uint3 d = instruction() >> 0; if(load == 1) r(d) = bus_read(r(n) + offset, Byte); - if(load == 0) bus_write(r(d) + offset, Byte, r(n)); + if(load == 0) bus_write(r(n) + offset, Byte, r(d)); } //(ldr,str)h rd,[rn,#offset] @@ -345,21 +270,21 @@ void ARM::thumb_op_move_half_immediate() { uint3 d = instruction() >> 0; if(load == 1) r(d) = bus_read(r(n) + offset * 2, Half); - if(load == 0) bus_write(r(d) + offset * 2, Half, r(n)); + if(load == 0) bus_write(r(n) + offset * 2, Half, r(d)); } -//(ldr,str) rd,[sp,#relative] -//1001 oddd rrrr rrrr +//(ldr,str) rd,[sp,#immediate] +//1001 oddd iiii iiii //o = opcode //d = rd -//r = relative +//i = immediate void ARM::thumb_op_move_stack() { uint1 opcode = instruction() >> 11; uint3 d = instruction() >> 8; - int8 relative = instruction(); + uint8 immediate = instruction(); - if(opcode == 0) bus_write(r(13) + relative * 4, Word, r(d)); - if(opcode == 1) r(d) = bus_read(r(13) + relative * 4, Word); + if(opcode == 0) bus_write(r(13) + immediate * 4, Word, r(d)); + if(opcode == 1) r(d) = bus_read(r(13) + immediate * 4, Word); } //add rd,{pc,sp},#immediate diff --git a/bsnes/processor/arm/instructions-thumb.hpp b/bsnes/processor/arm/instructions-thumb.hpp index 0fe6bab3..64baec35 100755 --- a/bsnes/processor/arm/instructions-thumb.hpp +++ b/bsnes/processor/arm/instructions-thumb.hpp @@ -1,17 +1,7 @@ void thumb_step(); -bool thumb_condition(uint4 condition); void thumb_opcode(uint4 opcode, uint4 d, uint4 s); -uint32 thumb_tst(uint32 modify); -uint32 thumb_add(uint32 source, uint32 modify, bool carry = 0); -uint32 thumb_sub(uint32 source, uint32 modify, bool carry = 1); -uint32 thumb_lsl(uint32 source, uint32 modify); -uint32 thumb_lsr(uint32 source, uint32 modify); -uint32 thumb_asr(uint32 source, uint32 modify); -uint32 thumb_ror(uint32 source, uint32 modify); -uint32 thumb_mul(uint32 source, uint32 modify); - void thumb_op_adjust_register(); void thumb_op_adjust_immediate(); void thumb_op_shift_immediate(); diff --git a/bsnes/processor/arm/registers.cpp b/bsnes/processor/arm/registers.cpp index 08e4d994..e39baff0 100755 --- a/bsnes/processor/arm/registers.cpp +++ b/bsnes/processor/arm/registers.cpp @@ -10,6 +10,9 @@ void ARM::Processor::power() { und.sp = und.lr = 0; pc = 0; + carryout = false; + irqline = false; + cpsr = 0; spsr = nullptr; fiq.spsr = 0; @@ -31,7 +34,7 @@ void ARM::Processor::power() { } void ARM::Processor::setMode(Mode mode) { - cpsr.m = (unsigned)mode; + cpsr.m = 0x10 | (unsigned)mode; if(mode == Mode::FIQ) { r[ 8] = &fiq.r8; @@ -57,4 +60,19 @@ void ARM::Processor::setMode(Mode mode) { } } +void ARM::pipeline_step() { + pipeline.execute = pipeline.decode; + pipeline.decode = pipeline.fetch; + + if(cpsr().t == 0) { + r(15).data += 4; + pipeline.fetch.address = r(15); + pipeline.fetch.instruction = bus_read(r(15), Word); + } else { + r(15).data += 2; + pipeline.fetch.address = r(15); + pipeline.fetch.instruction = bus_read(r(15), Half); + } +} + #endif diff --git a/bsnes/processor/arm/registers.hpp b/bsnes/processor/arm/registers.hpp index 91cf097f..c5f355b8 100755 --- a/bsnes/processor/arm/registers.hpp +++ b/bsnes/processor/arm/registers.hpp @@ -104,6 +104,7 @@ struct Processor { GPR pc; PSR cpsr; bool carryout; + bool irqline; GPR *r[16]; PSR *spsr; @@ -114,7 +115,9 @@ struct Processor { Processor processor; Pipeline pipeline; -bool exception; +bool crash; + +void pipeline_step(); alwaysinline GPR& r(unsigned n) { return *processor.r[n]; } alwaysinline PSR& cpsr() { return processor.cpsr; } @@ -122,3 +125,5 @@ alwaysinline PSR& spsr() { return *processor.spsr; } alwaysinline bool& carryout() { return processor.carryout; } alwaysinline uint32 instruction() { return pipeline.execute.instruction; } alwaysinline Processor::Mode mode() { return (Processor::Mode)processor.cpsr.m; } +alwaysinline bool privilegedmode() const { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; } +alwaysinline bool exceptionmode() const { return privilegedmode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; } diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp index 9744734e..ca12bf63 100755 --- a/bsnes/snes/chip/armdsp/armdsp.cpp +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -27,7 +27,7 @@ void ArmDSP::enter() { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } - if(exception) { + if(crash) { print(disassemble_arm_instruction(pipeline.execute.address), "\n"); print(disassemble_registers(), "\n"); print("Executed: ", instructions, "\n");