From c2d0ed4ca8e24c560188805a5e4d02eaddc4316e Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 10 Sep 2018 12:11:19 +1000 Subject: [PATCH] Update to v106r62 release. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit byuu says: Changelog: - sfc/cx4: added missing instructions [info from Overload] - sfc/cx4: added instruction cache emulation [info from ikari] - sfc/sa1: don't let CPU access SA1-only I/O registers, and vice versa - sfc/sa1: fixed IRQs that were broken from the recent WIP - sfc/sa1: significantly improved bus conflict emulation - all tests match hardware now, other than HDMA ROM↔ROM, which is 0.5 - 0.8% too fast - sfc/cpu: fixed a bug with DMA→CPU alignment timing - sfc/cpu: removed the DMA pipe; performs writes on the same cycles as reads [info from nocash] - sfc/memory: fix a crashing bug due to not clearing Memory size field [hex_usr] - bsnes/gb: use .rtc for real-time clock file extensions on the Game Boy [hex_usr] - ruby/cgl: compilation fix [Sintendo] Now let's see if I can accept being off by ~0.65% on one of twelve SA1 timing tests for the time being and prioritize much more important things or not. --- higan/emulator/emulator.hpp | 2 +- higan/processor/hg51b/hg51b.cpp | 44 +- higan/processor/hg51b/hg51b.hpp | 126 +++- higan/processor/hg51b/instruction.cpp | 639 ++++++++++++++++++++ higan/processor/hg51b/instructions.cpp | 657 ++++++++++----------- higan/processor/hg51b/registers.cpp | 48 +- higan/processor/hg51b/serialization.cpp | 17 +- higan/processor/wdc65816/serialization.cpp | 1 - higan/processor/wdc65816/wdc65816.cpp | 2 +- higan/processor/wdc65816/wdc65816.hpp | 1 - higan/sfc/cartridge/load.cpp | 2 +- higan/sfc/coprocessor/sa1/bwram.cpp | 1 - higan/sfc/coprocessor/sa1/dma.cpp | 19 +- higan/sfc/coprocessor/sa1/io.cpp | 232 ++++---- higan/sfc/coprocessor/sa1/iram.cpp | 3 +- higan/sfc/coprocessor/sa1/memory.cpp | 180 +++--- higan/sfc/coprocessor/sa1/rom.cpp | 7 +- higan/sfc/coprocessor/sa1/sa1.cpp | 27 +- higan/sfc/coprocessor/sa1/sa1.hpp | 18 +- higan/sfc/cpu/cpu.cpp | 4 +- higan/sfc/cpu/cpu.hpp | 27 +- higan/sfc/cpu/dma.cpp | 77 +-- higan/sfc/cpu/memory.cpp | 15 +- higan/sfc/cpu/serialization.cpp | 11 +- higan/sfc/cpu/timing.cpp | 54 +- higan/sfc/memory/protectable.hpp | 1 + higan/sfc/memory/readable.hpp | 1 + higan/sfc/memory/writable.hpp | 1 + higan/target-bsnes/program/game-rom.cpp | 2 +- nall/path.hpp | 6 + nall/platform.hpp | 2 + nall/windows/guard.hpp | 2 + ruby/ruby.cpp | 6 +- ruby/video/cgl.cpp | 2 +- 34 files changed, 1446 insertions(+), 791 deletions(-) create mode 100644 higan/processor/hg51b/instruction.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 29ff2cab..6f416c38 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -28,7 +28,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.61"; + static const string Version = "106.62"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/processor/hg51b/hg51b.cpp b/higan/processor/hg51b/hg51b.cpp index 7e1f5091..37ddde5b 100644 --- a/higan/processor/hg51b/hg51b.cpp +++ b/higan/processor/hg51b/hg51b.cpp @@ -4,6 +4,7 @@ namespace Processor { #include "registers.cpp" +#include "instruction.cpp" #include "instructions.cpp" #include "serialization.cpp" @@ -24,7 +25,7 @@ auto HG51B::wait(uint24 address) -> uint { auto HG51B::main() -> void { if(io.lock) return step(1); if(io.suspend.enable) return suspend(); - if(io.cache.enable) return cache(); + if(io.cache.enable) return cache(), void(); if(io.dma.enable) return dma(); if(io.halt) return step(1); return execute(); @@ -37,55 +38,56 @@ auto HG51B::step(uint clocks) -> void { } else { io.bus.enable = 0; io.bus.pending = 0; - if(io.bus.reading) io.bus.reading = 0, r.busData = read(io.bus.address); - if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.busData); + if(io.bus.reading) io.bus.reading = 0, r.mdr = read(io.bus.address); + if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.mdr); } } } auto HG51B::execute() -> void { - uint24 address = io.cache.base + r.pb * 512; - if(io.cache.address[io.cache.page] != address) { - io.cache.page ^= 1; - if(io.cache.address[io.cache.page] != address) { - if(io.cache.lock[io.cache.page]) { - io.cache.page ^= 1; - if(io.cache.lock[io.cache.page]) return halt(); - } - cache(); - } - } - - opcode = programRAM[io.cache.page][r.pc]; + if(!cache()) return halt(); + auto opcode = programRAM[io.cache.page][r.pc]; advance(); - step(1); - instruction(); + instructionTable[opcode](); } auto HG51B::advance() -> void { if(++r.pc == 0) { if(io.cache.page == 1) return halt(); io.cache.page = 1; + if(io.cache.lock[io.cache.page]) return halt(); r.pb = r.p; + if(!cache()) return halt(); } } auto HG51B::suspend() -> void { if(!io.suspend.duration) return step(1); //indefinite step(io.suspend.duration); - io.suspend.enable = 0; io.suspend.duration = 0; + io.suspend.enable = 0; } -auto HG51B::cache() -> void { +auto HG51B::cache() -> bool { uint24 address = io.cache.base + r.pb * 512; + + //try to use the current page ... + if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true; + //if it's not valid, try to use the other page ... + io.cache.page ^= 1; + if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true; + //if it's not valid, try to load into the other page ... + if(io.cache.lock[io.cache.page]) io.cache.page ^= 1; + //if it's locked, try to load into the first page ... + if(io.cache.lock[io.cache.page]) return io.cache.enable = 0, false; + io.cache.address[io.cache.page] = address; for(uint offset : range(256)) { step(wait(address)); programRAM[io.cache.page][offset].byte(0) = read(address++); step(wait(address)); programRAM[io.cache.page][offset].byte(1) = read(address++); } - io.cache.enable = 0; + return io.cache.enable = 0, true; } auto HG51B::dma() -> void { diff --git a/higan/processor/hg51b/hg51b.hpp b/higan/processor/hg51b/hg51b.hpp index b0b3fb9c..6065b6e5 100644 --- a/higan/processor/hg51b/hg51b.hpp +++ b/higan/processor/hg51b/hg51b.hpp @@ -1,10 +1,14 @@ #pragma once -//Hitachi HG51B169 (HG51BS family/derivative?) +//Hitachi HG51B S169 namespace Processor { struct HG51B { + //instruction.cpp + HG51B(); + + //hg51b.cpp virtual auto step(uint clocks) -> void; virtual auto isROM(uint24 address) -> bool = 0; virtual auto isRAM(uint24 address) -> bool = 0; @@ -17,49 +21,115 @@ struct HG51B { auto execute() -> void; auto advance() -> void; auto suspend() -> void; - auto cache() -> void; + auto cache() -> bool; auto dma() -> void; auto running() const -> bool; auto busy() const -> bool; auto power() -> void; - auto serialize(serializer&) -> void; - uint16 programRAM[2][256]; - uint24 dataROM[1024]; - uint8 dataRAM[3072]; - -protected: + //instructions.cpp auto push() -> void; auto pull() -> void; - auto sa() -> uint; - auto ri() -> uint; - auto np() -> void; - auto instruction() -> void; + + auto algorithmADD(uint24 x, uint24 y) -> uint24; + auto algorithmAND(uint24 x, uint24 y) -> uint24; + auto algorithmASR(uint24 a, uint5 s) -> uint24; + auto algorithmMUL(int24 x, int24 y) -> uint48; + auto algorithmOR(uint24 x, uint24 y) -> uint24; + auto algorithmROR(uint24 a, uint5 s) -> uint24; + auto algorithmSHL(uint24 a, uint5 s) -> uint24; + auto algorithmSHR(uint24 a, uint5 s) -> uint24; + auto algorithmSUB(uint24 x, uint24 y) -> uint24; + auto algorithmSX(uint24 x) -> uint24; + auto algorithmXNOR(uint24 x, uint24 y) -> uint24; + auto algorithmXOR(uint24 x, uint24 y) -> uint24; + + auto instructionADD(uint7 reg, uint5 shift) -> void; + auto instructionADD(uint8 imm, uint5 shift) -> void; + auto instructionAND(uint7 reg, uint5 shift) -> void; + auto instructionAND(uint8 imm, uint5 shift) -> void; + auto instructionASR(uint7 reg) -> void; + auto instructionASR(uint5 imm) -> void; + auto instructionCLEAR() -> void; + auto instructionCMP(uint7 reg, uint5 shift) -> void; + auto instructionCMP(uint8 imm, uint5 shift) -> void; + auto instructionCMPR(uint7 reg, uint5 shift) -> void; + auto instructionCMPR(uint8 imm, uint5 shift) -> void; + auto instructionHALT() -> void; + auto instructionINC(uint24& reg) -> void; + auto instructionJMP(uint8 data, uint1 far, const uint1& take) -> void; + auto instructionJSR(uint8 data, uint1 far, const uint1& take) -> void; + auto instructionLD(uint24& out, uint7 reg) -> void; + auto instructionLD(uint15& out, uint4 reg) -> void; + auto instructionLD(uint24& out, uint8 imm) -> void; + auto instructionLD(uint15& out, uint8 imm) -> void; + auto instructionLDL(uint15& out, uint8 imm) -> void; + auto instructionLDH(uint15& out, uint7 imm) -> void; + auto instructionMUL(uint7 reg) -> void; + auto instructionMUL(uint8 imm) -> void; + auto instructionNOP() -> void; + auto instructionOR(uint7 reg, uint5 shift) -> void; + auto instructionOR(uint8 imm, uint5 shift) -> void; + auto instructionRDRAM(uint2 byte, uint24& a) -> void; + auto instructionRDRAM(uint2 byte, uint8 imm) -> void; + auto instructionRDROM(uint24& reg) -> void; + auto instructionRDROM(uint10 imm) -> void; + auto instructionROR(uint7 reg) -> void; + auto instructionROR(uint5 imm) -> void; + auto instructionRTS() -> void; + auto instructionSHL(uint7 reg) -> void; + auto instructionSHL(uint5 imm) -> void; + auto instructionSHR(uint7 reg) -> void; + auto instructionSHR(uint5 imm) -> void; + auto instructionSKIP(uint1 take, const uint1& flag) -> void; + auto instructionST(uint7 reg, uint24& in) -> void; + auto instructionSUB(uint7 reg, uint5 shift) -> void; + auto instructionSUB(uint8 imm, uint5 shift) -> void; + auto instructionSUBR(uint7 reg, uint5 shift) -> void; + auto instructionSUBR(uint8 imm, uint5 shift) -> void; + auto instructionSWAP(uint24& a, uint4 reg) -> void; + auto instructionSXB() -> void; + auto instructionSXW() -> void; + auto instructionWAIT() -> void; + auto instructionWRRAM(uint2 byte, uint24& a) -> void; + auto instructionWRRAM(uint2 byte, uint8 imm) -> void; + auto instructionXNOR(uint7 reg, uint5 shift) -> void; + auto instructionXNOR(uint8 imm, uint5 shift) -> void; + auto instructionXOR(uint7 reg, uint5 shift) -> void; + auto instructionXOR(uint8 imm, uint5 shift) -> void; + + //serialization.cpp + auto serialize(serializer&) -> void; + + uint16 programRAM[2][256]; //instruction cache + uint24 dataROM[1024]; + uint8 dataRAM[3072]; //registers.cpp auto readRegister(uint7 address) -> uint24; auto writeRegister(uint7 address, uint24 data) -> void; +protected: struct Registers { - uint16 p; - uint16 pb; //program bank + uint15 pb; //program bank uint8 pc; //program counter boolean n; //negative boolean z; //zero boolean c; //carry + boolean v; //overflow boolean i; //interrupt - uint24 a; //accumulator - uint24 acch; - uint24 accl; - uint24 busData; - uint24 romData; - uint24 ramData; - uint24 busAddress; - uint24 ramAddress; - uint24 gpr[16]; + uint24 a; //accumulator + uint15 p; //page register + uint48 mul; //multiplier + uint24 mdr; //bus memory data register + uint24 rom; //data ROM data buffer + uint24 ram; //data RAM data buffer + uint24 mar; //bus memory address register + uint24 dpr; //data RAM address pointer + uint24 gpr[16]; //general purpose registers } r; struct IO { @@ -83,9 +153,9 @@ protected: uint1 enable; uint1 page; uint1 lock[2]; - uint24 address[2]; - uint24 base; - uint16 pb; + uint24 address[2]; //cache address is in bytes; so 24-bit + uint24 base; //base address is also in bytes + uint15 pb; uint8 pc; } cache; @@ -105,8 +175,8 @@ protected: } bus; } io; - uint24 stack[8]; - uint16 opcode; + uint23 stack[8]; + function instructionTable[65536]; }; } diff --git a/higan/processor/hg51b/instruction.cpp b/higan/processor/hg51b/instruction.cpp new file mode 100644 index 00000000..f3e51d02 --- /dev/null +++ b/higan/processor/hg51b/instruction.cpp @@ -0,0 +1,639 @@ +HG51B::HG51B() { + #define bind(id, name, ...) { \ + if(instructionTable[id]) throw; \ + instructionTable[id] = [=] { return instruction##name(__VA_ARGS__); }; \ + } + + #define pattern(s) \ + std::integral_constant::value + + static const uint5 shifts[] = {0, 1, 8, 16}; + + //NOP + for(uint10 null : range(1024)) { + auto opcode = pattern("0000 00.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //??? + for(uint10 null : range(1024)) { + auto opcode = pattern("0000 01.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //JMP imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0000 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, 1); + } + + //JMP EQ,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0000 11f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.z); + } + + //JMP GE,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0001 00f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.c); + } + + //JMP MI,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0001 01f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.n); + } + + //JMP VS,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0001 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JMP, data, far, r.v); + } + + //WAIT + for(uint10 null : range(1024)) { + auto opcode = pattern("0001 11.. .... ...."); + bind(opcode | null << 0, WAIT); + } + + //??? + for(uint10 null : range(1024)) { + auto opcode = pattern("0010 00.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //SKIP V + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0100 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.v); + } + + //SKIP C + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0101 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.c); + } + + //SKIP Z + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0110 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.z); + } + + //SKIP N + for(uint1 take : range( 2)) + for(uint7 null : range(128)) { + auto opcode = pattern("0010 0111 .... ...t"); + bind(opcode | take << 0 | null << 1, SKIP, take, r.n); + } + + //JSR + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0010 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, 1); + } + + //JSR EQ,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0010 11f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.z); + } + + //JSR GE,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0011 00f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.c); + } + + //JSR MI,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0011 01f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.n); + } + + //JSR VS,imm + for(uint8 data : range(256)) + for(uint1 null : range( 2)) + for(uint1 far : range( 2)) { + auto opcode = pattern("0011 10f. dddd dddd"); + bind(opcode | data << 0 | null << 8 | far << 9, JSR, data, far, r.v); + } + + //RTS + for(uint10 null : range(1024)) { + auto opcode = pattern("0011 11.. .... ...."); + bind(opcode | null << 0, RTS); + } + + //INC MAR + for(uint10 null : range(1024)) { + auto opcode = pattern("0100 00.. .... ...."); + bind(opcode | null << 0, INC, r.mar); + } + + //??? + for(uint10 null : range(1024)) { + auto opcode = pattern("0100 01.. .... ...."); + bind(opcode | null << 0, NOP); + } + + //CMPR A< void { r.pc = pc >> 0; } -//Shift-A: math opcodes can shift A register prior to ALU operation -auto HG51B::sa() -> uint { - static const uint shift[] = {0, 1, 8, 16}; - return r.a << shift[opcode.bits(8,9)]; +// + +auto HG51B::algorithmADD(uint24 x, uint24 y) -> uint24 { + int z = x + y; + r.n = z & 0x800000; + r.z = (uint24)z == 0; + r.c = z > 0xffffff; + r.v = ~(x ^ y) & (x ^ z) & 0x800000; + return z; } -//Register-or-Immediate: most opcodes can load from a register or immediate -auto HG51B::ri() -> uint { - if(opcode.bit(10)) return opcode.bits(0,7); - return readRegister(opcode.bits(0,7)); +auto HG51B::algorithmAND(uint24 x, uint24 y) -> uint24 { + x = x & y; + r.n = x & 0x800000; + r.z = x == 0; + return x; } -//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes) -auto HG51B::np() -> void { - if(opcode.bit(9)) r.pb = r.p; - r.pc = opcode.bits(0,7); +auto HG51B::algorithmASR(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = (int24)a >> s; + r.n = a & 0x800000; + r.z = a == 0; + return a; } -auto HG51B::instruction() -> void { - if((opcode & 0xffff) == 0x0000) { - //0000 0000 0000 0000 - //nop - } - - else if((opcode & 0xdd00) == 0x0800) { - //00.0 10.0 .... .... - //jump i - if(opcode & 0x2000) push(); - np(); - step(2); - } - - else if((opcode & 0xdd00) == 0x0c00) { - //00.0 11.0 .... .... - //jumpeq i - if(r.z) { - if(opcode & 0x2000) push(); - np(); - step(2); - } - } - - else if((opcode & 0xdd00) == 0x1000) { - //00.1 00.0 .... .... - //jumpge i - if(r.c) { - if(opcode & 0x2000) push(); - np(); - step(2); - } - } - - else if((opcode & 0xdd00) == 0x1400) { - //00.1 01.0 .... .... - //jumpmi i - if(r.n) { - if(opcode & 0x2000) push(); - np(); - step(2); - } - } - - else if((opcode & 0xffff) == 0x1c00) { - //0001 1100 0000 0000 - //wait - if(io.bus.enable) step(io.bus.pending); - } - - else if((opcode & 0xfffe) == 0x2500) { - //0010 0101 0000 000. - //skiplt/skipge - if(r.c == (opcode & 1)) { - advance(); - step(1); - } - } - - else if((opcode & 0xfffe) == 0x2600) { - //0010 0110 0000 000. - //skipne/skipeq - if(r.z == (opcode & 1)) { - advance(); - step(1); - } - } - - else if((opcode & 0xfffe) == 0x2700) { - //0010 0111 0000 000. - //skipmi/skippl - if(r.n == (opcode & 1)) { - advance(); - step(1); - } - } - - else if((opcode & 0xffff) == 0x3c00) { - //0011 1100 0000 0000 - //ret - pull(); - step(2); - } - - else if((opcode & 0xffff) == 0x4000) { - //0100 0000 0000 0000 - //??? - r.busAddress++; - } - - else if((opcode & 0xf800) == 0x4800) { - //0100 1... .... .... - //cmpr a<= 0; - } - - else if((opcode & 0xf800) == 0x5000) { - //0101 0... .... .... - //cmp a<= 0; - } - - else if((opcode & 0xfb00) == 0x5900) { - //0101 1.01 .... .... - //sxb - r.a = (int8)ri(); - } - - else if((opcode & 0xfb00) == 0x5a00) { - //0101 1.10 .... .... - //sxw - r.a = (int16)ri(); - } - - else if((opcode & 0xfb00) == 0x6000) { - //0110 0.00 .... .... - //ld a,ri - r.a = ri(); - } - - else if((opcode & 0xfb00) == 0x6100) { - //0110 0.01 .... .... - //ld bus,ri - r.busData = ri(); - } - - else if((opcode & 0xfb00) == 0x6300) { - //0110 0.11 .... .... - //ld p,ri - r.p = ri(); - } - - else if((opcode & 0xfb00) == 0x6800) { - //0110 1.00 .... .... - //rdraml - uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0); - if(target < 0xc00) r.ramData.byte(0) = dataRAM[target]; - } - - else if((opcode & 0xfb00) == 0x6900) { - //0110 1.01 .... .... - //rdramh - uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0); - if(target < 0xc00) r.ramData.byte(1) = dataRAM[target]; - } - - else if((opcode & 0xfb00) == 0x6a00) { - //0110 1.10 .... .... - //rdramb - uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0); - if(target < 0xc00) r.ramData.byte(2) = dataRAM[target]; - } - - else if((opcode & 0xffff) == 0x7000) { - //0111 0000 0000 0000 - //rdrom - r.romData = dataROM[(uint10)r.a]; - } - - else if((opcode & 0xff00) == 0x7c00) { - //0111 1100 .... .... - //ld pl,i - r.p.byte(0) = opcode.bits(0,7); - } - - else if((opcode & 0xff00) == 0x7d00) { - //0111 1101 .... .... - //ld ph,i - r.p.byte(1) = opcode.bits(0,7); - } - - else if((opcode & 0xf800) == 0x8000) { - //1000 0... .... .... - //add a< 0xffffff; - } - - else if((opcode & 0xf800) == 0x8800) { - //1000 1... .... .... - //subr a<= 0; - } - - else if((opcode & 0xf800) == 0x9000) { - //1001 0... .... .... - //sub a<= 0; - } - - else if((opcode & 0xfb00) == 0x9800) { - //1001 1.00 .... .... - //mul a,ri - int64 x = (int24)r.a; - int64 y = (int24)ri(); - x *= y; - r.accl = x >> 0ull; - r.acch = x >> 24ull; - r.n = r.acch & 0x800000; - r.z = x == 0; - } - - else if((opcode & 0xf800) == 0xa800) { - //1010 1... .... .... - //xor a<> ri(); - r.n = r.a & 0x800000; - r.z = r.a == 0; - } - - else if((opcode & 0xfb00) == 0xc800) { - //1100 1.00 .... .... - //asr a,ri - r.a = (int24)r.a >> ri(); - r.n = r.a & 0x800000; - r.z = r.a == 0; - } - - else if((opcode & 0xfb00) == 0xd000) { - //1101 0.00 .... .... - //ror a,ri - uint24 length = ri(); - r.a = (r.a >> length) | (r.a << (24 - length)); - r.n = r.a & 0x800000; - r.z = r.a == 0; - } - - else if((opcode & 0xfb00) == 0xd800) { - //1101 1.00 .... .... - //shl a,ri - r.a = r.a << ri(); - r.n = r.a & 0x800000; - r.z = r.a == 0; - } - - else if((opcode & 0xff00) == 0xe000) { - //1110 0000 .... .... - //st r,a - writeRegister(opcode & 0xff, r.a); - } - - else if((opcode & 0xff00) == 0xe100) { - //1110 0001 .... .... - //st r,bus - writeRegister(opcode & 0xff, r.busData); - } - - else if((opcode & 0xfb00) == 0xe800) { - //1110 1.00 .... .... - //wrraml - uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0); - if(target < 0xc00) dataRAM[target] = r.ramData.byte(0); - } - - else if((opcode & 0xfb00) == 0xe900) { - //1110 1.01 .... .... - //wrramh - uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0); - if(target < 0xc00) dataRAM[target] = r.ramData.byte(1); - } - - else if((opcode & 0xfb00) == 0xea00) { - //1110 1.10 .... .... - //wrramb - uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0); - if(target < 0xc00) dataRAM[target] = r.ramData.byte(2); - } - - else if((opcode & 0xff00) == 0xf000) { - //1111 0000 .... .... - //swap a,r - uint24 source = readRegister(opcode & 0xff); - uint24 target = r.a; - r.a = source; - writeRegister(opcode & 0xff, target); - } - - else if((opcode & 0xffff) == 0xfc00) { - //1111 1100 0000 0000 - //halt - halt(); - } - - else { - print("Hitachi DSP: unknown opcode @ ", hex((r.pb << 8 | r.pc << 0) - 1, 6L), " = ", hex(opcode, 4L), "\n"); - halt(); - } +auto HG51B::algorithmMUL(int24 x, int24 y) -> uint48 { + return (int48)x * (int48)y; +} + +auto HG51B::algorithmOR(uint24 x, uint24 y) -> uint24 { + x = x | y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmROR(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = (a >> s) | (a << 24 - s); + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmSHL(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = a << s; + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmSHR(uint24 a, uint5 s) -> uint24 { + if(s > 24) s = 0; + a = a >> s; + r.n = a & 0x800000; + r.z = a == 0; + return a; +} + +auto HG51B::algorithmSUB(uint24 x, uint24 y) -> uint24 { + int z = x - y; + r.n = z & 0x800000; + r.z = (uint24)z == 0; + r.c = z >= 0; + r.v = ~(x ^ y) & (x ^ z) & 0x800000; + return z; +} + +auto HG51B::algorithmSX(uint24 x) -> uint24 { + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmXNOR(uint24 x, uint24 y) -> uint24 { + x = ~x ^ y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +auto HG51B::algorithmXOR(uint24 x, uint24 y) -> uint24 { + x = x ^ y; + r.n = x & 0x800000; + r.z = x == 0; + return x; +} + +// + +auto HG51B::instructionADD(uint7 reg, uint5 shift) -> void { + r.a = algorithmADD(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionADD(uint8 imm, uint5 shift) -> void { + r.a = algorithmADD(r.a << shift, imm); +} + +auto HG51B::instructionAND(uint7 reg, uint5 shift) -> void { + r.a = algorithmAND(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionAND(uint8 imm, uint5 shift) -> void { + r.a = algorithmAND(r.a << shift, imm); +} + +auto HG51B::instructionASR(uint7 reg) -> void { + r.a = algorithmASR(r.a, readRegister(reg)); +} + +auto HG51B::instructionASR(uint5 imm) -> void { + r.a = algorithmASR(r.a, imm); +} + +auto HG51B::instructionCLEAR() -> void { + r.a = 0; + r.p = 0; + r.ram = 0; + r.dpr = 0; +} + +auto HG51B::instructionCMP(uint7 reg, uint5 shift) -> void { + algorithmSUB(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionCMP(uint8 imm, uint5 shift) -> void { + algorithmSUB(r.a << shift, imm); +} + +auto HG51B::instructionCMPR(uint7 reg, uint5 shift) -> void { + algorithmSUB(readRegister(reg), r.a << shift); +} + +auto HG51B::instructionCMPR(uint8 imm, uint5 shift) -> void { + algorithmSUB(imm, r.a << shift); +} + +auto HG51B::instructionHALT() -> void { + halt(); +} + +auto HG51B::instructionINC(uint24& reg) -> void { + reg++; +} + +auto HG51B::instructionJMP(uint8 data, uint1 far, const uint1& take) -> void { + if(!take) return; + if(far) r.pb = r.p; + r.pc = data; + step(2); +} + +auto HG51B::instructionJSR(uint8 data, uint1 far, const uint1& take) -> void { + if(!take) return; + push(); + if(far) r.pb = r.p; + r.pc = data; + step(2); +} + +auto HG51B::instructionLD(uint24& out, uint7 reg) -> void { + out = readRegister(reg); +} + +auto HG51B::instructionLD(uint15& out, uint4 reg) -> void { + out = r.gpr[reg]; +} + +auto HG51B::instructionLD(uint24& out, uint8 imm) -> void { + out = imm; +} + +auto HG51B::instructionLD(uint15& out, uint8 imm) -> void { + out = imm; +} + +auto HG51B::instructionLDL(uint15& out, uint8 imm) -> void { + out.bits(0,7) = imm; +} + +auto HG51B::instructionLDH(uint15& out, uint7 imm) -> void { + out.bits(8,14) = imm; +} + +auto HG51B::instructionMUL(uint7 reg) -> void { + r.mul = algorithmMUL(r.a, readRegister(reg)); +} + +auto HG51B::instructionMUL(uint8 imm) -> void { + r.mul = algorithmMUL(r.a, imm); +} + +auto HG51B::instructionNOP() -> void { +} + +auto HG51B::instructionOR(uint7 reg, uint5 shift) -> void { + r.a = algorithmOR(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionOR(uint8 imm, uint5 shift) -> void { + r.a = algorithmOR(r.a << shift, imm); +} + +auto HG51B::instructionRDRAM(uint2 byte, uint24& a) -> void { + uint12 address = a; + if(address >= 0xc00) address -= 0x400; + r.ram.byte(byte) = dataRAM[address]; +} + +auto HG51B::instructionRDRAM(uint2 byte, uint8 imm) -> void { + uint12 address = r.dpr + imm; + if(address >= 0xc00) address -= 0x400; + r.ram.byte(byte) = dataRAM[address]; +} + +auto HG51B::instructionRDROM(uint24& reg) -> void { + r.rom = dataROM[(uint10)reg]; +} + +auto HG51B::instructionRDROM(uint10 imm) -> void { + r.rom = dataROM[imm]; +} + +auto HG51B::instructionROR(uint7 reg) -> void { + r.a = algorithmROR(r.a, readRegister(reg)); +} + +auto HG51B::instructionROR(uint5 imm) -> void { + r.a = algorithmROR(r.a, imm); +} + +auto HG51B::instructionRTS() -> void { + pull(); + step(2); +} + +auto HG51B::instructionSKIP(uint1 take, const uint1& flag) -> void { + if(flag != take) return; + advance(); + step(1); +} + +auto HG51B::instructionSHL(uint7 reg) -> void { + r.a = algorithmSHL(r.a, readRegister(reg)); +} + +auto HG51B::instructionSHL(uint5 imm) -> void { + r.a = algorithmSHL(r.a, imm); +} + +auto HG51B::instructionSHR(uint7 reg) -> void { + r.a = algorithmSHR(r.a, readRegister(reg)); +} + +auto HG51B::instructionSHR(uint5 imm) -> void { + r.a = algorithmSHR(r.a, imm); +} + +auto HG51B::instructionST(uint7 reg, uint24& in) -> void { + writeRegister(reg, in); +} + +auto HG51B::instructionSUB(uint7 reg, uint5 shift) -> void { + r.a = algorithmSUB(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionSUB(uint8 imm, uint5 shift) -> void { + r.a = algorithmSUB(r.a << shift, imm); +} + +auto HG51B::instructionSUBR(uint7 reg, uint5 shift) -> void { + r.a = algorithmSUB(readRegister(reg), r.a << shift); +} + +auto HG51B::instructionSUBR(uint8 imm, uint5 shift) -> void { + r.a = algorithmSUB(imm, r.a << shift); +} + +auto HG51B::instructionSWAP(uint24& a, uint4 reg) -> void { + swap(a, r.gpr[reg]); +} + +auto HG51B::instructionSXB() -> void { + r.a = algorithmSX((int8)r.a); +} + +auto HG51B::instructionSXW() -> void { + r.a = algorithmSX((int16)r.a); +} + +auto HG51B::instructionWAIT() -> void { + if(!io.bus.enable) return; + return step(io.bus.pending); +} + +auto HG51B::instructionWRRAM(uint2 byte, uint24& a) -> void { + uint12 address = a; + if(address >= 0xc00) address -= 0x400; + dataRAM[address] = r.ram.byte(byte); +} + +auto HG51B::instructionWRRAM(uint2 byte, uint8 imm) -> void { + uint12 address = r.dpr + imm; + if(address >= 0xc00) address -= 0x400; + dataRAM[address] = r.ram.byte(byte); +} + +auto HG51B::instructionXNOR(uint7 reg, uint5 shift) -> void { + r.a = algorithmXNOR(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionXNOR(uint8 imm, uint5 shift) -> void { + r.a = algorithmXNOR(r.a << shift, imm); +} + +auto HG51B::instructionXOR(uint7 reg, uint5 shift) -> void { + r.a = algorithmXOR(r.a << shift, readRegister(reg)); +} + +auto HG51B::instructionXOR(uint8 imm, uint5 shift) -> void { + r.a = algorithmXOR(r.a << shift, imm); } diff --git a/higan/processor/hg51b/registers.cpp b/higan/processor/hg51b/registers.cpp index b7362748..3535048a 100644 --- a/higan/processor/hg51b/registers.cpp +++ b/higan/processor/hg51b/registers.cpp @@ -1,26 +1,28 @@ auto HG51B::readRegister(uint7 address) -> uint24 { switch(address) { - case 0x00: return r.a; - case 0x01: return r.acch; - case 0x02: return r.accl; - case 0x03: return r.busData; - case 0x08: return r.romData; - case 0x0c: return r.ramData; - case 0x13: return r.busAddress; - case 0x1c: return r.ramAddress; + case 0x01: return r.mul.bits(24,47); + case 0x02: return r.mul.bits( 0,23); + case 0x03: return r.mdr; + case 0x08: return r.rom; + case 0x0c: return r.ram; + case 0x13: return r.mar; + case 0x1c: return r.dpr; case 0x20: return r.pc; + case 0x28: return r.p; case 0x2e: io.bus.enable = 1; io.bus.reading = 1; io.bus.pending = 1 + io.wait.rom; - io.bus.address = r.busAddress; + io.bus.address = r.mar; return 0x000000; case 0x2f: io.bus.enable = 1; io.bus.reading = 1; io.bus.pending = 1 + io.wait.ram; - io.bus.address = r.busAddress; + io.bus.address = r.mar; return 0x000000; + + //constant registers case 0x50: return 0x000000; case 0x51: return 0xffffff; case 0x52: return 0x00ff00; @@ -37,6 +39,8 @@ auto HG51B::readRegister(uint7 address) -> uint24 { case 0x5d: return 0xfeffff; case 0x5e: return 0x000100; case 0x5f: return 0x00feff; + + //general purpose registers case 0x60: case 0x70: return r.gpr[ 0]; case 0x61: case 0x71: return r.gpr[ 1]; case 0x62: case 0x72: return r.gpr[ 2]; @@ -54,32 +58,34 @@ auto HG51B::readRegister(uint7 address) -> uint24 { case 0x6e: case 0x7e: return r.gpr[14]; case 0x6f: case 0x7f: return r.gpr[15]; } - return 0x000000; + + return 0x000000; //verified } auto HG51B::writeRegister(uint7 address, uint24 data) -> void { switch(address) { - case 0x00: r.a = data; return; - case 0x01: r.acch = data; return; - case 0x02: r.accl = data; return; - case 0x03: r.busData = data; return; - case 0x08: r.romData = data; return; - case 0x0c: r.ramData = data; return; - case 0x13: r.busAddress = data; return; - case 0x1c: r.ramAddress = data; return; + case 0x01: r.mul.bits(24,47) = data; return; + case 0x02: r.mul.bits( 0,23) = data; return; + case 0x03: r.mdr = data; return; + case 0x08: r.rom = data; return; + case 0x0c: r.ram = data; return; + case 0x13: r.mar = data; return; + case 0x1c: r.dpr = data; return; case 0x20: r.pc = data; return; + case 0x28: r.p = data; return; case 0x2e: io.bus.enable = 1; io.bus.writing = 1; io.bus.pending = 1 + io.wait.rom; - io.bus.address = r.busAddress; + io.bus.address = r.mar; return; case 0x2f: io.bus.enable = 1; io.bus.writing = 1; io.bus.pending = 1 + io.wait.ram; - io.bus.address = r.busAddress; + io.bus.address = r.mar; return; + case 0x60: case 0x70: r.gpr[ 0] = data; return; case 0x61: case 0x71: r.gpr[ 1] = data; return; case 0x62: case 0x72: r.gpr[ 2] = data; return; diff --git a/higan/processor/hg51b/serialization.cpp b/higan/processor/hg51b/serialization.cpp index 74f148d3..d8fd4eeb 100644 --- a/higan/processor/hg51b/serialization.cpp +++ b/higan/processor/hg51b/serialization.cpp @@ -3,23 +3,23 @@ auto HG51B::serialize(serializer& s) -> void { s.array(programRAM[1]); s.array(dataRAM); - s.integer(r.p); s.integer(r.pb); s.integer(r.pc); s.boolean(r.n); s.boolean(r.z); s.boolean(r.c); + s.boolean(r.v); s.boolean(r.i); s.integer(r.a); - s.integer(r.acch); - s.integer(r.accl); - s.integer(r.busData); - s.integer(r.romData); - s.integer(r.ramData); - s.integer(r.busAddress); - s.integer(r.ramAddress); + s.integer(r.p); + s.integer(r.mul); + s.integer(r.mdr); + s.integer(r.rom); + s.integer(r.ram); + s.integer(r.mar); + s.integer(r.dpr); s.array(r.gpr); s.integer(io.lock); @@ -54,5 +54,4 @@ auto HG51B::serialize(serializer& s) -> void { s.integer(io.bus.address); s.array(stack); - s.integer(opcode); } diff --git a/higan/processor/wdc65816/serialization.cpp b/higan/processor/wdc65816/serialization.cpp index 3b9bff3d..d7e72d98 100644 --- a/higan/processor/wdc65816/serialization.cpp +++ b/higan/processor/wdc65816/serialization.cpp @@ -22,7 +22,6 @@ auto WDC65816::serialize(serializer& s) -> void { s.integer(r.irq); s.integer(r.wai); s.integer(r.stp); - s.integer(r.rwb); s.integer(r.mar); s.integer(r.mdr); s.integer(r.vector); diff --git a/higan/processor/wdc65816/wdc65816.cpp b/higan/processor/wdc65816/wdc65816.cpp index 51644adf..af0e19dd 100644 --- a/higan/processor/wdc65816/wdc65816.cpp +++ b/higan/processor/wdc65816/wdc65816.cpp @@ -54,9 +54,9 @@ auto WDC65816::power() -> void { P = 0x34; EF = 1; + r.irq = false; r.wai = false; r.stp = false; - r.rwb = false; r.mar = 0x000000; r.mdr = 0x00; r.vector = 0xfffc; //reset vector address diff --git a/higan/processor/wdc65816/wdc65816.hpp b/higan/processor/wdc65816/wdc65816.hpp index 7a0c06dd..19005854 100644 --- a/higan/processor/wdc65816/wdc65816.hpp +++ b/higan/processor/wdc65816/wdc65816.hpp @@ -252,7 +252,6 @@ struct WDC65816 { bool irq = false; //IRQ pin (0 = low, 1 = trigger) bool wai = false; //raised during wai, cleared after interrupt triggered bool stp = false; //raised during stp, never cleared - bool rwb = false; //read/write pin uint24 mar; //memory address register uint8 mdr; //memory data register uint16 vector; //interrupt vector address diff --git a/higan/sfc/cartridge/load.cpp b/higan/sfc/cartridge/load.cpp index 741188ad..056a8da9 100644 --- a/higan/sfc/cartridge/load.cpp +++ b/higan/sfc/cartridge/load.cpp @@ -302,7 +302,7 @@ auto Cartridge::loadSA1(Markup::Node node) -> void { has.SA1 = true; for(auto map : node.find("map")) { - loadMap(map, {&SA1::readIO, &sa1}, {&SA1::writeIO, &sa1}); + loadMap(map, {&SA1::readIOCPU, &sa1}, {&SA1::writeIOCPU, &sa1}); } if(auto mcu = node["mcu"]) { diff --git a/higan/sfc/coprocessor/sa1/bwram.cpp b/higan/sfc/coprocessor/sa1/bwram.cpp index 420aad4f..90090267 100644 --- a/higan/sfc/coprocessor/sa1/bwram.cpp +++ b/higan/sfc/coprocessor/sa1/bwram.cpp @@ -1,7 +1,6 @@ auto SA1::BWRAM::conflict() const -> bool { if(configuration.hacks.coprocessors.delayedSync) return false; - if(!cpu.r.rwb) return false; if((cpu.r.mar & 0x40e000) == 0x006000) return true; //00-3f,80-bf:6000-7fff if((cpu.r.mar & 0xf00000) == 0x400000) return true; //40-4f:0000-ffff return false; diff --git a/higan/sfc/coprocessor/sa1/dma.cpp b/higan/sfc/coprocessor/sa1/dma.cpp index 7252fba2..b67a77cb 100644 --- a/higan/sfc/coprocessor/sa1/dma.cpp +++ b/higan/sfc/coprocessor/sa1/dma.cpp @@ -6,25 +6,36 @@ auto SA1::dmaNormal() -> void { uint16 target = mmio.dda++; if(mmio.sd == DMA::SourceROM && mmio.dd == DMA::DestBWRAM) { - step(bwram.conflict() ? 8 : 4); + step(); + step(); + if(bwram.conflict()) step(); + if(bwram.conflict()) step(); data = rom.readSA1(source, data); bwram.write(target, data); } if(mmio.sd == DMA::SourceROM && mmio.dd == DMA::DestIRAM) { - step(iram.conflict() ? 6 : 4); + step(); + if(iram.conflict() || rom.conflict()) step(); + if(iram.conflict()) step(); data = rom.readSA1(source, data); iram.write(target, data); } if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestIRAM) { - step(bwram.conflict() ? 8 : iram.conflict() ? 6 : 4); + step(); + step(); + if(bwram.conflict() || iram.conflict()) step(); + if(bwram.conflict()) step(); data = bwram.read(source, data); iram.write(target, data); } if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestBWRAM) { - step(bwram.conflict() ? 8 : iram.conflict() ? 6 : 4); + step(); + step(); + if(bwram.conflict() || iram.conflict()) step(); + if(bwram.conflict()) step(); data = iram.read(source, data); bwram.write(target, data); } diff --git a/higan/sfc/coprocessor/sa1/io.cpp b/higan/sfc/coprocessor/sa1/io.cpp index cb1f9138..c514d4a9 100644 --- a/higan/sfc/coprocessor/sa1/io.cpp +++ b/higan/sfc/coprocessor/sa1/io.cpp @@ -1,7 +1,7 @@ -auto SA1::readIO(uint24 addr, uint8) -> uint8 { - cpu.active() ? cpu.synchronize(sa1) : synchronize(cpu); +auto SA1::readIOCPU(uint24 address, uint8 data) -> uint8 { + cpu.synchronize(sa1); - switch(0x2300 | addr.bits(0,7)) { + switch(0x2200 | address.bits(0,8)) { //(SFR) S-CPU flag read case 0x2300: { @@ -14,6 +14,21 @@ auto SA1::readIO(uint24 addr, uint8) -> uint8 { return data; } + //(VC) version code register + case 0x230e: { + break; //does not actually exist on real hardware ... always returns open bus + } + + } + + return data; +} + +auto SA1::readIOSA1(uint24 address, uint8) -> uint8 { + synchronize(cpu); + + switch(0x2200 | address.bits(0,8)) { + //(CFR) SA-1 flag read case 0x2301: { uint8 data; @@ -80,20 +95,15 @@ auto SA1::readIO(uint24 addr, uint8) -> uint8 { return data >> 8; } - //(VC) version code register - case 0x230e: { - return 0x23; //RF5A123 } - } - - return 0x00; + return 0xff; } -auto SA1::writeIO(uint24 addr, uint8 data) -> void { - cpu.active() ? cpu.synchronize(sa1) : synchronize(cpu); +auto SA1::writeIOCPU(uint24 address, uint8 data) -> void { + cpu.synchronize(sa1); - switch(0x2200 | addr.bits(0,7)) { + switch(0x2200 | address.bits(0,8)) { //(CCNT) SA-1 control case 0x2200: { @@ -166,6 +176,70 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void { case 0x2207: { mmio.civ = (mmio.civ & 0xff00) | data; return; } case 0x2208: { mmio.civ = (data << 8) | (mmio.civ & 0xff); return; } + //(CXB) Super MMC bank C + case 0x2220: { + mmio.cbmode = (data & 0x80); + mmio.cb = (data & 0x07); + return; + } + + //(DXB) Super MMC bank D + case 0x2221: { + mmio.dbmode = (data & 0x80); + mmio.db = (data & 0x07); + return; + } + + //(EXB) Super MMC bank E + case 0x2222: { + mmio.ebmode = (data & 0x80); + mmio.eb = (data & 0x07); + return; + } + + //(FXB) Super MMC bank F + case 0x2223: { + mmio.fbmode = (data & 0x80); + mmio.fb = (data & 0x07); + return; + } + + //(BMAPS) S-CPU BW-RAM address mapping + case 0x2224: { + mmio.sbm = (data & 0x1f); + return; + } + + //(SWBE) S-CPU BW-RAM write enable + case 0x2226: { + mmio.swen = (data & 0x80); + return; + } + + //(BWPA) BW-RAM write-protected area + case 0x2228: { + mmio.bwp = (data & 0x0f); + return; + } + + //(SIWP) S-CPU I-RAM write protection + case 0x2229: { + mmio.siwp = data; + return; + } + + case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: { + return writeIOShared(address, data); + } + + } +} + +auto SA1::writeIOSA1(uint24 address, uint8 data) -> void { + synchronize(cpu); + + switch(0x2200 | address.bits(0,8)) { + //(SCNT) S-CPU control case 0x2209: { mmio.cpu_irq = (data & 0x80); @@ -243,40 +317,6 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void { case 0x2214: { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); return; } case 0x2215: { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); return; } - //(CXB) Super MMC bank C - case 0x2220: { - mmio.cbmode = (data & 0x80); - mmio.cb = (data & 0x07); - return; - } - - //(DXB) Super MMC bank D - case 0x2221: { - mmio.dbmode = (data & 0x80); - mmio.db = (data & 0x07); - return; - } - - //(EXB) Super MMC bank E - case 0x2222: { - mmio.ebmode = (data & 0x80); - mmio.eb = (data & 0x07); - return; - } - - //(FXB) Super MMC bank F - case 0x2223: { - mmio.fbmode = (data & 0x80); - mmio.fb = (data & 0x07); - return; - } - - //(BMAPS) S-CPU BW-RAM address mapping - case 0x2224: { - mmio.sbm = (data & 0x1f); - return; - } - //(BMAP) SA-1 BW-RAM address mapping case 0x2225: { mmio.sw46 = (data & 0x80); @@ -284,30 +324,12 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void { return; } - //(SWBE) S-CPU BW-RAM write enable - case 0x2226: { - mmio.swen = (data & 0x80); - return; - } - //(CWBE) SA-1 BW-RAM write enable case 0x2227: { mmio.cwen = (data & 0x80); return; } - //(BWPA) BW-RAM write-protected area - case 0x2228: { - mmio.bwp = (data & 0x0f); - return; - } - - //(SIWP) S-CPU I-RAM write protection - case 0x2229: { - mmio.siwp = data; - return; - } - //(CIWP) SA-1 I-RAM write protection case 0x222a: { mmio.ciwp = data; @@ -327,42 +349,8 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void { return; } - //(CDMA) character conversion DMA parameters - case 0x2231: { - mmio.chdend = (data & 0x80); - mmio.dmasize = (data >> 2) & 7; - mmio.dmacb = (data & 0x03); - - if(mmio.chdend) bwram.dma = false; - if(mmio.dmasize > 5) mmio.dmasize = 5; - if(mmio.dmacb > 2) mmio.dmacb = 2; - return; - } - - //(SDA) DMA source device start address - case 0x2232: { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); return; } - case 0x2233: { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); return; } - case 0x2234: { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); return; } - - //(DDA) DMA destination start address - case 0x2235: { mmio.dda = (mmio.dda & 0xffff00) | (data << 0); return; } - case 0x2236: { mmio.dda = (mmio.dda & 0xff00ff) | (data << 8); - if(mmio.dmaen) { - if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) { - dmaNormal(); - } else if(mmio.cden == 1 && mmio.cdsel == 1) { - dmaCC1(); - } - } - return; - } - case 0x2237: { mmio.dda = (mmio.dda & 0x00ffff) | (data << 16); - if(mmio.dmaen) { - if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) { - dmaNormal(); - } - } - return; + case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: { + return writeIOShared(address, data); } //(DTC) DMA terminal counter @@ -488,3 +476,47 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void { } } + +auto SA1::writeIOShared(uint24 address, uint8 data) -> void { + switch(0x2200 | address.bits(0,8)) { + + //(CDMA) character conversion DMA parameters + case 0x2231: { + mmio.chdend = (data & 0x80); + mmio.dmasize = (data >> 2) & 7; + mmio.dmacb = (data & 0x03); + + if(mmio.chdend) bwram.dma = false; + if(mmio.dmasize > 5) mmio.dmasize = 5; + if(mmio.dmacb > 2) mmio.dmacb = 2; + return; + } + + //(SDA) DMA source device start address + case 0x2232: { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); return; } + case 0x2233: { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); return; } + case 0x2234: { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); return; } + + //(DDA) DMA destination start address + case 0x2235: { mmio.dda = (mmio.dda & 0xffff00) | (data << 0); return; } + case 0x2236: { mmio.dda = (mmio.dda & 0xff00ff) | (data << 8); + if(mmio.dmaen) { + if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) { + dmaNormal(); + } else if(mmio.cden == 1 && mmio.cdsel == 1) { + dmaCC1(); + } + } + return; + } + case 0x2237: { mmio.dda = (mmio.dda & 0x00ffff) | (data << 16); + if(mmio.dmaen) { + if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) { + dmaNormal(); + } + } + return; + } + + } +} diff --git a/higan/sfc/coprocessor/sa1/iram.cpp b/higan/sfc/coprocessor/sa1/iram.cpp index 3a41ca47..6712d896 100644 --- a/higan/sfc/coprocessor/sa1/iram.cpp +++ b/higan/sfc/coprocessor/sa1/iram.cpp @@ -1,8 +1,7 @@ auto SA1::IRAM::conflict() const -> bool { if(configuration.hacks.coprocessors.delayedSync) return false; - if(!cpu.r.rwb) return false; - if((cpu.r.mar & 0x40f800) == 0x003000) return true; //00-3f,80-bf:3000-37ff + if((cpu.r.mar & 0x40f800) == 0x003000) return cpu.refresh() == 0; //00-3f,80-bf:3000-37ff return false; } diff --git a/higan/sfc/coprocessor/sa1/memory.cpp b/higan/sfc/coprocessor/sa1/memory.cpp index 2d78e179..8a13e11c 100644 --- a/higan/sfc/coprocessor/sa1/memory.cpp +++ b/higan/sfc/coprocessor/sa1/memory.cpp @@ -1,12 +1,16 @@ auto SA1::idle() -> void { - r.rwb = 0; - step(2); + step(); } //RTx, JMx, JSx auto SA1::idleJump() -> void { //ROM access penalty cycle: does not apply to BWRAM or IRAM - if((r.pc & 0x408000) == 0x008000 || (r.pc & 0xc00000) == 0xc00000) idle(); + if((r.pc & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (r.pc & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + step(); + if(rom.conflict()) step(); + } } //Bxx @@ -15,118 +19,90 @@ auto SA1::idleBranch() -> void { } auto SA1::read(uint24 address) -> uint8 { - r.rwb = 1; r.mar = address; uint8 data = r.mdr; - //00-3f,80-bf:2200-23ff - if((address & 0x40fe00) == 0x002200) { - step(2); - return r.mdr = readIO(address, data); + if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff + ) { + step(); + return r.mdr = readIOSA1(address, data); } - //00-3f,80-bf:8000-ffff - if((address & 0x408000) == 0x008000) { - step(rom.conflict() ? 4 : 2); + if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + step(); + if(rom.conflict()) step(); return r.mdr = rom.readSA1(address, data); } - //c0-ff:0000-ffff - if((address & 0xc00000) == 0xc00000) { - step(rom.conflict() ? 4 : 2); - return r.mdr = rom.readSA1(address, data); - } - - //00-3f,80-bf:6000-7fff - if((address & 0x40e000) == 0x006000) { - step(bwram.conflict() ? 8 : 4); + if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff + || (address & 0xf00000) == 0x400000 //40-4f:0000-ffff + || (address & 0xf00000) == 0x600000 //60-6f:0000-ffff + ) { + step(); + step(); + if(bwram.conflict()) step(); + if(bwram.conflict()) step(); + if(address.bit(22) && address.bit(21)) return r.mdr = bwram.readBitmap(address, data); + if(address.bit(22)) return r.mdr = bwram.readLinear(address, data); return r.mdr = bwram.readSA1(address, data); } - //00-3f,80-bf:0000-07ff - if((address & 0x40f800) == 0x000000) { - step(iram.conflict() ? 6 : 2); + if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff + || (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff + ) { + step(); + if(iram.conflict()) step(); + if(iram.conflict()) step(); return r.mdr = iram.readSA1(address, data); } - //00-3f,80-bf:3000-37ff - if((address & 0x40f800) == 0x003000) { - step(iram.conflict() ? 6 : 2); - return r.mdr = iram.readSA1(address, data); - } - - //40-4f:0000-ffff - if((address & 0xf00000) == 0x400000) { - step(bwram.conflict() ? 8 : 4); - return r.mdr = bwram.readLinear(address, data); - } - - //60-6f:0000-ffff - if((address & 0xf00000) == 0x600000) { - step(bwram.conflict() ? 8 : 4); - return r.mdr = bwram.readBitmap(address, data); - } - - //unmapped region - step(2); + step(); return data; } auto SA1::write(uint24 address, uint8 data) -> void { - r.rwb = 1; r.mar = address; r.mdr = data; - //00-3f,80-bf:2200-23ff - if((address & 0x40fe00) == 0x002200) { - step(2); - return writeIO(address, data); + if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff + ) { + step(); + return writeIOSA1(address, data); } - //00-3f,80-bf:8000-ffff - if((address & 0x408000) == 0x008000) { - step(rom.conflict() ? 4 : 2); + if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { + step(); + if(rom.conflict()) step(); return rom.writeSA1(address, data); } - //c0-ff:0000-ffff - if((address & 0xc00000) == 0xc00000) { - step(rom.conflict() ? 4 : 2); - return rom.writeSA1(address, data); - } - - //00-3f,80-bf:6000-7fff - if((address & 0x40e000) == 0x006000) { - step(bwram.conflict() ? 8 : 4); + if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff + || (address & 0xf00000) == 0x400000 //40-4f:0000-ffff + || (address & 0xf00000) == 0x600000 //60-6f:0000-ffff + ) { + step(); + step(); + if(bwram.conflict()) step(); + if(bwram.conflict()) step(); + if(address.bit(22) && address.bit(21)) return bwram.writeBitmap(address, data); + if(address.bit(22)) return bwram.writeLinear(address, data); return bwram.writeSA1(address, data); } - //00-3f,80-bf:0000-07ff - if((address & 0x40f800) == 0x000000) { - step(iram.conflict() ? 6 : 2); + if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff + || (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff + ) { + step(); + if(iram.conflict()) step(); + if(iram.conflict()) step(); return iram.writeSA1(address, data); } - //00-3f,80-bf:3000-37ff - if((address & 0x40f800) == 0x003000) { - step(iram.conflict() ? 6 : 2); - return iram.writeSA1(address, data); - } - - //40-4f:0000-ffff - if((address & 0xf00000) == 0x400000) { - step(bwram.conflict() ? 8 : 4); - return bwram.writeLinear(address, data); - } - - //60-6f:0000-ffff - if((address & 0xf00000) == 0x600000) { - step(bwram.conflict() ? 8 : 4); - return bwram.writeBitmap(address, data); - } - - //unmapped region - step(2); + step(); return; } @@ -135,35 +111,29 @@ auto SA1::write(uint24 address, uint8 data) -> void { //to avoid syncing the S-CPU and SA-1*; as both chips are able to access //these ports. auto SA1::readVBR(uint24 address, uint8 data) -> uint8 { - //00-3f,80-bf:8000-ffff - if((address & 0x408000) == 0x008000) { + if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff + || (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff + ) { return rom.readSA1(address, data); } - //c0-ff:0000-ffff - if((address & 0xc00000) == 0xc00000) { - return rom.readSA1(address, data); - } - - //00-3f,80-bf:6000-7fff - if((address & 0x40e000) == 0x006000) { + if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff + || (address & 0xf00000) == 0x400000 //40-4f:0000-ffff + ) { return bwram.read(address, data); } - //40-4f:0000-ffff - if((address & 0xf00000) == 0x400000) { - return bwram.read(address, data); - } - - //00-3f,80-bf:0000-07ff - if((address & 0x40f800) == 0x000000) { + if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff + || (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff + ) { return iram.read(address, data); } - //00-3f,80-bf:3000-37ff - if((address & 0x40f800) == 0x003000) { - return iram.read(address, data); - } - - return 0x00; + return 0xff; +} + +auto SA1::readDisassembler(uint24 address) -> uint8 { + //TODO: this is a hack; SA1::read() advances the clock; whereas Bus::read() does not + //the CPU and SA1 bus are identical for ROM, but have differences in BWRAM and IRAM + return bus.read(address, r.mdr); } diff --git a/higan/sfc/coprocessor/sa1/rom.cpp b/higan/sfc/coprocessor/sa1/rom.cpp index 87f7e20d..008af59f 100644 --- a/higan/sfc/coprocessor/sa1/rom.cpp +++ b/higan/sfc/coprocessor/sa1/rom.cpp @@ -1,7 +1,6 @@ auto SA1::ROM::conflict() const -> bool { if(configuration.hacks.coprocessors.delayedSync) return false; - if(!cpu.r.rwb) return false; if((cpu.r.mar & 0x408000) == 0x008000) return true; //00-3f,80-bf:8000-ffff if((cpu.r.mar & 0xc00000) == 0xc00000) return true; //c0-ff:0000-ffff return false; @@ -55,7 +54,7 @@ auto SA1::ROM::readCPU(uint24 address, uint8 data) -> uint8 { return read(sa1.mmio.fb << 20 | address & 0x0fffff); } - return 0x00; + return data; //unreachable } auto SA1::ROM::writeCPU(uint24 address, uint8 data) -> void { @@ -69,8 +68,4 @@ auto SA1::ROM::readSA1(uint24 address, uint8 data) -> uint8 { } auto SA1::ROM::writeSA1(uint24 address, uint8 data) -> void { - if((address & 0x408000) == 0x008000) { - address = (address & 0x800000) >> 2 | (address & 0x3f0000) >> 1 | address & 0x007fff; - } - return writeCPU(address, data); } diff --git a/higan/sfc/coprocessor/sa1/sa1.cpp b/higan/sfc/coprocessor/sa1/sa1.cpp index 553af4de..6430087e 100644 --- a/higan/sfc/coprocessor/sa1/sa1.cpp +++ b/higan/sfc/coprocessor/sa1/sa1.cpp @@ -21,7 +21,7 @@ auto SA1::main() -> void { if(mmio.sa1_rdyb || mmio.sa1_resb) { //SA-1 co-processor is asleep - step(2); + step(); return; } @@ -31,6 +31,7 @@ auto SA1::main() -> void { return; } +//print(disassemble(), "\n"); instruction(); } @@ -82,8 +83,8 @@ auto SA1::synchronizing() const -> bool { return scheduler.synchronizing(); } -auto SA1::step(uint clocks) -> void { - Thread::step(clocks); +auto SA1::step() -> void { + Thread::step(2); synchronize(cpu); //adjust counters: @@ -91,21 +92,23 @@ auto SA1::step(uint clocks) -> void { //whereas MMIO register counters are in dots (4 clocks = 1 dot) if(mmio.hvselb == 0) { //HV timer - status.hcounter += clocks; - while(status.hcounter >= 1364) { - status.hcounter -= 1364; - if(++status.vcounter >= status.scanlines) status.vcounter = 0; + status.hcounter += 2; + if(status.hcounter >= 1364) { + status.hcounter = 0; + if(++status.vcounter >= status.scanlines) { + status.vcounter = 0; + } } } else { //linear timer - status.hcounter += clocks; - status.vcounter += (status.hcounter >> 11); + status.hcounter += 2; + status.vcounter += status.hcounter >> 11; status.hcounter &= 0x07ff; status.vcounter &= 0x01ff; } //test counters for timer IRQ - switch((mmio.ven << 1) + (mmio.hen << 0)) { + switch(mmio.hen << 0 | mmio.ven << 1) { case 0: break; case 1: if(status.hcounter == mmio.hcnt << 2) triggerIRQ(); break; case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) triggerIRQ(); break; @@ -129,8 +132,8 @@ auto SA1::power() -> void { create(SA1::Enter, system.cpuFrequency()); bwram.dma = false; - for(auto addr : range(iram.size())) { - iram.write(addr, 0x00); + for(uint address : range(iram.size())) { + iram.write(address, 0x00); } status.counter = 0; diff --git a/higan/sfc/coprocessor/sa1/sa1.hpp b/higan/sfc/coprocessor/sa1/sa1.hpp index f5168009..806fca5b 100644 --- a/higan/sfc/coprocessor/sa1/sa1.hpp +++ b/higan/sfc/coprocessor/sa1/sa1.hpp @@ -1,10 +1,10 @@ -//Super Accelerator 1 +//Super Accelerator (SA-1) struct SA1 : Processor::WDC65816, Thread { //sa1.cpp static auto Enter() -> void; auto main() -> void; - auto step(uint clocks) -> void; + auto step() -> void; auto interrupt() -> void override; alwaysinline auto triggerIRQ() -> void; @@ -36,13 +36,17 @@ struct SA1 : Processor::WDC65816, Thread { alwaysinline auto idle() -> void override; alwaysinline auto idleJump() -> void override; alwaysinline auto idleBranch() -> void override; - alwaysinline auto read(uint24 addr) -> uint8 override; - alwaysinline auto write(uint24 addr, uint8 data) -> void override; - auto readVBR(uint24 addr, uint8 data = 0) -> uint8; + alwaysinline auto read(uint24 address) -> uint8 override; + alwaysinline auto write(uint24 address, uint8 data) -> void override; + auto readVBR(uint24 address, uint8 data = 0) -> uint8; + auto readDisassembler(uint24 address) -> uint8 override; //io.cpp - auto readIO(uint24 addr, uint8 data) -> uint8; - auto writeIO(uint24 addr, uint8 data) -> void; + auto readIOCPU(uint24 address, uint8 data) -> uint8; + auto readIOSA1(uint24 address, uint8 data) -> uint8; + auto writeIOCPU(uint24 address, uint8 data) -> void; + auto writeIOSA1(uint24 address, uint8 data) -> void; + auto writeIOShared(uint24 address, uint8 data) -> void; //serialization.cpp auto serialize(serializer&) -> void; diff --git a/higan/sfc/cpu/cpu.cpp b/higan/sfc/cpu/cpu.cpp index bcc30f46..a7677eab 100644 --- a/higan/sfc/cpu/cpu.cpp +++ b/higan/sfc/cpu/cpu.cpp @@ -85,9 +85,9 @@ auto CPU::power(bool reset) -> void { if(n != 7) channels[n].next = channels[n + 1]; } + counter = {}; io = {}; alu = {}; - pipe = {}; status = {}; status.lineClocks = lineclocks(); @@ -97,8 +97,6 @@ auto CPU::power(bool reset) -> void { status.powerPending = reset == 0; status.resetPending = reset == 1; status.interruptPending = true; - - clockCounter = 0; } } diff --git a/higan/sfc/cpu/cpu.hpp b/higan/sfc/cpu/cpu.hpp index 2b3a12a4..9dc716ce 100644 --- a/higan/sfc/cpu/cpu.hpp +++ b/higan/sfc/cpu/cpu.hpp @@ -1,6 +1,7 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { inline auto interruptPending() const -> bool override { return status.interruptPending; } inline auto pio() const -> uint8 { return io.pio; } + inline auto refresh() const -> bool { return status.dramRefresh == 1; } inline auto synchronizing() const -> bool override { return scheduler.synchronizing(); } //cpu.cpp @@ -14,10 +15,6 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { inline auto hdmaEnable() -> bool; inline auto hdmaActive() -> bool; - inline auto dmaStep(uint clocks) -> void; - inline auto dmaFlush() -> void; - inline auto dmaWrite() -> void; - auto dmaRun() -> void; auto hdmaReset() -> void; auto hdmaSetup() -> void; @@ -27,7 +24,7 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { auto idle() -> void override; auto read(uint24 addr) -> uint8 override; auto write(uint24 addr, uint8 data) -> void override; - alwaysinline auto speed(uint24 addr) const -> uint; + alwaysinline auto wait(uint24 addr) const -> uint; auto readDisassembler(uint24 addr) -> uint8 override; //io.cpp @@ -41,6 +38,7 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { auto writeDMA(uint24 address, uint8 data) -> void; //timing.cpp + inline auto dmaClocks() const -> uint; inline auto dmaCounter() const -> uint; inline auto joypadCounter() const -> uint; @@ -72,7 +70,11 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter { private: uint version = 2; //allowed: 1, 2 - uint clockCounter; + + struct Counter { + uint cpu = 0; + uint dma = 0; + } counter; struct Status { uint clockCount = 0; @@ -81,7 +83,7 @@ private: bool irqLock = false; uint dramRefreshPosition = 0; - bool dramRefreshed = false; + uint dramRefresh = 0; //0 = not refreshed; 1 = refresh active; 2 = refresh inactive uint hdmaSetupPosition = 0; bool hdmaSetupTriggered = false; @@ -107,7 +109,6 @@ private: bool interruptPending = false; bool dmaActive = false; - uint dmaClocks = 0; bool dmaPending = false; bool hdmaPending = false; bool hdmaMode = 0; //0 = init, 1 = run @@ -167,15 +168,11 @@ private: //dma.cpp inline auto step(uint clocks) -> void; inline auto edge() -> void; - inline auto flush() -> void; - inline auto write() -> void; inline auto validA(uint24 address) -> bool; inline auto readA(uint24 address) -> uint8; - inline auto readA(uint24 address, bool valid) -> uint8; inline auto readB(uint8 address, bool valid) -> uint8; inline auto writeA(uint24 address, uint8 data) -> void; - inline auto writeA(uint24 address, uint8 data, bool valid) -> void; inline auto writeB(uint8 address, uint8 data, bool valid) -> void; inline auto transfer(uint24 address, uint2 index) -> void; @@ -237,12 +234,6 @@ private: Channel() : transferSize(0xffff) {} } channels[8]; - - struct Pipe { - uint1 valid; - uint24 address; - uint8 data; - } pipe; }; extern CPU cpu; diff --git a/higan/sfc/cpu/dma.cpp b/higan/sfc/cpu/dma.cpp index f456f406..a2ed19e4 100644 --- a/higan/sfc/cpu/dma.cpp +++ b/higan/sfc/cpu/dma.cpp @@ -1,18 +1,3 @@ -/* DMA timing: - The general idea is that DMA moves values between the A-bus and B-bus in parallel. - Obviously, a write can't happen at the same time as a read, as the read needs 8 cycles to complete. - My theory is that the accesses are staggered, like so: - - Cycle 0: read 0 - Cycle 1: read 1, write 0 - Cycle 2: read 2, write 1 - ... - Cycle n: read n, write n-1 - Cycle n+1: write n - - The staggered writes are implemented below using the pipe/flush concept. -*/ - auto CPU::dmaEnable() -> bool { for(auto& channel : channels) if(channel.dmaEnable) return true; return false; @@ -28,29 +13,10 @@ auto CPU::hdmaActive() -> bool { return false; } -auto CPU::dmaStep(uint clocks) -> void { - status.dmaClocks += clocks; - step(clocks); -} - -auto CPU::dmaFlush() -> void { - if(!pipe.valid) return; - pipe.valid = false; - bus.write(pipe.address, pipe.data); -} - -auto CPU::dmaWrite() -> void { - r.rwb = pipe.valid; - r.mar = pipe.address; - dmaStep(8); - dmaFlush(); -} - auto CPU::dmaRun() -> void { - dmaWrite(); + step(8); dmaEdge(); for(auto& channel : channels) channel.dmaRun(); - dmaFlush(); status.irqLock = true; } @@ -59,26 +25,22 @@ auto CPU::hdmaReset() -> void { } auto CPU::hdmaSetup() -> void { - dmaWrite(); + step(8); for(auto& channel : channels) channel.hdmaSetup(); - dmaFlush(); status.irqLock = true; } auto CPU::hdmaRun() -> void { - dmaWrite(); + step(8); for(auto& channel : channels) channel.hdmaTransfer(); for(auto& channel : channels) channel.hdmaAdvance(); - dmaFlush(); status.irqLock = true; } // -auto CPU::Channel::step(uint clocks) -> void { return cpu.dmaStep(clocks); } +auto CPU::Channel::step(uint clocks) -> void { return cpu.step(clocks); } auto CPU::Channel::edge() -> void { return cpu.dmaEdge(); } -auto CPU::Channel::flush() -> void { return cpu.dmaFlush(); } -auto CPU::Channel::write() -> void { return cpu.dmaWrite(); } auto CPU::Channel::validA(uint24 address) -> bool { //A-bus cannot access the B-bus or CPU I/O registers @@ -90,14 +52,9 @@ auto CPU::Channel::validA(uint24 address) -> bool { } auto CPU::Channel::readA(uint24 address) -> uint8 { - return readA(address, validA(address)); -} - -auto CPU::Channel::readA(uint24 address, bool valid) -> uint8 { step(4); - cpu.r.mdr = valid ? bus.read(address, cpu.r.mdr) : (uint8)0x00; + cpu.r.mdr = validA(address) ? bus.read(address, cpu.r.mdr) : (uint8)0x00; step(4); - flush(); return cpu.r.mdr; } @@ -105,24 +62,15 @@ auto CPU::Channel::readB(uint8 address, bool valid) -> uint8 { step(4); cpu.r.mdr = valid ? bus.read(0x2100 | address, cpu.r.mdr) : (uint8)0x00; step(4); - flush(); return cpu.r.mdr; } auto CPU::Channel::writeA(uint24 address, uint8 data) -> void { - return writeA(address, data, validA(address)); -} - -auto CPU::Channel::writeA(uint24 address, uint8 data, bool valid) -> void { - cpu.pipe.valid = valid; - cpu.pipe.address = address; - cpu.pipe.data = data; + if(validA(address)) bus.write(address, data); } auto CPU::Channel::writeB(uint8 address, uint8 data, bool valid) -> void { - cpu.pipe.valid = valid; - cpu.pipe.address = 0x2100 | address; - cpu.pipe.data = data; + if(valid) bus.write(0x2100 | address, data); } auto CPU::Channel::transfer(uint24 addressA, uint2 index) -> void { @@ -134,9 +82,8 @@ auto CPU::Channel::transfer(uint24 addressA, uint2 index) -> void { } //transfers from WRAM to WRAM are invalid - bool valid = addressB != 0x2180 || ((addressA & 0xfe0000) != 0x7e0000 && (addressA & 0x40e000) != 0x0000); + bool valid = addressB != 0x80 || ((addressA & 0xfe0000) != 0x7e0000 && (addressA & 0x40e000) != 0x0000); - cpu.r.rwb = 1; cpu.r.mar = addressA; if(direction == 0) { auto data = readA(addressA); @@ -150,6 +97,9 @@ auto CPU::Channel::transfer(uint24 addressA, uint2 index) -> void { auto CPU::Channel::dmaRun() -> void { if(!dmaEnable) return; + step(8); + edge(); + uint2 index = 0; do { transfer(sourceBank << 16 | sourceAddress, index++); @@ -157,8 +107,6 @@ auto CPU::Channel::dmaRun() -> void { edge(); } while(dmaEnable && --transferSize); - write(); - edge(); dmaEnable = false; } @@ -191,7 +139,6 @@ auto CPU::Channel::hdmaSetup() -> void { } auto CPU::Channel::hdmaReload() -> void { - cpu.r.rwb = 1; auto data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress); if((uint7)lineCounter == 0) { @@ -202,12 +149,10 @@ auto CPU::Channel::hdmaReload() -> void { hdmaDoTransfer = !hdmaCompleted; if(indirect) { - cpu.r.rwb = 1; data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++); indirectAddress = data << 8 | 0x00; //todo: should 0x00 be indirectAddress >> 8 ? if(hdmaCompleted && hdmaFinished()) return; - cpu.r.rwb = 1; data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++); indirectAddress = data << 8 | indirectAddress >> 8; } diff --git a/higan/sfc/cpu/memory.cpp b/higan/sfc/cpu/memory.cpp index 5b2735ae..d13577c7 100644 --- a/higan/sfc/cpu/memory.cpp +++ b/higan/sfc/cpu/memory.cpp @@ -1,36 +1,33 @@ auto CPU::idle() -> void { status.clockCount = 6; dmaEdge(); - r.rwb = 0; step(6); aluEdge(); } auto CPU::read(uint24 address) -> uint8 { - status.clockCount = speed(address); + status.clockCount = wait(address); dmaEdge(); - r.rwb = 1; r.mar = address; step(status.clockCount - 4); - auto data = bus.read(r.mar, r.mdr); + auto data = bus.read(address, r.mdr); step(4); aluEdge(); //$00-3f,80-bf:4000-43ff reads are internal to CPU, and do not update the MDR - if((r.mar & 0x40fc00) != 0x4000) r.mdr = data; + if((address & 0x40fc00) != 0x4000) r.mdr = data; return data; } auto CPU::write(uint24 address, uint8 data) -> void { aluEdge(); - status.clockCount = speed(address); + status.clockCount = wait(address); dmaEdge(); - r.rwb = 1; r.mar = address; step(status.clockCount); - bus.write(r.mar, r.mdr = data); + bus.write(address, r.mdr = data); } -auto CPU::speed(uint24 address) const -> uint { +auto CPU::wait(uint24 address) const -> uint { if(address & 0x408000) return address & 0x800000 ? io.romSpeed : 8; if(address + 0x6000 & 0x4000) return 8; if(address - 0x4000 & 0x7e00) return 6; diff --git a/higan/sfc/cpu/serialization.cpp b/higan/sfc/cpu/serialization.cpp index e010be4e..66e04b7e 100644 --- a/higan/sfc/cpu/serialization.cpp +++ b/higan/sfc/cpu/serialization.cpp @@ -6,7 +6,9 @@ auto CPU::serialize(serializer& s) -> void { s.array(wram); s.integer(version); - s.integer(clockCounter); + + s.integer(counter.cpu); + s.integer(counter.dma); s.integer(status.clockCount); s.integer(status.lineClocks); @@ -14,7 +16,7 @@ auto CPU::serialize(serializer& s) -> void { s.integer(status.irqLock); s.integer(status.dramRefreshPosition); - s.integer(status.dramRefreshed); + s.integer(status.dramRefresh); s.integer(status.hdmaSetupPosition); s.integer(status.hdmaSetupTriggered); @@ -40,7 +42,6 @@ auto CPU::serialize(serializer& s) -> void { s.integer(status.interruptPending); s.integer(status.dmaActive); - s.integer(status.dmaClocks); s.integer(status.dmaPending); s.integer(status.hdmaPending); s.integer(status.hdmaMode); @@ -102,8 +103,4 @@ auto CPU::serialize(serializer& s) -> void { s.integer(channel.hdmaCompleted); s.integer(channel.hdmaDoTransfer); } - - s.integer(pipe.valid); - s.integer(pipe.address); - s.integer(pipe.data); } diff --git a/higan/sfc/cpu/timing.cpp b/higan/sfc/cpu/timing.cpp index b75b010e..7b7788be 100644 --- a/higan/sfc/cpu/timing.cpp +++ b/higan/sfc/cpu/timing.cpp @@ -1,11 +1,27 @@ -auto CPU::dmaCounter() const -> uint { return clockCounter & 7; } -auto CPU::joypadCounter() const -> uint { return clockCounter & 255; } +//the number of clock cycles that have elapsed since (H)DMA began +auto CPU::dmaClocks() const -> uint { + if(counter.cpu >= counter.dma) { + return counter.cpu - counter.dma; + } else { + return 0 - counter.cpu + counter.dma; + } +} + +//DMA clock divider +auto CPU::dmaCounter() const -> uint { + return counter.cpu & 7; +} + +//joypad auto-poll clock divider +auto CPU::joypadCounter() const -> uint { + return counter.cpu & 255; +} auto CPU::step(uint clocks) -> void { status.irqLock = false; uint ticks = clocks >> 1; while(ticks--) { - clockCounter += 2; + counter.cpu += 2; tick(); if(hcounter() & 2) pollInterrupts(); if(joypadCounter() == 0) joypadEdge(); @@ -14,13 +30,14 @@ auto CPU::step(uint clocks) -> void { Thread::step(clocks); for(auto peripheral : peripherals) synchronize(*peripheral); - if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) { - status.dramRefreshed = true; - r.rwb = 0; - for(auto _ : range(5)) { - step(8); - aluEdge(); - } + if(!status.dramRefresh && hcounter() >= status.dramRefreshPosition) { + //note: pattern should technically be 5-3, 5-3, 5-3, 5-3, 5-3 per logic analyzer + //result averages out the same as no coprocessor polls refresh() at > frequency()/2 + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); + status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge(); } if(configuration.hacks.coprocessors.delayedSync) return; @@ -46,7 +63,7 @@ auto CPU::scanline() -> void { //DRAM refresh occurs once every scanline if(version == 2) status.dramRefreshPosition = 530 + 8 - dmaCounter(); - status.dramRefreshed = false; + status.dramRefresh = 0; //HDMA triggers once every visible scanline if(vcounter() < ppu.vdisp()) { @@ -88,13 +105,12 @@ auto CPU::dmaEdge() -> void { status.hdmaPending = false; if(hdmaEnable()) { if(!dmaEnable()) { - r.rwb = 0; - dmaStep(8 - dmaCounter()); + counter.dma = counter.cpu; + step(8 - dmaCounter()); } status.hdmaMode == 0 ? hdmaSetup() : hdmaRun(); if(!dmaEnable()) { - r.rwb = 0; //unverified - step(status.clockCount - (status.dmaClocks % status.clockCount)); + step(status.clockCount - dmaClocks() % status.clockCount); status.dmaActive = false; } } @@ -103,11 +119,10 @@ auto CPU::dmaEdge() -> void { if(status.dmaPending) { status.dmaPending = false; if(dmaEnable()) { - r.rwb = 0; - dmaStep(8 - dmaCounter()); + counter.dma = counter.cpu; + step(8 - dmaCounter()); dmaRun(); - r.rwb = 0; //unverified - step(status.clockCount - (status.dmaClocks % status.clockCount)); + step(status.clockCount - dmaClocks() % status.clockCount); status.dmaActive = false; } } @@ -132,7 +147,6 @@ auto CPU::dmaEdge() -> void { if(!status.dmaActive) { if(status.dmaPending || status.hdmaPending) { - status.dmaClocks = 0; status.dmaActive = true; } } diff --git a/higan/sfc/memory/protectable.hpp b/higan/sfc/memory/protectable.hpp index 47034bc4..e0e1ff69 100644 --- a/higan/sfc/memory/protectable.hpp +++ b/higan/sfc/memory/protectable.hpp @@ -2,6 +2,7 @@ struct ProtectableMemory : Memory { inline auto reset() -> void override { delete[] self.data; self.data = nullptr; + self.size = 0; } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { diff --git a/higan/sfc/memory/readable.hpp b/higan/sfc/memory/readable.hpp index 9e958352..88d249ac 100644 --- a/higan/sfc/memory/readable.hpp +++ b/higan/sfc/memory/readable.hpp @@ -2,6 +2,7 @@ struct ReadableMemory : Memory { inline auto reset() -> void override { delete[] self.data; self.data = nullptr; + self.size = 0; } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { diff --git a/higan/sfc/memory/writable.hpp b/higan/sfc/memory/writable.hpp index dbac10d2..c11e676d 100644 --- a/higan/sfc/memory/writable.hpp +++ b/higan/sfc/memory/writable.hpp @@ -2,6 +2,7 @@ struct WritableMemory : Memory { inline auto reset() -> void override { delete[] self.data; self.data = nullptr; + self.size = 0; } inline auto allocate(uint size, uint8 fill = 0xff) -> void override { diff --git a/higan/target-bsnes/program/game-rom.cpp b/higan/target-bsnes/program/game-rom.cpp index f186e3a6..05216297 100644 --- a/higan/target-bsnes/program/game-rom.cpp +++ b/higan/target-bsnes/program/game-rom.cpp @@ -141,7 +141,7 @@ auto Program::openRomGameBoy(string name, vfs::file::mode mode) -> vfs::shared:: } if(name == "time.rtc") { - return vfs::fs::file::open(path("Saves", gameBoy.location, ".sav"), mode); + return vfs::fs::file::open(path("Saves", gameBoy.location, ".rtc"), mode); } return {}; diff --git a/nall/path.hpp b/nall/path.hpp index ed4d148c..8c416eb8 100644 --- a/nall/path.hpp +++ b/nall/path.hpp @@ -69,6 +69,12 @@ inline auto user() -> string { return result; } +// /home/username/Desktop/ +// c:/users/username/Desktop/ +inline auto desktop(string_view name = {}) -> string { + return {user(), "Desktop/", name}; +} + // /home/username/.local/share/ // ~/Library/Application Support/ // c:/users/username/appdata/roaming/ diff --git a/nall/platform.hpp b/nall/platform.hpp index 493611d9..bfe983f6 100644 --- a/nall/platform.hpp +++ b/nall/platform.hpp @@ -9,6 +9,8 @@ namespace Math { #if defined(PLATFORM_WINDOWS) #include + #include + #include #include #include #include diff --git a/nall/windows/guard.hpp b/nall/windows/guard.hpp index aec11d47..bb067d2f 100644 --- a/nall/windows/guard.hpp +++ b/nall/windows/guard.hpp @@ -26,6 +26,8 @@ #undef NALL_WINDOWS_GUARD_HPP #undef boolean +#undef far #undef interface +#undef near #endif diff --git a/ruby/ruby.cpp b/ruby/ruby.cpp index f392e7e9..ae0569e3 100644 --- a/ruby/ruby.cpp +++ b/ruby/ruby.cpp @@ -1,8 +1,3 @@ -#ifdef _WIN32 - #include - #include -#endif - #include using namespace nall; using namespace ruby; @@ -21,6 +16,7 @@ using namespace ruby; #include #include #elif defined(DISPLAY_WINDOWS) + #define far #include #endif diff --git a/ruby/video/cgl.cpp b/ruby/video/cgl.cpp index 5213cd89..90e92762 100644 --- a/ruby/video/cgl.cpp +++ b/ruby/video/cgl.cpp @@ -111,7 +111,7 @@ private: [view lockFocus]; - OpenGL::initialize(); + OpenGL::initialize(self.shader); int blocking = self.blocking; [[view openGLContext] setValues:&blocking forParameter:NSOpenGLCPSwapInterval];