diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 385c1c17..efd5d2b9 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -8,7 +8,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "094.31"; + static const string Version = "094.32"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/gba/cpu/cpu.cpp b/gba/cpu/cpu.cpp index e391029c..83df0496 100644 --- a/gba/cpu/cpu.cpp +++ b/gba/cpu/cpu.cpp @@ -3,6 +3,7 @@ namespace GameBoyAdvance { #include "registers.cpp" +#include "prefetch.cpp" #include "mmio.cpp" #include "memory.cpp" #include "dma.cpp" @@ -71,18 +72,40 @@ auto CPU::sync_step(unsigned clocks) -> void { } auto CPU::bus_idle(uint32 addr) -> void { + if(regs.wait.control.prefetch) prefetch_run(); step(1); - return bus.idle(addr); } -auto CPU::bus_read(uint32 addr, uint32 size) -> uint32 { - step(bus.wait(addr, size)); - return bus.read(addr, size); +auto CPU::bus_read(uint32 addr, uint32 size, bool mode) -> uint32 { + if(regs.wait.control.prefetch) { + if((addr & 0x0fffffff) >= 0x08000000 && (addr & 0x0fffffff) <= 0x0dffffff) { + if(auto word = prefetch_read(addr, size)) { + step(1 + (size == Word)); + return *word; + } + } + } + + unsigned wait = bus.wait(addr, size, mode); + unsigned word = bus.read(addr, size); + step(wait); + return word; } -auto CPU::bus_write(uint32 addr, uint32 size, uint32 word) -> void { - step(bus.wait(addr, size)); - return bus.write(addr, size, word); +auto CPU::bus_load(uint32 addr, uint32 size, bool mode) -> uint32 { + if(regs.wait.control.prefetch) prefetch_run(); + return bus_read(addr, size, mode); +} + +auto CPU::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void { + unsigned wait = bus.wait(addr, size, mode); + step(wait); + bus.write(addr, size, word); +} + +auto CPU::bus_store(uint32 addr, uint32 size, bool mode, uint32 word) -> void { + if(regs.wait.control.prefetch) prefetch_run(); + return bus_write(addr, size, mode, word); } auto CPU::keypad_run() -> void { @@ -118,6 +141,7 @@ auto CPU::power() -> void { for(auto& timer : regs.timer) { timer.period = 0; timer.reload = 0; + timer.pending = false; timer.control = 0; } regs.keypad.control = 0; diff --git a/gba/cpu/cpu.hpp b/gba/cpu/cpu.hpp index 88208ef3..75d9dff7 100644 --- a/gba/cpu/cpu.hpp +++ b/gba/cpu/cpu.hpp @@ -1,7 +1,11 @@ struct CPU : Processor::ARM, Thread, MMIO { + using ARM::read; + using ARM::write; + uint8* iwram = nullptr; uint8* ewram = nullptr; #include "registers.hpp" + #include "prefetch.hpp" #include "state.hpp" //cpu.cpp @@ -12,8 +16,10 @@ struct CPU : Processor::ARM, Thread, MMIO { auto sync_step(unsigned clocks) -> void; auto bus_idle(uint32 addr) -> void; - auto bus_read(uint32 addr, uint32 size) -> uint32; - auto bus_write(uint32 addr, uint32 size, uint32 word) -> void; + auto bus_read(uint32 addr, uint32 size, bool mode) -> uint32; + auto bus_load(uint32 addr, uint32 size, bool mode) -> uint32; + auto bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void; + auto bus_store(uint32 addr, uint32 size, bool mode, uint32 word) -> void; auto keypad_run() -> void; auto power() -> void; diff --git a/gba/cpu/dma.cpp b/gba/cpu/dma.cpp index 5bf0205a..c31b30e0 100644 --- a/gba/cpu/dma.cpp +++ b/gba/cpu/dma.cpp @@ -17,21 +17,16 @@ auto CPU::dma_run() -> void { auto CPU::dma_exec(Registers::DMA& dma) -> void { unsigned size = dma.control.size ? Word : Half; + unsigned mode = dma.run.length == dma.length ? Nonsequential : Sequential; unsigned seek = dma.control.size ? 4 : 2; - if(dma.run.length == dma.length) { + if(mode == Nonsequential) { idle(); idle(); - sequential() = false; - } else { - sequential() = true; } - step(bus.wait(dma.run.source, size)); - uint32 word = bus.read(dma.run.source, size); - - step(bus.wait(dma.run.target, size)); - bus.write(dma.run.target, size, word); + uint32 word = bus_read(dma.run.source, size, mode); + bus_write(dma.run.target, size, mode, word); switch(dma.control.sourcemode) { case 0: dma.run.source += seek; break; diff --git a/gba/cpu/mmio.cpp b/gba/cpu/mmio.cpp index 99010ae1..39dce843 100644 --- a/gba/cpu/mmio.cpp +++ b/gba/cpu/mmio.cpp @@ -231,7 +231,7 @@ auto CPU::write(uint32 addr, uint8 byte) -> void { bool enable = timer.control.enable; timer.control = byte; if(enable == 0 && timer.control.enable == 1) { - timer.period = timer.reload; + timer.pending = true; } return; } diff --git a/gba/cpu/prefetch.cpp b/gba/cpu/prefetch.cpp new file mode 100644 index 00000000..3bc48b68 --- /dev/null +++ b/gba/cpu/prefetch.cpp @@ -0,0 +1,17 @@ +auto CPU::prefetch_run() -> void { + if(prefetch.slots == 8) return; + prefetch.slots++; +} + +auto CPU::prefetch_read(uint32 addr, uint32 size) -> maybe { + if(prefetch.slots >= (size == Word ? 2 : 1)) { + prefetch.slots -= (size == Word ? 2 : 1); + return cartridge.read(addr, size); + } + prefetch.slots = 0; + return nothing; +} + +auto CPU::prefetch_take() -> uint16 { + return 0; +} diff --git a/gba/cpu/prefetch.hpp b/gba/cpu/prefetch.hpp new file mode 100644 index 00000000..d4dd18d1 --- /dev/null +++ b/gba/cpu/prefetch.hpp @@ -0,0 +1,13 @@ +struct Prefetch { + struct Slot { + uint32 addr; + uint16 half; + } slot[8]; + + unsigned slots = 0; + uint32 addr = 0; +} prefetch; + +auto prefetch_run() -> void; +auto prefetch_read(uint32 addr, uint32 size) -> maybe; +auto prefetch_take() -> uint16; diff --git a/gba/cpu/registers.hpp b/gba/cpu/registers.hpp index 9e2d13f4..a9d760d9 100644 --- a/gba/cpu/registers.hpp +++ b/gba/cpu/registers.hpp @@ -43,6 +43,7 @@ struct Registers { struct Timer { uint16 period; uint16 reload; + bool pending; TimerControl control; } timer[4]; diff --git a/gba/cpu/serialization.cpp b/gba/cpu/serialization.cpp index fec88d33..0e38944d 100644 --- a/gba/cpu/serialization.cpp +++ b/gba/cpu/serialization.cpp @@ -25,6 +25,7 @@ auto CPU::serialize(serializer& s) -> void { for(auto& timer : regs.timer) { s.integer(timer.period); s.integer(timer.reload); + s.integer(timer.pending); s.integer(timer.control.frequency); s.integer(timer.control.cascade); s.integer(timer.control.irq); diff --git a/gba/cpu/timer.cpp b/gba/cpu/timer.cpp index 251e6828..5b80c350 100644 --- a/gba/cpu/timer.cpp +++ b/gba/cpu/timer.cpp @@ -2,6 +2,15 @@ auto CPU::timer_step(unsigned clocks) -> void { for(unsigned c = 0; c < clocks; c++) { for(unsigned n = 0; n < 4; n++) { auto& timer = regs.timer[n]; + + if(timer.pending) { + timer.pending = false; + if(timer.control.enable == 1) { + timer.period = timer.reload; + } + continue; + } + if(timer.control.enable == false || timer.control.cascade == true) continue; static unsigned mask[] = {0, 63, 255, 1023}; diff --git a/gba/gba.hpp b/gba/gba.hpp index 11d50dc2..6336ea5a 100644 --- a/gba/gba.hpp +++ b/gba/gba.hpp @@ -22,6 +22,7 @@ namespace GameBoyAdvance { namespace GameBoyAdvance { enum : unsigned { Byte = 8, Half = 16, Word = 32 }; + enum : bool { Nonsequential = 0, Sequential = 1 }; struct Thread { ~Thread() { diff --git a/gba/memory/memory.cpp b/gba/memory/memory.cpp index b4963b63..16726c74 100644 --- a/gba/memory/memory.cpp +++ b/gba/memory/memory.cpp @@ -31,13 +31,13 @@ auto Bus::mirror(uint32 addr, uint32 size) -> uint32 { return base; } -auto Bus::wait(uint32 addr, uint32 size) -> unsigned { +auto Bus::wait(uint32 addr, uint32 size, bool mode) -> unsigned { switch(addr & 0x0f000000) { case 0x00000000: return 1; case 0x01000000: return 1; case 0x02000000: return (16 - cpu.regs.memory.control.ewramwait) * (size == Word ? 2 : 1); case 0x03000000: return 1; - case 0x04000000: return 2; + case 0x04000000: return 1; case 0x05000000: return 1 + (size == Word); case 0x06000000: return 1 + (size == Word); case 0x07000000: return 1; @@ -55,9 +55,8 @@ auto Bus::wait(uint32 addr, uint32 size) -> unsigned { case 0x0e000000: s = n; break; } - bool sequential = cpu.sequential(); + bool sequential = (mode == Sequential); if((addr & 0x1fffe) == 0) sequential = false; //N cycle on 16-bit ROM crossing 128KB page boundary (RAM S==N) - if(idleflag) sequential = false; //LDR/LDM interrupts instruction fetches unsigned clocks = sequential ? s : n; if(size == Word) clocks += s; //16-bit bus requires two transfers for words @@ -66,51 +65,42 @@ auto Bus::wait(uint32 addr, uint32 size) -> unsigned { } } -auto Bus::idle(uint32 addr) -> void { - if(addr & 0x08000000) idleflag = true; -} - auto Bus::read(uint32 addr, uint32 size) -> uint32 { - idleflag = false; - if(addr & 0x08000000) return cartridge.read(addr, size); - - switch(addr >> 24 & 7) { - case 0: return bios.read(addr, size); - case 1: return bios.read(addr, size); - case 2: return cpu.ewram_read(addr, size); - case 3: return cpu.iwram_read(addr, size); - case 4: + switch(addr & 0x0f000000) { + case 0x00000000: return bios.read(addr, size); + case 0x01000000: return bios.read(addr, size); + case 0x02000000: return cpu.ewram_read(addr, size); + case 0x03000000: return cpu.iwram_read(addr, size); + case 0x4000000: if((addr & 0xfffffc00) == 0x04000000) return mmio[addr & 0x3ff]->read(addr, size); if((addr & 0xff00ffff) == 0x04000800) return ((MMIO&)cpu).read(0x04000800 | (addr & 3), size); return cpu.pipeline.fetch.instruction; - case 5: return ppu.pram_read(addr, size); - case 6: return ppu.vram_read(addr, size); - case 7: return ppu.oam_read(addr, size); + case 0x05000000: return ppu.pram_read(addr, size); + case 0x06000000: return ppu.vram_read(addr, size); + case 0x07000000: return ppu.oam_read(addr, size); + default: return cartridge.read(addr, size); } } auto Bus::write(uint32 addr, uint32 size, uint32 word) -> void { - idleflag = false; - if(addr & 0x08000000) return cartridge.write(addr, size, word); - - switch(addr >> 24 & 7) { - case 0: return; - case 1: return; - case 2: return cpu.ewram_write(addr, size, word); - case 3: return cpu.iwram_write(addr, size, word); - case 4: + switch(addr & 0x0f000000) { + case 0x00000000: return; + case 0x01000000: return; + case 0x02000000: return cpu.ewram_write(addr, size, word); + case 0x03000000: return cpu.iwram_write(addr, size, word); + case 0x04000000: if((addr & 0xfffffc00) == 0x04000000) return mmio[addr & 0x3ff]->write(addr, size, word); if((addr & 0xff00ffff) == 0x04000800) return ((MMIO&)cpu).write(0x04000800 | (addr & 3), size, word); return; - case 5: return ppu.pram_write(addr, size, word); - case 6: return ppu.vram_write(addr, size, word); - case 7: return ppu.oam_write(addr, size, word); + case 0x05000000: return ppu.pram_write(addr, size, word); + case 0x06000000: return ppu.vram_write(addr, size, word); + case 0x07000000: return ppu.oam_write(addr, size, word); + default: return cartridge.write(addr, size, word); } } auto Bus::power() -> void { - for(unsigned n = 0; n < 0x400; n++) mmio[n] = &unmappedMemory; - idleflag = false; + for(auto n : range(0x400)) mmio[n] = &unmappedMemory; } } diff --git a/gba/memory/memory.hpp b/gba/memory/memory.hpp index ebe80403..f1852cea 100644 --- a/gba/memory/memory.hpp +++ b/gba/memory/memory.hpp @@ -13,8 +13,7 @@ struct MMIO : Memory { struct Bus : Memory { static auto mirror(uint32 addr, uint32 size) -> uint32; - auto wait(uint32 addr, uint32 size) -> unsigned; - auto idle(uint32 addr) -> void; + auto wait(uint32 addr, uint32 size, bool mode) -> unsigned; auto read(uint32 addr, uint32 size) -> uint32; auto write(uint32 addr, uint32 size, uint32 word) -> void; auto power() -> void; @@ -22,7 +21,6 @@ struct Bus : Memory { auto serialize(serializer&) -> void; Memory* mmio[0x400]{nullptr}; - bool idleflag{false}; }; extern Bus bus; diff --git a/gba/memory/serialization.cpp b/gba/memory/serialization.cpp index 06cc5d4e..1987ee2c 100644 --- a/gba/memory/serialization.cpp +++ b/gba/memory/serialization.cpp @@ -1,3 +1,2 @@ auto Bus::serialize(serializer& s) -> void { - s.integer(idleflag); } diff --git a/processor/arm/arm.cpp b/processor/arm/arm.cpp index 5fee5ff0..07e175f9 100644 --- a/processor/arm/arm.cpp +++ b/processor/arm/arm.cpp @@ -29,18 +29,18 @@ auto ARM::exec() -> void { } auto ARM::idle() -> void { + processor.nonsequential = true; bus_idle(r(15)); } -auto ARM::read(uint32 addr, uint32 size) -> uint32 { - uint32 word = bus_read(addr, size); - sequential() = true; - return word; +auto ARM::read(uint32 addr, uint32 size, bool mode) -> uint32 { + if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential; + return bus_read(addr, size, mode); } -auto ARM::load(uint32 addr, uint32 size) -> uint32 { - sequential() = false; - uint32 word = read(addr, size); +auto ARM::load(uint32 addr, uint32 size, bool mode) -> uint32 { + if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential; + uint32 word = bus_load(addr, size, mode); if(size == Half) { word &= 0xffff; word |= word << 16; } if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; } @@ -53,18 +53,18 @@ auto ARM::load(uint32 addr, uint32 size) -> uint32 { return word; } -auto ARM::write(uint32 addr, uint32 size, uint32 word) -> void { - bus_write(addr, size, word); - sequential() = true; +auto ARM::write(uint32 addr, uint32 size, bool mode, uint32 word) -> void { + if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential; + return bus_write(addr, size, mode, word); } -auto ARM::store(uint32 addr, uint32 size, uint32 word) -> void { +auto ARM::store(uint32 addr, uint32 size, bool mode, uint32 word) -> void { if(size == Half) { word &= 0xffff; word |= word << 16; } if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; } - sequential() = false; - write(addr, size, word); - sequential() = false; + if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential; + bus_store(addr, size, mode, word); + processor.nonsequential = true; } auto ARM::vector(uint32 addr, Processor::Mode mode) -> void { diff --git a/processor/arm/arm.hpp b/processor/arm/arm.hpp index 2ccc9466..430a9d39 100644 --- a/processor/arm/arm.hpp +++ b/processor/arm/arm.hpp @@ -9,6 +9,7 @@ namespace Processor { struct ARM { enum : unsigned { Byte = 8, Half = 16, Word = 32 }; + enum : bool { Nonsequential = 0, Sequential = 1 }; #include "registers.hpp" #include "instructions-arm.hpp" @@ -17,17 +18,19 @@ struct ARM { virtual auto step(unsigned clocks) -> void = 0; virtual auto bus_idle(uint32 addr) -> void = 0; - virtual auto bus_read(uint32 addr, uint32 size) -> uint32 = 0; - virtual auto bus_write(uint32 addr, uint32 size, uint32 word) -> void = 0; + virtual auto bus_read(uint32 addr, uint32 size, bool mode) -> uint32 = 0; + virtual auto bus_load(uint32 addr, uint32 size, bool mode) -> uint32 = 0; + virtual auto bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void = 0; + virtual auto bus_store(uint32 addr, uint32 size, bool mode, uint32 word) -> void = 0; //arm.cpp auto power() -> void; auto exec() -> void; auto idle() -> void; - auto read(uint32 addr, uint32 size) -> uint32; - auto load(uint32 addr, uint32 size) -> uint32; - auto write(uint32 addr, uint32 size, uint32 word) -> void; - auto store(uint32 addr, uint32 size, uint32 word) -> void; + auto read(uint32 addr, uint32 size, bool mode) -> uint32; + auto load(uint32 addr, uint32 size, bool mode) -> uint32; + auto write(uint32 addr, uint32 size, bool mode, uint32 word) -> void; + auto store(uint32 addr, uint32 size, bool mode, uint32 word) -> void; auto vector(uint32 addr, Processor::Mode mode) -> void; //algorithms.cpp diff --git a/processor/arm/disassembler.cpp b/processor/arm/disassembler.cpp index e00de0ca..a8ac573e 100644 --- a/processor/arm/disassembler.cpp +++ b/processor/arm/disassembler.cpp @@ -32,7 +32,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string { string output{hex<8>(pc), " "}; - uint32 instruction = read(pc & ~3, Word); + uint32 instruction = read(pc & ~3, Word, Nonsequential); output.append(hex<8>(instruction), " "); //multiply() @@ -134,7 +134,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string { if(pre == 1) output.append("]"); if(pre == 0 || writeback == 1) output.append("!"); - if(rn == 15) output.append(" =0x", hex<4>(read(pc + 8 + (up ? +immediate : -immediate), Half))); + if(rn == 15) output.append(" =0x", hex<4>(read(pc + 8 + (up ? +immediate : -immediate), Half, Nonsequential))); return output; } @@ -184,8 +184,8 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string { if(pre == 1) output.append("]"); if(pre == 0 || writeback == 1) output.append("!"); - if(rn == 15 && half == 1) output.append(" =0x", hex<4>(read(pc + 8 + (up ? +immediate : -immediate), Half))); - if(rn == 15 && half == 0) output.append(" =0x", hex<2>(read(pc + 8 + (up ? +immediate : -immediate), Byte))); + if(rn == 15 && half == 1) output.append(" =0x", hex<4>(read(pc + 8 + (up ? +immediate : -immediate), Half, Nonsequential))); + if(rn == 15 && half == 0) output.append(" =0x", hex<2>(read(pc + 8 + (up ? +immediate : -immediate), Byte, Nonsequential))); return output; } @@ -359,7 +359,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string { if(pre == 1) output.append("]"); if(pre == 0 || writeback == 1) output.append("!"); - if(rn == 15) output.append(" =0x", hex<8>(read(pc + 8 + (up ? +immediate : -immediate), byte ? Byte : Word))); + if(rn == 15) output.append(" =0x", hex<8>(read(pc + 8 + (up ? +immediate : -immediate), byte ? Byte : Word, Nonsequential))); return output; } @@ -457,7 +457,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string { string output{hex<8>(pc), " "}; - uint16 instruction = read(pc & ~1, Half); + uint16 instruction = read(pc & ~1, Half, Nonsequential); output.append(hex<4>(instruction), " "); //adjust_register() @@ -571,7 +571,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string { unsigned rm = ((pc + 4) & ~3) + displacement * 4; output.append("ldr ", registers[rd], ",[pc,#0x", hex<3>(rm), "]"); - output.append(" =0x", hex<8>(read(rm, Word))); + output.append(" =0x", hex<8>(read(rm, Word, Nonsequential))); return output; } @@ -740,7 +740,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string { //bl address if((instruction & 0xf800) == 0xf000) { uint11 offsethi = instruction; - instruction = read((pc & ~1) + 2, Half); + instruction = read((pc & ~1) + 2, Half, Nonsequential); uint11 offsetlo = instruction; int22 displacement = (offsethi << 11) | (offsetlo << 0); diff --git a/processor/arm/instructions-arm.cpp b/processor/arm/instructions-arm.cpp index 3b5e995b..21a5de5a 100644 --- a/processor/arm/instructions-arm.cpp +++ b/processor/arm/instructions-arm.cpp @@ -27,7 +27,7 @@ auto ARM::arm_opcode(uint32 rm) { case 15: r(d) = bit(~rm); break; //MVN } - if(exceptionmode() && d == 15 && save) { + if(exceptionMode() && d == 15 && save) { cpsr() = spsr(); processor.setMode((Processor::Mode)cpsr().m); } @@ -45,7 +45,7 @@ auto ARM::arm_move_to_status(uint32 rm) { PSR &psr = source ? spsr() : cpsr(); if(field & 1) { - if(source == 1 || privilegedmode()) { + if(source == 1 || privilegedMode()) { psr.i = rm & 0x00000080; psr.f = rm & 0x00000040; psr.t = rm & 0x00000020; @@ -137,8 +137,8 @@ auto ARM::arm_op_memory_swap() { uint4 d = instruction() >> 12; uint4 m = instruction(); - uint32 word = load(r(n), byte ? Byte : Word); - store(r(n), byte ? Byte : Word, r(m)); + uint32 word = load(r(n), byte ? Byte : Word, Nonsequential); + store(r(n), byte ? Byte : Word, Nonsequential, r(m)); r(d) = word; } @@ -166,8 +166,8 @@ auto ARM::arm_op_move_half_register() { uint32 rm = r(m); if(pre == 1) rn = up ? rn + rm : rn - rm; - if(l == 1) r(d) = load(rn, Half); - if(l == 0) store(rn, Half, r(d)); + if(l == 1) r(d) = load(rn, Half, Nonsequential); + if(l == 0) store(rn, Half, Nonsequential, r(d)); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; @@ -199,8 +199,8 @@ auto ARM::arm_op_move_half_immediate() { uint8 immediate = (ih << 4) + (il << 0); if(pre == 1) rn = up ? rn + immediate : rn - immediate; - if(l == 1) r(d) = load(rn, Half); - if(l == 0) store(rn, Half, r(d)); + if(l == 1) r(d) = load(rn, Half, Nonsequential); + if(l == 0) store(rn, Half, Nonsequential, r(d)); if(pre == 0) rn = up ? rn + immediate : rn - immediate; if(pre == 0 || writeback == 1) r(n) = rn; @@ -230,7 +230,7 @@ auto ARM::arm_op_load_register() { uint32 rm = r(m); if(pre == 1) rn = up ? rn + rm : rn - rm; - uint32 word = load(rn, half ? Half : Byte); + uint32 word = load(rn, half ? Half : Byte, Nonsequential); r(d) = half ? (int16)word : (int8)word; if(pre == 0) rn = up ? rn + rm : rn - rm; @@ -263,7 +263,7 @@ auto ARM::arm_op_load_immediate() { uint8 immediate = (ih << 4) + (il << 0); if(pre == 1) rn = up ? rn + immediate : rn - immediate; - uint32 word = load(rn, half ? Half : Byte); + uint32 word = load(rn, half ? Half : Byte, Nonsequential); r(d) = half ? (int16)word : (int8)word; if(pre == 0) rn = up ? rn + immediate : rn - immediate; @@ -437,8 +437,8 @@ auto ARM::arm_op_move_immediate_offset() { auto& rd = r(d); if(pre == 1) rn = up ? rn + rm : rn - rm; - if(l == 1) rd = load(rn, byte ? Byte : Word); - if(l == 0) store(rn, byte ? Byte : Word, rd); + if(l == 1) rd = load(rn, byte ? Byte : Word, Nonsequential); + if(l == 0) store(rn, byte ? Byte : Word, Nonsequential, rd); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; @@ -482,8 +482,8 @@ auto ARM::arm_op_move_register_offset() { if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm); if(pre == 1) rn = up ? rn + rm : rn - rm; - if(l == 1) rd = load(rn, byte ? Byte : Word); - if(l == 0) store(rn, byte ? Byte : Word, rd); + if(l == 1) rd = load(rn, byte ? Byte : Word, Nonsequential); + if(l == 0) store(rn, byte ? Byte : Word, Nonsequential, rd); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; @@ -522,10 +522,9 @@ auto ARM::arm_op_move_multiple() { if(usr) processor.setMode(Processor::Mode::USR); for(unsigned m = 0; m < 16; m++) { - sequential() = false; if(list & 1 << m) { - if(l == 1) r(m) = read(rn, Word); - if(l == 0) write(rn, Word, r(m)); + if(l == 1) r(m) = read(rn, Word, Nonsequential); + if(l == 0) write(rn, Word, Nonsequential, r(m)); rn += 4; } } @@ -540,6 +539,8 @@ auto ARM::arm_op_move_multiple() { processor.setMode((Processor::Mode)cpsr().m); } } + } else { + processor.nonsequential = true; } if(writeback) { diff --git a/processor/arm/instructions-thumb.cpp b/processor/arm/instructions-thumb.cpp index 78c58e8d..a8587389 100644 --- a/processor/arm/instructions-thumb.cpp +++ b/processor/arm/instructions-thumb.cpp @@ -145,7 +145,7 @@ auto ARM::thumb_op_load_literal() { uint8 displacement = instruction(); unsigned rm = (r(15) & ~3) + displacement * 4; - r(d) = load(rm, Word); + r(d) = load(rm, Word, Nonsequential); } //(ld(r,s),str){b,h} rd,[rn,rm] @@ -161,14 +161,14 @@ auto ARM::thumb_op_move_register_offset() { uint3 d = instruction() >> 0; switch(opcode) { - case 0: store(r(n) + r(m), Word, r(d)); break; //STR - case 1: store(r(n) + r(m), Half, r(d)); break; //STRH - case 2: store(r(n) + r(m), Byte, r(d)); break; //STRB - case 3: r(d) = (int8)load(r(n) + r(m), Byte); break; //LDSB - case 4: r(d) = load(r(n) + r(m), Word); break; //LDR - case 5: r(d) = load(r(n) + r(m), Half); break; //LDRH - case 6: r(d) = load(r(n) + r(m), Byte); break; //LDRB - case 7: r(d) = (int16)load(r(n) + r(m), Half); break; //LDSH + case 0: store(r(n) + r(m), Word, Nonsequential, r(d)); break; //STR + case 1: store(r(n) + r(m), Half, Nonsequential, r(d)); break; //STRH + case 2: store(r(n) + r(m), Byte, Nonsequential, r(d)); break; //STRB + case 3: r(d) = (int8)load(r(n) + r(m), Byte, Nonsequential); break; //LDSB + case 4: r(d) = load(r(n) + r(m), Word, Nonsequential); break; //LDR + case 5: r(d) = load(r(n) + r(m), Half, Nonsequential); break; //LDRH + case 6: r(d) = load(r(n) + r(m), Byte, Nonsequential); break; //LDRB + case 7: r(d) = (int16)load(r(n) + r(m), Half, Nonsequential); break; //LDSH } } @@ -184,8 +184,8 @@ auto ARM::thumb_op_move_word_immediate() { uint3 n = instruction() >> 3; uint3 d = instruction() >> 0; - if(l == 1) r(d) = load(r(n) + offset * 4, Word); - if(l == 0) store(r(n) + offset * 4, Word, r(d)); + if(l == 1) r(d) = load(r(n) + offset * 4, Word, Nonsequential); + if(l == 0) store(r(n) + offset * 4, Word, Nonsequential, r(d)); } //(ldr,str)b rd,[rn,#offset] @@ -200,8 +200,8 @@ auto ARM::thumb_op_move_byte_immediate() { uint3 n = instruction() >> 3; uint3 d = instruction() >> 0; - if(l == 1) r(d) = load(r(n) + offset, Byte); - if(l == 0) store(r(n) + offset, Byte, r(d)); + if(l == 1) r(d) = load(r(n) + offset, Byte, Nonsequential); + if(l == 0) store(r(n) + offset, Byte, Nonsequential, r(d)); } //(ldr,str)h rd,[rn,#offset] @@ -216,8 +216,8 @@ auto ARM::thumb_op_move_half_immediate() { uint3 n = instruction() >> 3; uint3 d = instruction() >> 0; - if(l == 1) r(d) = load(r(n) + offset * 2, Half); - if(l == 0) store(r(n) + offset * 2, Half, r(d)); + if(l == 1) r(d) = load(r(n) + offset * 2, Half, Nonsequential); + if(l == 0) store(r(n) + offset * 2, Half, Nonsequential, r(d)); } //(ldr,str) rd,[sp,#immediate] @@ -230,8 +230,8 @@ auto ARM::thumb_op_move_stack() { uint3 d = instruction() >> 8; uint8 immediate = instruction(); - if(l == 1) r(d) = load(r(13) + immediate * 4, Word); - if(l == 0) store(r(13) + immediate * 4, Word, r(d)); + if(l == 1) r(d) = load(r(13) + immediate * 4, Word, Nonsequential); + if(l == 0) store(r(13) + immediate * 4, Word, Nonsequential, r(d)); } //add rd,{pc,sp},#immediate @@ -275,19 +275,18 @@ auto ARM::thumb_op_stack_multiple() { if(l == 1) sp = r(13); if(l == 0) sp = r(13) - (bit::count(list) + branch) * 4; - sequential() = false; for(unsigned m = 0; m < 8; m++) { if(list & 1 << m) { - if(l == 1) r(m) = read(sp, Word); //POP - if(l == 0) write(sp, Word, r(m)); //PUSH + if(l == 1) r(m) = read(sp, Word, Nonsequential); //POP + if(l == 0) write(sp, Word, Nonsequential, r(m)); //PUSH sp += 4; } } if(branch) { //note: ARMv5+ POP sets cpsr().t - if(l == 1) r(15) = read(sp, Word); //POP - if(l == 0) write(sp, Word, r(14)); //PUSH + if(l == 1) r(15) = read(sp, Word, Nonsequential); //POP + if(l == 0) write(sp, Word, Nonsequential, r(14)); //PUSH sp += 4; } @@ -307,11 +306,10 @@ auto ARM::thumb_op_move_multiple() { uint8 list = instruction(); uint32 rn = r(n); //rn may be in register list; so we must cache it - sequential() = false; for(unsigned m = 0; m < 8; m++) { if(list & 1 << m) { - if(l == 1) r(m) = read(rn, Word); //LDMIA - if(l == 0) write(rn, Word, r(m)); //STMIA + if(l == 1) r(m) = read(rn, Word, Nonsequential); //LDMIA + if(l == 0) write(rn, Word, Nonsequential, r(m)); //STMIA rn += 4; } } diff --git a/processor/arm/registers.cpp b/processor/arm/registers.cpp index bb924bae..efcf1621 100644 --- a/processor/arm/registers.cpp +++ b/processor/arm/registers.cpp @@ -11,7 +11,7 @@ auto ARM::Processor::power() -> void { pc = 0; carryout = false; - sequential = false; + nonsequential = false; irqline = false; cpsr = 0; @@ -68,11 +68,11 @@ auto ARM::pipeline_step() -> void { if(cpsr().t == 0) { r(15).data += 4; pipeline.fetch.address = r(15) & ~3; - pipeline.fetch.instruction = read(pipeline.fetch.address, Word); + pipeline.fetch.instruction = read(pipeline.fetch.address, Word, Sequential); } else { r(15).data += 2; pipeline.fetch.address = r(15) & ~1; - pipeline.fetch.instruction = read(pipeline.fetch.address, Half); + pipeline.fetch.instruction = read(pipeline.fetch.address, Half, Sequential); } } diff --git a/processor/arm/registers.hpp b/processor/arm/registers.hpp index e58d690d..115268d9 100644 --- a/processor/arm/registers.hpp +++ b/processor/arm/registers.hpp @@ -14,8 +14,8 @@ struct GPR { inline auto operator<<=(uint32 n) { return operator=(data << n); } inline auto operator>>=(uint32 n) { return operator=(data >> n); } - uint32 data{0}; - function modify; + uint32 data = 0; + function void> modify; }; struct PSR { @@ -38,22 +38,22 @@ struct PSR { auto serialize(serializer&) -> void; - bool n{false}; //negative - bool z{false}; //zero - bool c{false}; //carry - bool v{false}; //overflow - bool i{false}; //irq - bool f{false}; //fiq - bool t{false}; //thumb - unsigned m{0}; //mode + bool n = false; //negative + bool z = false; //zero + bool c = false; //carry + bool v = false; //overflow + bool i = false; //irq + bool f = false; //fiq + bool t = false; //thumb + unsigned m = 0; //mode }; struct Pipeline { - bool reload{false}; + bool reload = false; struct Instruction { - uint32 address{0}; - uint32 instruction{0}; + uint32 address = 0; + uint32 instruction = 0; }; Instruction execute; @@ -105,12 +105,12 @@ struct Processor { GPR pc; PSR cpsr; - bool carryout{false}; - bool sequential{false}; - bool irqline{false}; + bool carryout = false; + bool nonsequential = false; + bool irqline = false; - GPR* r[16]; - PSR* spsr; + GPR* r[16] = {nullptr}; + PSR* spsr = nullptr; auto power() -> void; auto setMode(Mode) -> void; @@ -118,7 +118,7 @@ struct Processor { Processor processor; Pipeline pipeline; -bool crash{false}; +bool crash = false; auto pipeline_step() -> void; @@ -126,8 +126,7 @@ alwaysinline auto r(unsigned n) -> GPR& { return *processor.r[n]; } alwaysinline auto cpsr() -> PSR& { return processor.cpsr; } alwaysinline auto spsr() -> PSR& { return *processor.spsr; } alwaysinline auto carryout() -> bool& { return processor.carryout; } -alwaysinline auto sequential() -> bool& { return processor.sequential; } alwaysinline auto instruction() -> uint32 { return pipeline.execute.instruction; } alwaysinline auto mode() -> Processor::Mode { return (Processor::Mode)processor.cpsr.m; } -alwaysinline auto privilegedmode() const -> bool { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; } -alwaysinline auto exceptionmode() const -> bool { return privilegedmode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; } +alwaysinline auto privilegedMode() const -> bool { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; } +alwaysinline auto exceptionMode() const -> bool { return privilegedMode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; } diff --git a/processor/arm/serialization.cpp b/processor/arm/serialization.cpp index d45123f7..cbf4ab6c 100644 --- a/processor/arm/serialization.cpp +++ b/processor/arm/serialization.cpp @@ -55,7 +55,7 @@ auto ARM::serialize(serializer& s) -> void { s.integer(processor.pc.data); processor.cpsr.serialize(s); s.integer(processor.carryout); - s.integer(processor.sequential); + s.integer(processor.nonsequential); s.integer(processor.irqline); s.integer(pipeline.reload); diff --git a/processor/arm/step.cpp b/processor/arm/step.cpp index 1d6fe8e6..c070f515 100644 --- a/processor/arm/step.cpp +++ b/processor/arm/step.cpp @@ -3,9 +3,8 @@ auto ARM::arm_step() -> void { pipeline.reload = false; r(15).data &= ~3; - sequential() = false; pipeline.fetch.address = r(15) & ~3; - pipeline.fetch.instruction = read(pipeline.fetch.address, Word); + pipeline.fetch.instruction = read(pipeline.fetch.address, Word, Nonsequential); pipeline_step(); } @@ -61,9 +60,8 @@ auto ARM::thumb_step() -> void { pipeline.reload = false; r(15).data &= ~1; - sequential() = false; pipeline.fetch.address = r(15) & ~1; - pipeline.fetch.instruction = read(pipeline.fetch.address, Half); + pipeline.fetch.instruction = read(pipeline.fetch.address, Half, Nonsequential); pipeline_step(); } diff --git a/sfc/chip/armdsp/armdsp.hpp b/sfc/chip/armdsp/armdsp.hpp index 3fdd686e..dca0ef44 100644 --- a/sfc/chip/armdsp/armdsp.hpp +++ b/sfc/chip/armdsp/armdsp.hpp @@ -12,8 +12,10 @@ struct ArmDSP : Processor::ARM, Coprocessor { void step(unsigned clocks); void bus_idle(uint32 addr); - uint32 bus_read(uint32 addr, uint32 size); - void bus_write(uint32 addr, uint32 size, uint32 word); + uint32 bus_read(uint32 addr, uint32 size, bool mode); + uint32 bus_load(uint32 addr, uint32 size, bool mode); + void bus_write(uint32 addr, uint32 size, bool mode, uint32 word); + void bus_store(uint32 addr, uint32 size, bool mode, uint32 word); uint8 mmio_read(unsigned addr); void mmio_write(unsigned addr, uint8 data); diff --git a/sfc/chip/armdsp/memory.cpp b/sfc/chip/armdsp/memory.cpp index 5d1ccb7c..6e6a6969 100644 --- a/sfc/chip/armdsp/memory.cpp +++ b/sfc/chip/armdsp/memory.cpp @@ -4,7 +4,7 @@ void ArmDSP::bus_idle(uint32 addr) { step(1); } -uint32 ArmDSP::bus_read(uint32 addr, uint32 size) { +uint32 ArmDSP::bus_read(uint32 addr, uint32 size, bool mode) { step(1); static auto memory = [&](const uint8 *memory, uint32 addr, uint32 size) -> uint32 { @@ -44,7 +44,11 @@ uint32 ArmDSP::bus_read(uint32 addr, uint32 size) { return 0u; } -void ArmDSP::bus_write(uint32 addr, uint32 size, uint32 word) { +uint32 ArmDSP::bus_load(uint32 addr, uint32 size, bool mode) { + return bus_read(addr, size, mode); +} + +void ArmDSP::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) { step(1); static auto memory = [](uint8 *memory, uint32 addr, uint32 size, uint32 word) { @@ -98,4 +102,8 @@ void ArmDSP::bus_write(uint32 addr, uint32 size, uint32 word) { } } +void ArmDSP::bus_store(uint32 addr, uint32 size, bool mode, uint32 word) { + return bus_write(addr, size, mode, word); +} + #endif diff --git a/target-tomoko/presentation/presentation.cpp b/target-tomoko/presentation/presentation.cpp index 10df5f48..b3fb99bd 100644 --- a/target-tomoko/presentation/presentation.cpp +++ b/target-tomoko/presentation/presentation.cpp @@ -106,6 +106,7 @@ Presentation::Presentation() { setResizable(false); setBackgroundColor({0, 0, 0}); resizeViewport(); + setCentered(); } auto Presentation::updateEmulator() -> void { @@ -161,7 +162,6 @@ auto Presentation::resizeViewport() -> void { setSize({windowWidth, windowHeight}); viewport.setGeometry({(windowWidth - width) / 2, (windowHeight - height) / 2, width, height}); - setPlacement(0.5, 0.5); } else { auto desktop = Desktop::size();