Update to v106r62 release.

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.
This commit is contained in:
Tim Allen 2018-09-10 12:11:19 +10:00
parent 3d34517f3e
commit c2d0ed4ca8
34 changed files with 1446 additions and 791 deletions

View File

@ -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/";

View File

@ -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 {

View File

@ -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<void ()> instructionTable[65536];
};
}

View File

@ -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<uint16_t, bit::test(s)>::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<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("0100 10ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, CMPR, reg, shifts[shift]);
}
//CMPR A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("0100 11ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, CMPR, imm, shifts[shift]);
}
//CMP A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("0101 00ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, CMP, reg, shifts[shift]);
}
//CMP A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("0101 01ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, CMP, imm, shifts[shift]);
}
//???
for(uint8 null : range(256)) {
auto opcode = pattern("0101 1000 .... ....");
bind(opcode | null << 0, NOP);
}
//SXB A
for(uint8 null : range(256)) {
auto opcode = pattern("0101 1001 .... ....");
bind(opcode | null << 0, SXB);
}
//SXW A
for(uint8 null : range(256)) {
auto opcode = pattern("0101 1010 .... ....");
bind(opcode | null << 0, SXW);
}
//???
for(uint8 null : range(256)) {
auto opcode = pattern("0101 1011 .... ....");
bind(opcode | null << 0, NOP);
}
//???
for(uint10 null : range(1024)) {
auto opcode = pattern("0101 11.. .... ....");
bind(opcode | null << 0, NOP);
}
//LD A,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2)) {
auto opcode = pattern("0110 0000 .rrr rrrr");
bind(opcode | reg << 0 | null << 7, LD, r.a, reg);
}
//LD MDR,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2)) {
auto opcode = pattern("0110 0001 .rrr rrrr");
bind(opcode | reg << 0 | null << 7, LD, r.mdr, reg);
}
//LD MAR,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2)) {
auto opcode = pattern("0110 0010 .rrr rrrr");
bind(opcode | reg << 0 | null << 7, LD, r.mar, reg);
}
//LD P,reg
for(uint4 reg : range(16))
for(uint4 null : range(16)) {
auto opcode = pattern("0110 0011 .... rrrr");
bind(opcode | reg << 0 | null << 4, LD, r.p, reg);
}
//LD A,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 0100 iiii iiii");
bind(opcode | imm << 0, LD, r.a, imm);
}
//LD MDR,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 0101 iiii iiii");
bind(opcode | imm << 0, LD, r.mdr, imm);
}
//LD MAR,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 0110 iiii iiii");
bind(opcode | imm << 0, LD, r.mar, imm);
}
//LD P,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 0111 iiii iiii");
bind(opcode | imm << 0, LD, r.p, imm);
}
//RDRAM 0,A
for(uint8 null : range(256)) {
auto opcode = pattern("0110 1000 .... ....");
bind(opcode | null << 0, RDRAM, 0, r.a);
}
//RDRAM 1,A
for(uint8 null : range(256)) {
auto opcode = pattern("0110 1001 .... ....");
bind(opcode | null << 0, RDRAM, 1, r.a);
}
//RDRAM 2,A
for(uint8 null : range(256)) {
auto opcode = pattern("0110 1010 .... ....");
bind(opcode | null << 0, RDRAM, 2, r.a);
}
//???
for(uint8 null : range(256)) {
auto opcode = pattern("0110 1011 .... ....");
bind(opcode | null << 0, NOP);
}
//RDRAM 0,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 1100 iiii iiii");
bind(opcode | imm << 0, RDRAM, 0, imm);
}
//RDRAM 1,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 1101 iiii iiii");
bind(opcode | imm << 0, RDRAM, 1, imm);
}
//RDRAM 2,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0110 1110 iiii iiii");
bind(opcode | imm << 0, RDRAM, 2, imm);
}
//???
for(uint8 null : range(256)) {
auto opcode = pattern("0110 1111 .... ....");
bind(opcode | null << 0, NOP);
}
//RDROM A
for(uint10 null : range(1024)) {
auto opcode = pattern("0111 00.. .... ....");
bind(opcode | null << 0, RDROM, r.a);
}
//RDROM imm
for(uint10 imm : range(1024)) {
auto opcode = pattern("0111 01ii iiii iiii");
bind(opcode | imm << 0, RDROM, imm);
}
//???
for(uint10 null : range(1024)) {
auto opcode = pattern("0111 10.. .... ....");
bind(opcode | null << 0, NOP);
}
//LD PL,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("0111 1100 iiii iiii");
bind(opcode | imm << 0, LDL, r.p, imm);
}
//LD PH,imm
for(uint7 imm : range(128))
for(uint1 null : range( 2)) {
auto opcode = pattern("0111 1101 .iii iiii");
bind(opcode | imm << 0 | null << 7, LDH, r.p, imm);
}
//???
for(uint9 null : range(512)) {
auto opcode = pattern("0111 111. .... ....");
bind(opcode | null << 0, NOP);
}
//ADD A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1000 00ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, ADD, reg, shifts[shift]);
}
//ADD A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1000 01ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, ADD, imm, shifts[shift]);
}
//SUBR A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1000 10ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, SUBR, reg, shifts[shift]);
}
//SUBR A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1000 11ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, SUBR, imm, shifts[shift]);
}
//SUB A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1001 00ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, SUB, reg, shifts[shift]);
}
//SUB A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1001 01ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, SUB, imm, shifts[shift]);
}
//MUL reg
for(uint7 reg : range(128))
for(uint3 null : range( 8)) {
auto opcode = pattern("1001 10.. .rrr rrrr");
bind(opcode | reg << 0 | null << 7, MUL, reg);
}
//MUL imm
for(uint8 imm : range(256))
for(uint2 null : range( 4)) {
auto opcode = pattern("1001 11.. iiii iiii");
bind(opcode | imm << 0 | null << 8, MUL, imm);
}
//XNOR A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1010 00ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, XNOR, reg, shifts[shift]);
}
//XNOR A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1010 01ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, XNOR, imm, shifts[shift]);
}
//XOR A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1010 10ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, XOR, reg, shifts[shift]);
}
//XOR A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1010 11ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, XOR, imm, shifts[shift]);
}
//AND A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1011 00ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, AND, reg, shifts[shift]);
}
//AND A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1011 01ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, AND, imm, shifts[shift]);
}
//OR A<<s,reg
for(uint7 reg : range(128))
for(uint1 null : range( 2))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1011 10ss .rrr rrrr");
bind(opcode | reg << 0 | null << 7 | shift << 8, OR, reg, shifts[shift]);
}
//OR A<<s,imm
for(uint8 imm : range(256))
for(uint2 shift : range( 4)) {
auto opcode = pattern("1011 11ss iiii iiii");
bind(opcode | imm << 0 | shift << 8, OR, imm, shifts[shift]);
}
//SHR A,reg
for(uint7 reg : range(128))
for(uint3 null : range( 8)) {
auto opcode = pattern("1100 00.. .rrr rrrr");
bind(opcode | reg << 0 | null << 7, SHR, reg);
}
//SHR A,imm
for(uint5 imm : range(32))
for(uint5 null : range(32)) {
auto opcode = pattern("1100 01.. ...i iiii");
bind(opcode | imm << 0 | null << 5, SHR, imm);
}
//ASR A,reg
for(uint7 reg : range(128))
for(uint3 null : range( 8)) {
auto opcode = pattern("1100 10.. .rrr rrrr");
bind(opcode | reg << 0 | null << 7, ASR, reg);
}
//ASR A,imm
for(uint5 imm : range(32))
for(uint5 null : range(32)) {
auto opcode = pattern("1100 11.. ...i iiii");
bind(opcode | imm << 0 | null << 5, ASR, imm);
}
//ROR A,reg
for(uint7 reg : range(128))
for(uint3 null : range( 8)) {
auto opcode = pattern("1101 00.. .rrr rrrr");
bind(opcode | reg << 0 | null << 7, ROR, reg);
}
//ROR A,imm
for(uint5 imm : range(32))
for(uint5 null : range(32)) {
auto opcode = pattern("1101 01.. ...i iiii");
bind(opcode | imm << 0 | null << 5, ROR, imm);
}
//SHL A,reg
for(uint7 reg : range(128))
for(uint3 null : range( 8)) {
auto opcode = pattern("1101 10.. .rrr rrrr");
bind(opcode | reg << 0 | null << 7, SHL, reg);
}
//SHL A,imm
for(uint5 imm : range(32))
for(uint5 null : range(32)) {
auto opcode = pattern("1101 11.. ...i iiii");
bind(opcode | imm << 0 | null << 5, SHL, imm);
}
//ST reg,A
for(uint7 reg : range(128))
for(uint1 null : range( 2)) {
auto opcode = pattern("1110 0000 .rrr rrrr");
bind(opcode | reg << 0 | null << 7, ST, reg, r.a);
}
//ST reg,MDR
for(uint7 reg : range(128))
for(uint1 null : range( 2)) {
auto opcode = pattern("1110 0001 .rrr rrrr");
bind(opcode | reg << 0 | null << 7, ST, reg, r.mdr);
}
//???
for(uint9 null : range(512)) {
auto opcode = pattern("1110 001. .... ....");
bind(opcode | null << 0, NOP);
}
//???
for(uint10 null : range(1024)) {
auto opcode = pattern("1110 01.. .... ....");
bind(opcode | null << 0, NOP);
}
//WRRAM 0,A
for(uint8 null : range(256)) {
auto opcode = pattern("1110 1000 .... ....");
bind(opcode | null << 0, WRRAM, 0, r.a);
}
//WRRAM 1,A
for(uint8 null : range(256)) {
auto opcode = pattern("1110 1001 .... ....");
bind(opcode | null << 0, WRRAM, 1, r.a);
}
//WRRAM 2,A
for(uint8 null : range(256)) {
auto opcode = pattern("1110 1010 .... ....");
bind(opcode | null << 0, WRRAM, 2, r.a);
}
//???
for(uint8 null : range(256)) {
auto opcode = pattern("1110 1011 .... ....");
bind(opcode | null << 0, NOP);
}
//WRRAM 0,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("1110 1100 iiii iiii");
bind(opcode | imm << 0, WRRAM, 0, imm);
}
//WRRAM 1,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("1110 1101 iiii iiii");
bind(opcode | imm << 0, WRRAM, 1, imm);
}
//WRRAM 2,imm
for(uint8 imm : range(256)) {
auto opcode = pattern("1110 1110 iiii iiii");
bind(opcode | imm << 0, WRRAM, 2, imm);
}
//???
for(uint8 null : range(256)) {
auto opcode = pattern("1110 1111 .... ....");
bind(opcode | null << 0, NOP);
}
//SWAP A,Rn
for(uint4 reg : range(16))
for(uint6 null : range(64)) {
auto opcode = pattern("1111 00.. .... rrrr");
bind(opcode | reg << 0 | null << 4, SWAP, r.a, reg);
}
//???
for(uint10 null : range(1024)) {
auto opcode = pattern("1111 01.. .... ....");
bind(opcode | null << 0, NOP);
}
//CLEAR
for(uint10 null : range(1024)) {
auto opcode = pattern("1111 10.. .... ....");
bind(opcode | null << 0, CLEAR);
}
//HALT
for(uint10 null : range(1024)) {
auto opcode = pattern("1111 11.. .... ....");
bind(opcode | null << 0, HALT);
}
#undef bind
#undef pattern
for(uint opcode : range(65536)) {
if(!instructionTable[opcode]) throw;
}
}

View File

@ -24,350 +24,327 @@ auto HG51B::pull() -> 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<<n,ri
int result = ri() - sa();
r.n = result & 0x800000;
r.z = (uint24)result == 0;
r.c = result >= 0;
}
else if((opcode & 0xf800) == 0x5000) {
//0101 0... .... ....
//cmp a<<n,ri
int result = sa() - ri();
r.n = result & 0x800000;
r.z = (uint24)result == 0;
r.c = result >= 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<<n,ri
int result = sa() + ri();
r.a = result;
r.n = r.a & 0x800000;
r.z = r.a == 0;
r.c = result > 0xffffff;
}
else if((opcode & 0xf800) == 0x8800) {
//1000 1... .... ....
//subr a<<n,ri
int result = ri() - sa();
r.a = result;
r.n = r.a & 0x800000;
r.z = r.a == 0;
r.c = result >= 0;
}
else if((opcode & 0xf800) == 0x9000) {
//1001 0... .... ....
//sub a<<n,ri
int result = sa() - ri();
r.a = result;
r.n = r.a & 0x800000;
r.z = r.a == 0;
r.c = result >= 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<<n,ri
r.a = sa() ^ ri();
r.n = r.a & 0x800000;
r.z = r.a == 0;
}
else if((opcode & 0xf800) == 0xb000) {
//1011 0... .... ....
//and a<<n,ri
r.a = sa() & ri();
r.n = r.a & 0x800000;
r.z = r.a == 0;
}
else if((opcode & 0xf800) == 0xb800) {
//1011 1... .... ....
//or a<<n,ri
r.a = sa() | ri();
r.n = r.a & 0x800000;
r.z = r.a == 0;
}
else if((opcode & 0xfb00) == 0xc000) {
//1100 0.00 .... ....
//shr a,ri
r.a = r.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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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"]) {

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {};

View File

@ -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/

View File

@ -9,6 +9,8 @@ namespace Math {
#if defined(PLATFORM_WINDOWS)
#include <nall/windows/guard.hpp>
#include <initguid.h>
#include <cguid.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>

View File

@ -26,6 +26,8 @@
#undef NALL_WINDOWS_GUARD_HPP
#undef boolean
#undef far
#undef interface
#undef near
#endif

View File

@ -1,8 +1,3 @@
#ifdef _WIN32
#include <initguid.h>
#include <cguid.h>
#endif
#include <ruby/ruby.hpp>
using namespace nall;
using namespace ruby;
@ -21,6 +16,7 @@ using namespace ruby;
#include <Carbon/Carbon.h>
#include <nall/macos/guard.hpp>
#elif defined(DISPLAY_WINDOWS)
#define far
#include <mmsystem.h>
#endif

View File

@ -111,7 +111,7 @@ private:
[view lockFocus];
OpenGL::initialize();
OpenGL::initialize(self.shader);
int blocking = self.blocking;
[[view openGLContext] setValues:&blocking forParameter:NSOpenGLCPSwapInterval];