mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
3d34517f3e
commit
c2d0ed4ca8
|
@ -28,7 +28,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
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 Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org/";
|
static const string Website = "https://byuu.org/";
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
#include "registers.cpp"
|
#include "registers.cpp"
|
||||||
|
#include "instruction.cpp"
|
||||||
#include "instructions.cpp"
|
#include "instructions.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ auto HG51B::wait(uint24 address) -> uint {
|
||||||
auto HG51B::main() -> void {
|
auto HG51B::main() -> void {
|
||||||
if(io.lock) return step(1);
|
if(io.lock) return step(1);
|
||||||
if(io.suspend.enable) return suspend();
|
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.dma.enable) return dma();
|
||||||
if(io.halt) return step(1);
|
if(io.halt) return step(1);
|
||||||
return execute();
|
return execute();
|
||||||
|
@ -37,55 +38,56 @@ auto HG51B::step(uint clocks) -> void {
|
||||||
} else {
|
} else {
|
||||||
io.bus.enable = 0;
|
io.bus.enable = 0;
|
||||||
io.bus.pending = 0;
|
io.bus.pending = 0;
|
||||||
if(io.bus.reading) io.bus.reading = 0, r.busData = read(io.bus.address);
|
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.busData);
|
if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.mdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HG51B::execute() -> void {
|
auto HG51B::execute() -> void {
|
||||||
uint24 address = io.cache.base + r.pb * 512;
|
if(!cache()) return halt();
|
||||||
if(io.cache.address[io.cache.page] != address) {
|
auto opcode = programRAM[io.cache.page][r.pc];
|
||||||
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];
|
|
||||||
advance();
|
advance();
|
||||||
|
|
||||||
step(1);
|
step(1);
|
||||||
instruction();
|
instructionTable[opcode]();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HG51B::advance() -> void {
|
auto HG51B::advance() -> void {
|
||||||
if(++r.pc == 0) {
|
if(++r.pc == 0) {
|
||||||
if(io.cache.page == 1) return halt();
|
if(io.cache.page == 1) return halt();
|
||||||
io.cache.page = 1;
|
io.cache.page = 1;
|
||||||
|
if(io.cache.lock[io.cache.page]) return halt();
|
||||||
r.pb = r.p;
|
r.pb = r.p;
|
||||||
|
if(!cache()) return halt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HG51B::suspend() -> void {
|
auto HG51B::suspend() -> void {
|
||||||
if(!io.suspend.duration) return step(1); //indefinite
|
if(!io.suspend.duration) return step(1); //indefinite
|
||||||
step(io.suspend.duration);
|
step(io.suspend.duration);
|
||||||
io.suspend.enable = 0;
|
|
||||||
io.suspend.duration = 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;
|
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;
|
io.cache.address[io.cache.page] = address;
|
||||||
for(uint offset : range(256)) {
|
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(0) = read(address++);
|
||||||
step(wait(address)); programRAM[io.cache.page][offset].byte(1) = 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 {
|
auto HG51B::dma() -> void {
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//Hitachi HG51B169 (HG51BS family/derivative?)
|
//Hitachi HG51B S169
|
||||||
|
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
struct HG51B {
|
struct HG51B {
|
||||||
|
//instruction.cpp
|
||||||
|
HG51B();
|
||||||
|
|
||||||
|
//hg51b.cpp
|
||||||
virtual auto step(uint clocks) -> void;
|
virtual auto step(uint clocks) -> void;
|
||||||
virtual auto isROM(uint24 address) -> bool = 0;
|
virtual auto isROM(uint24 address) -> bool = 0;
|
||||||
virtual auto isRAM(uint24 address) -> bool = 0;
|
virtual auto isRAM(uint24 address) -> bool = 0;
|
||||||
|
@ -17,49 +21,115 @@ struct HG51B {
|
||||||
auto execute() -> void;
|
auto execute() -> void;
|
||||||
auto advance() -> void;
|
auto advance() -> void;
|
||||||
auto suspend() -> void;
|
auto suspend() -> void;
|
||||||
auto cache() -> void;
|
auto cache() -> bool;
|
||||||
auto dma() -> void;
|
auto dma() -> void;
|
||||||
auto running() const -> bool;
|
auto running() const -> bool;
|
||||||
auto busy() const -> bool;
|
auto busy() const -> bool;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto serialize(serializer&) -> void;
|
|
||||||
|
|
||||||
uint16 programRAM[2][256];
|
//instructions.cpp
|
||||||
uint24 dataROM[1024];
|
|
||||||
uint8 dataRAM[3072];
|
|
||||||
|
|
||||||
protected:
|
|
||||||
auto push() -> void;
|
auto push() -> void;
|
||||||
auto pull() -> void;
|
auto pull() -> void;
|
||||||
auto sa() -> uint;
|
|
||||||
auto ri() -> uint;
|
auto algorithmADD(uint24 x, uint24 y) -> uint24;
|
||||||
auto np() -> void;
|
auto algorithmAND(uint24 x, uint24 y) -> uint24;
|
||||||
auto instruction() -> void;
|
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
|
//registers.cpp
|
||||||
auto readRegister(uint7 address) -> uint24;
|
auto readRegister(uint7 address) -> uint24;
|
||||||
auto writeRegister(uint7 address, uint24 data) -> void;
|
auto writeRegister(uint7 address, uint24 data) -> void;
|
||||||
|
|
||||||
|
protected:
|
||||||
struct Registers {
|
struct Registers {
|
||||||
uint16 p;
|
uint15 pb; //program bank
|
||||||
uint16 pb; //program bank
|
|
||||||
uint8 pc; //program counter
|
uint8 pc; //program counter
|
||||||
|
|
||||||
boolean n; //negative
|
boolean n; //negative
|
||||||
boolean z; //zero
|
boolean z; //zero
|
||||||
boolean c; //carry
|
boolean c; //carry
|
||||||
|
boolean v; //overflow
|
||||||
boolean i; //interrupt
|
boolean i; //interrupt
|
||||||
|
|
||||||
uint24 a; //accumulator
|
uint24 a; //accumulator
|
||||||
uint24 acch;
|
uint15 p; //page register
|
||||||
uint24 accl;
|
uint48 mul; //multiplier
|
||||||
uint24 busData;
|
uint24 mdr; //bus memory data register
|
||||||
uint24 romData;
|
uint24 rom; //data ROM data buffer
|
||||||
uint24 ramData;
|
uint24 ram; //data RAM data buffer
|
||||||
uint24 busAddress;
|
uint24 mar; //bus memory address register
|
||||||
uint24 ramAddress;
|
uint24 dpr; //data RAM address pointer
|
||||||
uint24 gpr[16];
|
uint24 gpr[16]; //general purpose registers
|
||||||
} r;
|
} r;
|
||||||
|
|
||||||
struct IO {
|
struct IO {
|
||||||
|
@ -83,9 +153,9 @@ protected:
|
||||||
uint1 enable;
|
uint1 enable;
|
||||||
uint1 page;
|
uint1 page;
|
||||||
uint1 lock[2];
|
uint1 lock[2];
|
||||||
uint24 address[2];
|
uint24 address[2]; //cache address is in bytes; so 24-bit
|
||||||
uint24 base;
|
uint24 base; //base address is also in bytes
|
||||||
uint16 pb;
|
uint15 pb;
|
||||||
uint8 pc;
|
uint8 pc;
|
||||||
} cache;
|
} cache;
|
||||||
|
|
||||||
|
@ -105,8 +175,8 @@ protected:
|
||||||
} bus;
|
} bus;
|
||||||
} io;
|
} io;
|
||||||
|
|
||||||
uint24 stack[8];
|
uint23 stack[8];
|
||||||
uint16 opcode;
|
function<void ()> instructionTable[65536];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,350 +24,327 @@ auto HG51B::pull() -> void {
|
||||||
r.pc = pc >> 0;
|
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};
|
auto HG51B::algorithmADD(uint24 x, uint24 y) -> uint24 {
|
||||||
return r.a << shift[opcode.bits(8,9)];
|
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::algorithmAND(uint24 x, uint24 y) -> uint24 {
|
||||||
auto HG51B::ri() -> uint {
|
x = x & y;
|
||||||
if(opcode.bit(10)) return opcode.bits(0,7);
|
r.n = x & 0x800000;
|
||||||
return readRegister(opcode.bits(0,7));
|
r.z = x == 0;
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//New-PC: determine jump target address; opcode.d9 = long jump flag (1 = yes)
|
auto HG51B::algorithmASR(uint24 a, uint5 s) -> uint24 {
|
||||||
auto HG51B::np() -> void {
|
if(s > 24) s = 0;
|
||||||
if(opcode.bit(9)) r.pb = r.p;
|
a = (int24)a >> s;
|
||||||
r.pc = opcode.bits(0,7);
|
r.n = a & 0x800000;
|
||||||
|
r.z = a == 0;
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HG51B::instruction() -> void {
|
auto HG51B::algorithmMUL(int24 x, int24 y) -> uint48 {
|
||||||
if((opcode & 0xffff) == 0x0000) {
|
return (int48)x * (int48)y;
|
||||||
//0000 0000 0000 0000
|
}
|
||||||
//nop
|
|
||||||
}
|
auto HG51B::algorithmOR(uint24 x, uint24 y) -> uint24 {
|
||||||
|
x = x | y;
|
||||||
else if((opcode & 0xdd00) == 0x0800) {
|
r.n = x & 0x800000;
|
||||||
//00.0 10.0 .... ....
|
r.z = x == 0;
|
||||||
//jump i
|
return x;
|
||||||
if(opcode & 0x2000) push();
|
}
|
||||||
np();
|
|
||||||
step(2);
|
auto HG51B::algorithmROR(uint24 a, uint5 s) -> uint24 {
|
||||||
}
|
if(s > 24) s = 0;
|
||||||
|
a = (a >> s) | (a << 24 - s);
|
||||||
else if((opcode & 0xdd00) == 0x0c00) {
|
r.n = a & 0x800000;
|
||||||
//00.0 11.0 .... ....
|
r.z = a == 0;
|
||||||
//jumpeq i
|
return a;
|
||||||
if(r.z) {
|
}
|
||||||
if(opcode & 0x2000) push();
|
|
||||||
np();
|
auto HG51B::algorithmSHL(uint24 a, uint5 s) -> uint24 {
|
||||||
step(2);
|
if(s > 24) s = 0;
|
||||||
}
|
a = a << s;
|
||||||
}
|
r.n = a & 0x800000;
|
||||||
|
r.z = a == 0;
|
||||||
else if((opcode & 0xdd00) == 0x1000) {
|
return a;
|
||||||
//00.1 00.0 .... ....
|
}
|
||||||
//jumpge i
|
|
||||||
if(r.c) {
|
auto HG51B::algorithmSHR(uint24 a, uint5 s) -> uint24 {
|
||||||
if(opcode & 0x2000) push();
|
if(s > 24) s = 0;
|
||||||
np();
|
a = a >> s;
|
||||||
step(2);
|
r.n = a & 0x800000;
|
||||||
}
|
r.z = a == 0;
|
||||||
}
|
return a;
|
||||||
|
}
|
||||||
else if((opcode & 0xdd00) == 0x1400) {
|
|
||||||
//00.1 01.0 .... ....
|
auto HG51B::algorithmSUB(uint24 x, uint24 y) -> uint24 {
|
||||||
//jumpmi i
|
int z = x - y;
|
||||||
if(r.n) {
|
r.n = z & 0x800000;
|
||||||
if(opcode & 0x2000) push();
|
r.z = (uint24)z == 0;
|
||||||
np();
|
r.c = z >= 0;
|
||||||
step(2);
|
r.v = ~(x ^ y) & (x ^ z) & 0x800000;
|
||||||
}
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xffff) == 0x1c00) {
|
auto HG51B::algorithmSX(uint24 x) -> uint24 {
|
||||||
//0001 1100 0000 0000
|
r.n = x & 0x800000;
|
||||||
//wait
|
r.z = x == 0;
|
||||||
if(io.bus.enable) step(io.bus.pending);
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xfffe) == 0x2500) {
|
auto HG51B::algorithmXNOR(uint24 x, uint24 y) -> uint24 {
|
||||||
//0010 0101 0000 000.
|
x = ~x ^ y;
|
||||||
//skiplt/skipge
|
r.n = x & 0x800000;
|
||||||
if(r.c == (opcode & 1)) {
|
r.z = x == 0;
|
||||||
advance();
|
return x;
|
||||||
step(1);
|
}
|
||||||
}
|
|
||||||
}
|
auto HG51B::algorithmXOR(uint24 x, uint24 y) -> uint24 {
|
||||||
|
x = x ^ y;
|
||||||
else if((opcode & 0xfffe) == 0x2600) {
|
r.n = x & 0x800000;
|
||||||
//0010 0110 0000 000.
|
r.z = x == 0;
|
||||||
//skipne/skipeq
|
return x;
|
||||||
if(r.z == (opcode & 1)) {
|
}
|
||||||
advance();
|
|
||||||
step(1);
|
//
|
||||||
}
|
|
||||||
}
|
auto HG51B::instructionADD(uint7 reg, uint5 shift) -> void {
|
||||||
|
r.a = algorithmADD(r.a << shift, readRegister(reg));
|
||||||
else if((opcode & 0xfffe) == 0x2700) {
|
}
|
||||||
//0010 0111 0000 000.
|
|
||||||
//skipmi/skippl
|
auto HG51B::instructionADD(uint8 imm, uint5 shift) -> void {
|
||||||
if(r.n == (opcode & 1)) {
|
r.a = algorithmADD(r.a << shift, imm);
|
||||||
advance();
|
}
|
||||||
step(1);
|
|
||||||
}
|
auto HG51B::instructionAND(uint7 reg, uint5 shift) -> void {
|
||||||
}
|
r.a = algorithmAND(r.a << shift, readRegister(reg));
|
||||||
|
}
|
||||||
else if((opcode & 0xffff) == 0x3c00) {
|
|
||||||
//0011 1100 0000 0000
|
auto HG51B::instructionAND(uint8 imm, uint5 shift) -> void {
|
||||||
//ret
|
r.a = algorithmAND(r.a << shift, imm);
|
||||||
pull();
|
}
|
||||||
step(2);
|
|
||||||
}
|
auto HG51B::instructionASR(uint7 reg) -> void {
|
||||||
|
r.a = algorithmASR(r.a, readRegister(reg));
|
||||||
else if((opcode & 0xffff) == 0x4000) {
|
}
|
||||||
//0100 0000 0000 0000
|
|
||||||
//???
|
auto HG51B::instructionASR(uint5 imm) -> void {
|
||||||
r.busAddress++;
|
r.a = algorithmASR(r.a, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xf800) == 0x4800) {
|
auto HG51B::instructionCLEAR() -> void {
|
||||||
//0100 1... .... ....
|
r.a = 0;
|
||||||
//cmpr a<<n,ri
|
r.p = 0;
|
||||||
int result = ri() - sa();
|
r.ram = 0;
|
||||||
r.n = result & 0x800000;
|
r.dpr = 0;
|
||||||
r.z = (uint24)result == 0;
|
}
|
||||||
r.c = result >= 0;
|
|
||||||
}
|
auto HG51B::instructionCMP(uint7 reg, uint5 shift) -> void {
|
||||||
|
algorithmSUB(r.a << shift, readRegister(reg));
|
||||||
else if((opcode & 0xf800) == 0x5000) {
|
}
|
||||||
//0101 0... .... ....
|
|
||||||
//cmp a<<n,ri
|
auto HG51B::instructionCMP(uint8 imm, uint5 shift) -> void {
|
||||||
int result = sa() - ri();
|
algorithmSUB(r.a << shift, imm);
|
||||||
r.n = result & 0x800000;
|
}
|
||||||
r.z = (uint24)result == 0;
|
|
||||||
r.c = result >= 0;
|
auto HG51B::instructionCMPR(uint7 reg, uint5 shift) -> void {
|
||||||
}
|
algorithmSUB(readRegister(reg), r.a << shift);
|
||||||
|
}
|
||||||
else if((opcode & 0xfb00) == 0x5900) {
|
|
||||||
//0101 1.01 .... ....
|
auto HG51B::instructionCMPR(uint8 imm, uint5 shift) -> void {
|
||||||
//sxb
|
algorithmSUB(imm, r.a << shift);
|
||||||
r.a = (int8)ri();
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionHALT() -> void {
|
||||||
else if((opcode & 0xfb00) == 0x5a00) {
|
halt();
|
||||||
//0101 1.10 .... ....
|
}
|
||||||
//sxw
|
|
||||||
r.a = (int16)ri();
|
auto HG51B::instructionINC(uint24& reg) -> void {
|
||||||
}
|
reg++;
|
||||||
|
}
|
||||||
else if((opcode & 0xfb00) == 0x6000) {
|
|
||||||
//0110 0.00 .... ....
|
auto HG51B::instructionJMP(uint8 data, uint1 far, const uint1& take) -> void {
|
||||||
//ld a,ri
|
if(!take) return;
|
||||||
r.a = ri();
|
if(far) r.pb = r.p;
|
||||||
}
|
r.pc = data;
|
||||||
|
step(2);
|
||||||
else if((opcode & 0xfb00) == 0x6100) {
|
}
|
||||||
//0110 0.01 .... ....
|
|
||||||
//ld bus,ri
|
auto HG51B::instructionJSR(uint8 data, uint1 far, const uint1& take) -> void {
|
||||||
r.busData = ri();
|
if(!take) return;
|
||||||
}
|
push();
|
||||||
|
if(far) r.pb = r.p;
|
||||||
else if((opcode & 0xfb00) == 0x6300) {
|
r.pc = data;
|
||||||
//0110 0.11 .... ....
|
step(2);
|
||||||
//ld p,ri
|
}
|
||||||
r.p = ri();
|
|
||||||
}
|
auto HG51B::instructionLD(uint24& out, uint7 reg) -> void {
|
||||||
|
out = readRegister(reg);
|
||||||
else if((opcode & 0xfb00) == 0x6800) {
|
}
|
||||||
//0110 1.00 .... ....
|
|
||||||
//rdraml
|
auto HG51B::instructionLD(uint15& out, uint4 reg) -> void {
|
||||||
uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0);
|
out = r.gpr[reg];
|
||||||
if(target < 0xc00) r.ramData.byte(0) = dataRAM[target];
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionLD(uint24& out, uint8 imm) -> void {
|
||||||
else if((opcode & 0xfb00) == 0x6900) {
|
out = imm;
|
||||||
//0110 1.01 .... ....
|
}
|
||||||
//rdramh
|
|
||||||
uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0);
|
auto HG51B::instructionLD(uint15& out, uint8 imm) -> void {
|
||||||
if(target < 0xc00) r.ramData.byte(1) = dataRAM[target];
|
out = imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xfb00) == 0x6a00) {
|
auto HG51B::instructionLDL(uint15& out, uint8 imm) -> void {
|
||||||
//0110 1.10 .... ....
|
out.bits(0,7) = imm;
|
||||||
//rdramb
|
}
|
||||||
uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0);
|
|
||||||
if(target < 0xc00) r.ramData.byte(2) = dataRAM[target];
|
auto HG51B::instructionLDH(uint15& out, uint7 imm) -> void {
|
||||||
}
|
out.bits(8,14) = imm;
|
||||||
|
}
|
||||||
else if((opcode & 0xffff) == 0x7000) {
|
|
||||||
//0111 0000 0000 0000
|
auto HG51B::instructionMUL(uint7 reg) -> void {
|
||||||
//rdrom
|
r.mul = algorithmMUL(r.a, readRegister(reg));
|
||||||
r.romData = dataROM[(uint10)r.a];
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionMUL(uint8 imm) -> void {
|
||||||
else if((opcode & 0xff00) == 0x7c00) {
|
r.mul = algorithmMUL(r.a, imm);
|
||||||
//0111 1100 .... ....
|
}
|
||||||
//ld pl,i
|
|
||||||
r.p.byte(0) = opcode.bits(0,7);
|
auto HG51B::instructionNOP() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xff00) == 0x7d00) {
|
auto HG51B::instructionOR(uint7 reg, uint5 shift) -> void {
|
||||||
//0111 1101 .... ....
|
r.a = algorithmOR(r.a << shift, readRegister(reg));
|
||||||
//ld ph,i
|
}
|
||||||
r.p.byte(1) = opcode.bits(0,7);
|
|
||||||
}
|
auto HG51B::instructionOR(uint8 imm, uint5 shift) -> void {
|
||||||
|
r.a = algorithmOR(r.a << shift, imm);
|
||||||
else if((opcode & 0xf800) == 0x8000) {
|
}
|
||||||
//1000 0... .... ....
|
|
||||||
//add a<<n,ri
|
auto HG51B::instructionRDRAM(uint2 byte, uint24& a) -> void {
|
||||||
int result = sa() + ri();
|
uint12 address = a;
|
||||||
r.a = result;
|
if(address >= 0xc00) address -= 0x400;
|
||||||
r.n = r.a & 0x800000;
|
r.ram.byte(byte) = dataRAM[address];
|
||||||
r.z = r.a == 0;
|
}
|
||||||
r.c = result > 0xffffff;
|
|
||||||
}
|
auto HG51B::instructionRDRAM(uint2 byte, uint8 imm) -> void {
|
||||||
|
uint12 address = r.dpr + imm;
|
||||||
else if((opcode & 0xf800) == 0x8800) {
|
if(address >= 0xc00) address -= 0x400;
|
||||||
//1000 1... .... ....
|
r.ram.byte(byte) = dataRAM[address];
|
||||||
//subr a<<n,ri
|
}
|
||||||
int result = ri() - sa();
|
|
||||||
r.a = result;
|
auto HG51B::instructionRDROM(uint24& reg) -> void {
|
||||||
r.n = r.a & 0x800000;
|
r.rom = dataROM[(uint10)reg];
|
||||||
r.z = r.a == 0;
|
}
|
||||||
r.c = result >= 0;
|
|
||||||
}
|
auto HG51B::instructionRDROM(uint10 imm) -> void {
|
||||||
|
r.rom = dataROM[imm];
|
||||||
else if((opcode & 0xf800) == 0x9000) {
|
}
|
||||||
//1001 0... .... ....
|
|
||||||
//sub a<<n,ri
|
auto HG51B::instructionROR(uint7 reg) -> void {
|
||||||
int result = sa() - ri();
|
r.a = algorithmROR(r.a, readRegister(reg));
|
||||||
r.a = result;
|
}
|
||||||
r.n = r.a & 0x800000;
|
|
||||||
r.z = r.a == 0;
|
auto HG51B::instructionROR(uint5 imm) -> void {
|
||||||
r.c = result >= 0;
|
r.a = algorithmROR(r.a, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xfb00) == 0x9800) {
|
auto HG51B::instructionRTS() -> void {
|
||||||
//1001 1.00 .... ....
|
pull();
|
||||||
//mul a,ri
|
step(2);
|
||||||
int64 x = (int24)r.a;
|
}
|
||||||
int64 y = (int24)ri();
|
|
||||||
x *= y;
|
auto HG51B::instructionSKIP(uint1 take, const uint1& flag) -> void {
|
||||||
r.accl = x >> 0ull;
|
if(flag != take) return;
|
||||||
r.acch = x >> 24ull;
|
advance();
|
||||||
r.n = r.acch & 0x800000;
|
step(1);
|
||||||
r.z = x == 0;
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionSHL(uint7 reg) -> void {
|
||||||
else if((opcode & 0xf800) == 0xa800) {
|
r.a = algorithmSHL(r.a, readRegister(reg));
|
||||||
//1010 1... .... ....
|
}
|
||||||
//xor a<<n,ri
|
|
||||||
r.a = sa() ^ ri();
|
auto HG51B::instructionSHL(uint5 imm) -> void {
|
||||||
r.n = r.a & 0x800000;
|
r.a = algorithmSHL(r.a, imm);
|
||||||
r.z = r.a == 0;
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionSHR(uint7 reg) -> void {
|
||||||
else if((opcode & 0xf800) == 0xb000) {
|
r.a = algorithmSHR(r.a, readRegister(reg));
|
||||||
//1011 0... .... ....
|
}
|
||||||
//and a<<n,ri
|
|
||||||
r.a = sa() & ri();
|
auto HG51B::instructionSHR(uint5 imm) -> void {
|
||||||
r.n = r.a & 0x800000;
|
r.a = algorithmSHR(r.a, imm);
|
||||||
r.z = r.a == 0;
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionST(uint7 reg, uint24& in) -> void {
|
||||||
else if((opcode & 0xf800) == 0xb800) {
|
writeRegister(reg, in);
|
||||||
//1011 1... .... ....
|
}
|
||||||
//or a<<n,ri
|
|
||||||
r.a = sa() | ri();
|
auto HG51B::instructionSUB(uint7 reg, uint5 shift) -> void {
|
||||||
r.n = r.a & 0x800000;
|
r.a = algorithmSUB(r.a << shift, readRegister(reg));
|
||||||
r.z = r.a == 0;
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionSUB(uint8 imm, uint5 shift) -> void {
|
||||||
else if((opcode & 0xfb00) == 0xc000) {
|
r.a = algorithmSUB(r.a << shift, imm);
|
||||||
//1100 0.00 .... ....
|
}
|
||||||
//shr a,ri
|
|
||||||
r.a = r.a >> ri();
|
auto HG51B::instructionSUBR(uint7 reg, uint5 shift) -> void {
|
||||||
r.n = r.a & 0x800000;
|
r.a = algorithmSUB(readRegister(reg), r.a << shift);
|
||||||
r.z = r.a == 0;
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionSUBR(uint8 imm, uint5 shift) -> void {
|
||||||
else if((opcode & 0xfb00) == 0xc800) {
|
r.a = algorithmSUB(imm, r.a << shift);
|
||||||
//1100 1.00 .... ....
|
}
|
||||||
//asr a,ri
|
|
||||||
r.a = (int24)r.a >> ri();
|
auto HG51B::instructionSWAP(uint24& a, uint4 reg) -> void {
|
||||||
r.n = r.a & 0x800000;
|
swap(a, r.gpr[reg]);
|
||||||
r.z = r.a == 0;
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionSXB() -> void {
|
||||||
else if((opcode & 0xfb00) == 0xd000) {
|
r.a = algorithmSX((int8)r.a);
|
||||||
//1101 0.00 .... ....
|
}
|
||||||
//ror a,ri
|
|
||||||
uint24 length = ri();
|
auto HG51B::instructionSXW() -> void {
|
||||||
r.a = (r.a >> length) | (r.a << (24 - length));
|
r.a = algorithmSX((int16)r.a);
|
||||||
r.n = r.a & 0x800000;
|
}
|
||||||
r.z = r.a == 0;
|
|
||||||
}
|
auto HG51B::instructionWAIT() -> void {
|
||||||
|
if(!io.bus.enable) return;
|
||||||
else if((opcode & 0xfb00) == 0xd800) {
|
return step(io.bus.pending);
|
||||||
//1101 1.00 .... ....
|
}
|
||||||
//shl a,ri
|
|
||||||
r.a = r.a << ri();
|
auto HG51B::instructionWRRAM(uint2 byte, uint24& a) -> void {
|
||||||
r.n = r.a & 0x800000;
|
uint12 address = a;
|
||||||
r.z = r.a == 0;
|
if(address >= 0xc00) address -= 0x400;
|
||||||
}
|
dataRAM[address] = r.ram.byte(byte);
|
||||||
|
}
|
||||||
else if((opcode & 0xff00) == 0xe000) {
|
|
||||||
//1110 0000 .... ....
|
auto HG51B::instructionWRRAM(uint2 byte, uint8 imm) -> void {
|
||||||
//st r,a
|
uint12 address = r.dpr + imm;
|
||||||
writeRegister(opcode & 0xff, r.a);
|
if(address >= 0xc00) address -= 0x400;
|
||||||
}
|
dataRAM[address] = r.ram.byte(byte);
|
||||||
|
}
|
||||||
else if((opcode & 0xff00) == 0xe100) {
|
|
||||||
//1110 0001 .... ....
|
auto HG51B::instructionXNOR(uint7 reg, uint5 shift) -> void {
|
||||||
//st r,bus
|
r.a = algorithmXNOR(r.a << shift, readRegister(reg));
|
||||||
writeRegister(opcode & 0xff, r.busData);
|
}
|
||||||
}
|
|
||||||
|
auto HG51B::instructionXNOR(uint8 imm, uint5 shift) -> void {
|
||||||
else if((opcode & 0xfb00) == 0xe800) {
|
r.a = algorithmXNOR(r.a << shift, imm);
|
||||||
//1110 1.00 .... ....
|
}
|
||||||
//wrraml
|
|
||||||
uint24 target = ri() + (opcode.bit(10) ? r.ramAddress : (uint24)0);
|
auto HG51B::instructionXOR(uint7 reg, uint5 shift) -> void {
|
||||||
if(target < 0xc00) dataRAM[target] = r.ramData.byte(0);
|
r.a = algorithmXOR(r.a << shift, readRegister(reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if((opcode & 0xfb00) == 0xe900) {
|
auto HG51B::instructionXOR(uint8 imm, uint5 shift) -> void {
|
||||||
//1110 1.01 .... ....
|
r.a = algorithmXOR(r.a << shift, imm);
|
||||||
//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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
auto HG51B::readRegister(uint7 address) -> uint24 {
|
auto HG51B::readRegister(uint7 address) -> uint24 {
|
||||||
switch(address) {
|
switch(address) {
|
||||||
case 0x00: return r.a;
|
case 0x01: return r.mul.bits(24,47);
|
||||||
case 0x01: return r.acch;
|
case 0x02: return r.mul.bits( 0,23);
|
||||||
case 0x02: return r.accl;
|
case 0x03: return r.mdr;
|
||||||
case 0x03: return r.busData;
|
case 0x08: return r.rom;
|
||||||
case 0x08: return r.romData;
|
case 0x0c: return r.ram;
|
||||||
case 0x0c: return r.ramData;
|
case 0x13: return r.mar;
|
||||||
case 0x13: return r.busAddress;
|
case 0x1c: return r.dpr;
|
||||||
case 0x1c: return r.ramAddress;
|
|
||||||
case 0x20: return r.pc;
|
case 0x20: return r.pc;
|
||||||
|
case 0x28: return r.p;
|
||||||
case 0x2e:
|
case 0x2e:
|
||||||
io.bus.enable = 1;
|
io.bus.enable = 1;
|
||||||
io.bus.reading = 1;
|
io.bus.reading = 1;
|
||||||
io.bus.pending = 1 + io.wait.rom;
|
io.bus.pending = 1 + io.wait.rom;
|
||||||
io.bus.address = r.busAddress;
|
io.bus.address = r.mar;
|
||||||
return 0x000000;
|
return 0x000000;
|
||||||
case 0x2f:
|
case 0x2f:
|
||||||
io.bus.enable = 1;
|
io.bus.enable = 1;
|
||||||
io.bus.reading = 1;
|
io.bus.reading = 1;
|
||||||
io.bus.pending = 1 + io.wait.ram;
|
io.bus.pending = 1 + io.wait.ram;
|
||||||
io.bus.address = r.busAddress;
|
io.bus.address = r.mar;
|
||||||
return 0x000000;
|
return 0x000000;
|
||||||
|
|
||||||
|
//constant registers
|
||||||
case 0x50: return 0x000000;
|
case 0x50: return 0x000000;
|
||||||
case 0x51: return 0xffffff;
|
case 0x51: return 0xffffff;
|
||||||
case 0x52: return 0x00ff00;
|
case 0x52: return 0x00ff00;
|
||||||
|
@ -37,6 +39,8 @@ auto HG51B::readRegister(uint7 address) -> uint24 {
|
||||||
case 0x5d: return 0xfeffff;
|
case 0x5d: return 0xfeffff;
|
||||||
case 0x5e: return 0x000100;
|
case 0x5e: return 0x000100;
|
||||||
case 0x5f: return 0x00feff;
|
case 0x5f: return 0x00feff;
|
||||||
|
|
||||||
|
//general purpose registers
|
||||||
case 0x60: case 0x70: return r.gpr[ 0];
|
case 0x60: case 0x70: return r.gpr[ 0];
|
||||||
case 0x61: case 0x71: return r.gpr[ 1];
|
case 0x61: case 0x71: return r.gpr[ 1];
|
||||||
case 0x62: case 0x72: return r.gpr[ 2];
|
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 0x6e: case 0x7e: return r.gpr[14];
|
||||||
case 0x6f: case 0x7f: return r.gpr[15];
|
case 0x6f: case 0x7f: return r.gpr[15];
|
||||||
}
|
}
|
||||||
return 0x000000;
|
|
||||||
|
return 0x000000; //verified
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HG51B::writeRegister(uint7 address, uint24 data) -> void {
|
auto HG51B::writeRegister(uint7 address, uint24 data) -> void {
|
||||||
switch(address) {
|
switch(address) {
|
||||||
case 0x00: r.a = data; return;
|
case 0x01: r.mul.bits(24,47) = data; return;
|
||||||
case 0x01: r.acch = data; return;
|
case 0x02: r.mul.bits( 0,23) = data; return;
|
||||||
case 0x02: r.accl = data; return;
|
case 0x03: r.mdr = data; return;
|
||||||
case 0x03: r.busData = data; return;
|
case 0x08: r.rom = data; return;
|
||||||
case 0x08: r.romData = data; return;
|
case 0x0c: r.ram = data; return;
|
||||||
case 0x0c: r.ramData = data; return;
|
case 0x13: r.mar = data; return;
|
||||||
case 0x13: r.busAddress = data; return;
|
case 0x1c: r.dpr = data; return;
|
||||||
case 0x1c: r.ramAddress = data; return;
|
|
||||||
case 0x20: r.pc = data; return;
|
case 0x20: r.pc = data; return;
|
||||||
|
case 0x28: r.p = data; return;
|
||||||
case 0x2e:
|
case 0x2e:
|
||||||
io.bus.enable = 1;
|
io.bus.enable = 1;
|
||||||
io.bus.writing = 1;
|
io.bus.writing = 1;
|
||||||
io.bus.pending = 1 + io.wait.rom;
|
io.bus.pending = 1 + io.wait.rom;
|
||||||
io.bus.address = r.busAddress;
|
io.bus.address = r.mar;
|
||||||
return;
|
return;
|
||||||
case 0x2f:
|
case 0x2f:
|
||||||
io.bus.enable = 1;
|
io.bus.enable = 1;
|
||||||
io.bus.writing = 1;
|
io.bus.writing = 1;
|
||||||
io.bus.pending = 1 + io.wait.ram;
|
io.bus.pending = 1 + io.wait.ram;
|
||||||
io.bus.address = r.busAddress;
|
io.bus.address = r.mar;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x60: case 0x70: r.gpr[ 0] = data; return;
|
case 0x60: case 0x70: r.gpr[ 0] = data; return;
|
||||||
case 0x61: case 0x71: r.gpr[ 1] = data; return;
|
case 0x61: case 0x71: r.gpr[ 1] = data; return;
|
||||||
case 0x62: case 0x72: r.gpr[ 2] = data; return;
|
case 0x62: case 0x72: r.gpr[ 2] = data; return;
|
||||||
|
|
|
@ -3,23 +3,23 @@ auto HG51B::serialize(serializer& s) -> void {
|
||||||
s.array(programRAM[1]);
|
s.array(programRAM[1]);
|
||||||
s.array(dataRAM);
|
s.array(dataRAM);
|
||||||
|
|
||||||
s.integer(r.p);
|
|
||||||
s.integer(r.pb);
|
s.integer(r.pb);
|
||||||
s.integer(r.pc);
|
s.integer(r.pc);
|
||||||
|
|
||||||
s.boolean(r.n);
|
s.boolean(r.n);
|
||||||
s.boolean(r.z);
|
s.boolean(r.z);
|
||||||
s.boolean(r.c);
|
s.boolean(r.c);
|
||||||
|
s.boolean(r.v);
|
||||||
s.boolean(r.i);
|
s.boolean(r.i);
|
||||||
|
|
||||||
s.integer(r.a);
|
s.integer(r.a);
|
||||||
s.integer(r.acch);
|
s.integer(r.p);
|
||||||
s.integer(r.accl);
|
s.integer(r.mul);
|
||||||
s.integer(r.busData);
|
s.integer(r.mdr);
|
||||||
s.integer(r.romData);
|
s.integer(r.rom);
|
||||||
s.integer(r.ramData);
|
s.integer(r.ram);
|
||||||
s.integer(r.busAddress);
|
s.integer(r.mar);
|
||||||
s.integer(r.ramAddress);
|
s.integer(r.dpr);
|
||||||
s.array(r.gpr);
|
s.array(r.gpr);
|
||||||
|
|
||||||
s.integer(io.lock);
|
s.integer(io.lock);
|
||||||
|
@ -54,5 +54,4 @@ auto HG51B::serialize(serializer& s) -> void {
|
||||||
s.integer(io.bus.address);
|
s.integer(io.bus.address);
|
||||||
|
|
||||||
s.array(stack);
|
s.array(stack);
|
||||||
s.integer(opcode);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ auto WDC65816::serialize(serializer& s) -> void {
|
||||||
s.integer(r.irq);
|
s.integer(r.irq);
|
||||||
s.integer(r.wai);
|
s.integer(r.wai);
|
||||||
s.integer(r.stp);
|
s.integer(r.stp);
|
||||||
s.integer(r.rwb);
|
|
||||||
s.integer(r.mar);
|
s.integer(r.mar);
|
||||||
s.integer(r.mdr);
|
s.integer(r.mdr);
|
||||||
s.integer(r.vector);
|
s.integer(r.vector);
|
||||||
|
|
|
@ -54,9 +54,9 @@ auto WDC65816::power() -> void {
|
||||||
P = 0x34;
|
P = 0x34;
|
||||||
EF = 1;
|
EF = 1;
|
||||||
|
|
||||||
|
r.irq = false;
|
||||||
r.wai = false;
|
r.wai = false;
|
||||||
r.stp = false;
|
r.stp = false;
|
||||||
r.rwb = false;
|
|
||||||
r.mar = 0x000000;
|
r.mar = 0x000000;
|
||||||
r.mdr = 0x00;
|
r.mdr = 0x00;
|
||||||
r.vector = 0xfffc; //reset vector address
|
r.vector = 0xfffc; //reset vector address
|
||||||
|
|
|
@ -252,7 +252,6 @@ struct WDC65816 {
|
||||||
bool irq = false; //IRQ pin (0 = low, 1 = trigger)
|
bool irq = false; //IRQ pin (0 = low, 1 = trigger)
|
||||||
bool wai = false; //raised during wai, cleared after interrupt triggered
|
bool wai = false; //raised during wai, cleared after interrupt triggered
|
||||||
bool stp = false; //raised during stp, never cleared
|
bool stp = false; //raised during stp, never cleared
|
||||||
bool rwb = false; //read/write pin
|
|
||||||
uint24 mar; //memory address register
|
uint24 mar; //memory address register
|
||||||
uint8 mdr; //memory data register
|
uint8 mdr; //memory data register
|
||||||
uint16 vector; //interrupt vector address
|
uint16 vector; //interrupt vector address
|
||||||
|
|
|
@ -302,7 +302,7 @@ auto Cartridge::loadSA1(Markup::Node node) -> void {
|
||||||
has.SA1 = true;
|
has.SA1 = true;
|
||||||
|
|
||||||
for(auto map : node.find("map")) {
|
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"]) {
|
if(auto mcu = node["mcu"]) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
auto SA1::BWRAM::conflict() const -> bool {
|
auto SA1::BWRAM::conflict() const -> bool {
|
||||||
if(configuration.hacks.coprocessors.delayedSync) return false;
|
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 & 0x40e000) == 0x006000) return true; //00-3f,80-bf:6000-7fff
|
||||||
if((cpu.r.mar & 0xf00000) == 0x400000) return true; //40-4f:0000-ffff
|
if((cpu.r.mar & 0xf00000) == 0x400000) return true; //40-4f:0000-ffff
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -6,25 +6,36 @@ auto SA1::dmaNormal() -> void {
|
||||||
uint16 target = mmio.dda++;
|
uint16 target = mmio.dda++;
|
||||||
|
|
||||||
if(mmio.sd == DMA::SourceROM && mmio.dd == DMA::DestBWRAM) {
|
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);
|
data = rom.readSA1(source, data);
|
||||||
bwram.write(target, data);
|
bwram.write(target, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mmio.sd == DMA::SourceROM && mmio.dd == DMA::DestIRAM) {
|
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);
|
data = rom.readSA1(source, data);
|
||||||
iram.write(target, data);
|
iram.write(target, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mmio.sd == DMA::SourceBWRAM && mmio.dd == DMA::DestIRAM) {
|
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);
|
data = bwram.read(source, data);
|
||||||
iram.write(target, data);
|
iram.write(target, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mmio.sd == DMA::SourceIRAM && mmio.dd == DMA::DestBWRAM) {
|
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);
|
data = iram.read(source, data);
|
||||||
bwram.write(target, data);
|
bwram.write(target, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
auto SA1::readIO(uint24 addr, uint8) -> uint8 {
|
auto SA1::readIOCPU(uint24 address, uint8 data) -> uint8 {
|
||||||
cpu.active() ? cpu.synchronize(sa1) : synchronize(cpu);
|
cpu.synchronize(sa1);
|
||||||
|
|
||||||
switch(0x2300 | addr.bits(0,7)) {
|
switch(0x2200 | address.bits(0,8)) {
|
||||||
|
|
||||||
//(SFR) S-CPU flag read
|
//(SFR) S-CPU flag read
|
||||||
case 0x2300: {
|
case 0x2300: {
|
||||||
|
@ -14,6 +14,21 @@ auto SA1::readIO(uint24 addr, uint8) -> uint8 {
|
||||||
return data;
|
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
|
//(CFR) SA-1 flag read
|
||||||
case 0x2301: {
|
case 0x2301: {
|
||||||
uint8 data;
|
uint8 data;
|
||||||
|
@ -80,20 +95,15 @@ auto SA1::readIO(uint24 addr, uint8) -> uint8 {
|
||||||
return data >> 8;
|
return data >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
//(VC) version code register
|
|
||||||
case 0x230e: {
|
|
||||||
return 0x23; //RF5A123
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return 0xff;
|
||||||
|
|
||||||
return 0x00;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::writeIO(uint24 addr, uint8 data) -> void {
|
auto SA1::writeIOCPU(uint24 address, uint8 data) -> void {
|
||||||
cpu.active() ? cpu.synchronize(sa1) : synchronize(cpu);
|
cpu.synchronize(sa1);
|
||||||
|
|
||||||
switch(0x2200 | addr.bits(0,7)) {
|
switch(0x2200 | address.bits(0,8)) {
|
||||||
|
|
||||||
//(CCNT) SA-1 control
|
//(CCNT) SA-1 control
|
||||||
case 0x2200: {
|
case 0x2200: {
|
||||||
|
@ -166,6 +176,70 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
case 0x2207: { mmio.civ = (mmio.civ & 0xff00) | data; return; }
|
case 0x2207: { mmio.civ = (mmio.civ & 0xff00) | data; return; }
|
||||||
case 0x2208: { mmio.civ = (data << 8) | (mmio.civ & 0xff); 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
|
//(SCNT) S-CPU control
|
||||||
case 0x2209: {
|
case 0x2209: {
|
||||||
mmio.cpu_irq = (data & 0x80);
|
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 0x2214: { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); return; }
|
||||||
case 0x2215: { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); 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
|
//(BMAP) SA-1 BW-RAM address mapping
|
||||||
case 0x2225: {
|
case 0x2225: {
|
||||||
mmio.sw46 = (data & 0x80);
|
mmio.sw46 = (data & 0x80);
|
||||||
|
@ -284,30 +324,12 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//(SWBE) S-CPU BW-RAM write enable
|
|
||||||
case 0x2226: {
|
|
||||||
mmio.swen = (data & 0x80);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//(CWBE) SA-1 BW-RAM write enable
|
//(CWBE) SA-1 BW-RAM write enable
|
||||||
case 0x2227: {
|
case 0x2227: {
|
||||||
mmio.cwen = (data & 0x80);
|
mmio.cwen = (data & 0x80);
|
||||||
return;
|
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
|
//(CIWP) SA-1 I-RAM write protection
|
||||||
case 0x222a: {
|
case 0x222a: {
|
||||||
mmio.ciwp = data;
|
mmio.ciwp = data;
|
||||||
|
@ -327,42 +349,8 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//(CDMA) character conversion DMA parameters
|
case 0x2231: case 0x2232: case 0x2233: case 0x2234: case 0x2235: case 0x2236: case 0x2237: {
|
||||||
case 0x2231: {
|
return writeIOShared(address, data);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//(DTC) DMA terminal counter
|
//(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
auto SA1::IRAM::conflict() const -> bool {
|
auto SA1::IRAM::conflict() const -> bool {
|
||||||
if(configuration.hacks.coprocessors.delayedSync) return false;
|
if(configuration.hacks.coprocessors.delayedSync) return false;
|
||||||
|
|
||||||
if(!cpu.r.rwb) return false;
|
if((cpu.r.mar & 0x40f800) == 0x003000) return cpu.refresh() == 0; //00-3f,80-bf:3000-37ff
|
||||||
if((cpu.r.mar & 0x40f800) == 0x003000) return true; //00-3f,80-bf:3000-37ff
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
auto SA1::idle() -> void {
|
auto SA1::idle() -> void {
|
||||||
r.rwb = 0;
|
step();
|
||||||
step(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//RTx, JMx, JSx
|
//RTx, JMx, JSx
|
||||||
auto SA1::idleJump() -> void {
|
auto SA1::idleJump() -> void {
|
||||||
//ROM access penalty cycle: does not apply to BWRAM or IRAM
|
//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
|
//Bxx
|
||||||
|
@ -15,118 +19,90 @@ auto SA1::idleBranch() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::read(uint24 address) -> uint8 {
|
auto SA1::read(uint24 address) -> uint8 {
|
||||||
r.rwb = 1;
|
|
||||||
r.mar = address;
|
r.mar = address;
|
||||||
uint8 data = r.mdr;
|
uint8 data = r.mdr;
|
||||||
|
|
||||||
//00-3f,80-bf:2200-23ff
|
if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff
|
||||||
if((address & 0x40fe00) == 0x002200) {
|
) {
|
||||||
step(2);
|
step();
|
||||||
return r.mdr = readIO(address, data);
|
return r.mdr = readIOSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:8000-ffff
|
if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|
||||||
if((address & 0x408000) == 0x008000) {
|
|| (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
|
||||||
step(rom.conflict() ? 4 : 2);
|
) {
|
||||||
|
step();
|
||||||
|
if(rom.conflict()) step();
|
||||||
return r.mdr = rom.readSA1(address, data);
|
return r.mdr = rom.readSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//c0-ff:0000-ffff
|
if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff
|
||||||
if((address & 0xc00000) == 0xc00000) {
|
|| (address & 0xf00000) == 0x400000 //40-4f:0000-ffff
|
||||||
step(rom.conflict() ? 4 : 2);
|
|| (address & 0xf00000) == 0x600000 //60-6f:0000-ffff
|
||||||
return r.mdr = rom.readSA1(address, data);
|
) {
|
||||||
}
|
step();
|
||||||
|
step();
|
||||||
//00-3f,80-bf:6000-7fff
|
if(bwram.conflict()) step();
|
||||||
if((address & 0x40e000) == 0x006000) {
|
if(bwram.conflict()) step();
|
||||||
step(bwram.conflict() ? 8 : 4);
|
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);
|
return r.mdr = bwram.readSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:0000-07ff
|
if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff
|
||||||
if((address & 0x40f800) == 0x000000) {
|
|| (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff
|
||||||
step(iram.conflict() ? 6 : 2);
|
) {
|
||||||
|
step();
|
||||||
|
if(iram.conflict()) step();
|
||||||
|
if(iram.conflict()) step();
|
||||||
return r.mdr = iram.readSA1(address, data);
|
return r.mdr = iram.readSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:3000-37ff
|
step();
|
||||||
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);
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::write(uint24 address, uint8 data) -> void {
|
auto SA1::write(uint24 address, uint8 data) -> void {
|
||||||
r.rwb = 1;
|
|
||||||
r.mar = address;
|
r.mar = address;
|
||||||
r.mdr = data;
|
r.mdr = data;
|
||||||
|
|
||||||
//00-3f,80-bf:2200-23ff
|
if((address & 0x40fe00) == 0x002200 //00-3f,80-bf:2200-23ff
|
||||||
if((address & 0x40fe00) == 0x002200) {
|
) {
|
||||||
step(2);
|
step();
|
||||||
return writeIO(address, data);
|
return writeIOSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:8000-ffff
|
if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|
||||||
if((address & 0x408000) == 0x008000) {
|
|| (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
|
||||||
step(rom.conflict() ? 4 : 2);
|
) {
|
||||||
|
step();
|
||||||
|
if(rom.conflict()) step();
|
||||||
return rom.writeSA1(address, data);
|
return rom.writeSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//c0-ff:0000-ffff
|
if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff
|
||||||
if((address & 0xc00000) == 0xc00000) {
|
|| (address & 0xf00000) == 0x400000 //40-4f:0000-ffff
|
||||||
step(rom.conflict() ? 4 : 2);
|
|| (address & 0xf00000) == 0x600000 //60-6f:0000-ffff
|
||||||
return rom.writeSA1(address, data);
|
) {
|
||||||
}
|
step();
|
||||||
|
step();
|
||||||
//00-3f,80-bf:6000-7fff
|
if(bwram.conflict()) step();
|
||||||
if((address & 0x40e000) == 0x006000) {
|
if(bwram.conflict()) step();
|
||||||
step(bwram.conflict() ? 8 : 4);
|
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);
|
return bwram.writeSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:0000-07ff
|
if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff
|
||||||
if((address & 0x40f800) == 0x000000) {
|
|| (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff
|
||||||
step(iram.conflict() ? 6 : 2);
|
) {
|
||||||
|
step();
|
||||||
|
if(iram.conflict()) step();
|
||||||
|
if(iram.conflict()) step();
|
||||||
return iram.writeSA1(address, data);
|
return iram.writeSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:3000-37ff
|
step();
|
||||||
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);
|
|
||||||
return;
|
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
|
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
||||||
//these ports.
|
//these ports.
|
||||||
auto SA1::readVBR(uint24 address, uint8 data) -> uint8 {
|
auto SA1::readVBR(uint24 address, uint8 data) -> uint8 {
|
||||||
//00-3f,80-bf:8000-ffff
|
if((address & 0x408000) == 0x008000 //00-3f,80-bf:8000-ffff
|
||||||
if((address & 0x408000) == 0x008000) {
|
|| (address & 0xc00000) == 0xc00000 //c0-ff:0000-ffff
|
||||||
|
) {
|
||||||
return rom.readSA1(address, data);
|
return rom.readSA1(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//c0-ff:0000-ffff
|
if((address & 0x40e000) == 0x006000 //00-3f,80-bf:6000-7fff
|
||||||
if((address & 0xc00000) == 0xc00000) {
|
|| (address & 0xf00000) == 0x400000 //40-4f:0000-ffff
|
||||||
return rom.readSA1(address, data);
|
) {
|
||||||
}
|
|
||||||
|
|
||||||
//00-3f,80-bf:6000-7fff
|
|
||||||
if((address & 0x40e000) == 0x006000) {
|
|
||||||
return bwram.read(address, data);
|
return bwram.read(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//40-4f:0000-ffff
|
if((address & 0x40f800) == 0x000000 //00-3f,80-bf:0000-07ff
|
||||||
if((address & 0xf00000) == 0x400000) {
|
|| (address & 0x40f800) == 0x003000 //00-3f,80-bf:3000-37ff
|
||||||
return bwram.read(address, data);
|
) {
|
||||||
}
|
|
||||||
|
|
||||||
//00-3f,80-bf:0000-07ff
|
|
||||||
if((address & 0x40f800) == 0x000000) {
|
|
||||||
return iram.read(address, data);
|
return iram.read(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//00-3f,80-bf:3000-37ff
|
return 0xff;
|
||||||
if((address & 0x40f800) == 0x003000) {
|
}
|
||||||
return iram.read(address, data);
|
|
||||||
}
|
auto SA1::readDisassembler(uint24 address) -> uint8 {
|
||||||
|
//TODO: this is a hack; SA1::read() advances the clock; whereas Bus::read() does not
|
||||||
return 0x00;
|
//the CPU and SA1 bus are identical for ROM, but have differences in BWRAM and IRAM
|
||||||
|
return bus.read(address, r.mdr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
auto SA1::ROM::conflict() const -> bool {
|
auto SA1::ROM::conflict() const -> bool {
|
||||||
if(configuration.hacks.coprocessors.delayedSync) return false;
|
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 & 0x408000) == 0x008000) return true; //00-3f,80-bf:8000-ffff
|
||||||
if((cpu.r.mar & 0xc00000) == 0xc00000) return true; //c0-ff:0000-ffff
|
if((cpu.r.mar & 0xc00000) == 0xc00000) return true; //c0-ff:0000-ffff
|
||||||
return false;
|
return false;
|
||||||
|
@ -55,7 +54,7 @@ auto SA1::ROM::readCPU(uint24 address, uint8 data) -> uint8 {
|
||||||
return read(sa1.mmio.fb << 20 | address & 0x0fffff);
|
return read(sa1.mmio.fb << 20 | address & 0x0fffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0x00;
|
return data; //unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::ROM::writeCPU(uint24 address, uint8 data) -> void {
|
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 {
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ auto SA1::main() -> void {
|
||||||
|
|
||||||
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
if(mmio.sa1_rdyb || mmio.sa1_resb) {
|
||||||
//SA-1 co-processor is asleep
|
//SA-1 co-processor is asleep
|
||||||
step(2);
|
step();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ auto SA1::main() -> void {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//print(disassemble(), "\n");
|
||||||
instruction();
|
instruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +83,8 @@ auto SA1::synchronizing() const -> bool {
|
||||||
return scheduler.synchronizing();
|
return scheduler.synchronizing();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SA1::step(uint clocks) -> void {
|
auto SA1::step() -> void {
|
||||||
Thread::step(clocks);
|
Thread::step(2);
|
||||||
synchronize(cpu);
|
synchronize(cpu);
|
||||||
|
|
||||||
//adjust counters:
|
//adjust counters:
|
||||||
|
@ -91,21 +92,23 @@ auto SA1::step(uint clocks) -> void {
|
||||||
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
|
//whereas MMIO register counters are in dots (4 clocks = 1 dot)
|
||||||
if(mmio.hvselb == 0) {
|
if(mmio.hvselb == 0) {
|
||||||
//HV timer
|
//HV timer
|
||||||
status.hcounter += clocks;
|
status.hcounter += 2;
|
||||||
while(status.hcounter >= 1364) {
|
if(status.hcounter >= 1364) {
|
||||||
status.hcounter -= 1364;
|
status.hcounter = 0;
|
||||||
if(++status.vcounter >= status.scanlines) status.vcounter = 0;
|
if(++status.vcounter >= status.scanlines) {
|
||||||
|
status.vcounter = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//linear timer
|
//linear timer
|
||||||
status.hcounter += clocks;
|
status.hcounter += 2;
|
||||||
status.vcounter += (status.hcounter >> 11);
|
status.vcounter += status.hcounter >> 11;
|
||||||
status.hcounter &= 0x07ff;
|
status.hcounter &= 0x07ff;
|
||||||
status.vcounter &= 0x01ff;
|
status.vcounter &= 0x01ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
//test counters for timer IRQ
|
//test counters for timer IRQ
|
||||||
switch((mmio.ven << 1) + (mmio.hen << 0)) {
|
switch(mmio.hen << 0 | mmio.ven << 1) {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
case 1: if(status.hcounter == mmio.hcnt << 2) triggerIRQ(); break;
|
case 1: if(status.hcounter == mmio.hcnt << 2) triggerIRQ(); break;
|
||||||
case 2: if(status.vcounter == mmio.vcnt && status.hcounter == 0) 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());
|
create(SA1::Enter, system.cpuFrequency());
|
||||||
|
|
||||||
bwram.dma = false;
|
bwram.dma = false;
|
||||||
for(auto addr : range(iram.size())) {
|
for(uint address : range(iram.size())) {
|
||||||
iram.write(addr, 0x00);
|
iram.write(address, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
status.counter = 0;
|
status.counter = 0;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//Super Accelerator 1
|
//Super Accelerator (SA-1)
|
||||||
|
|
||||||
struct SA1 : Processor::WDC65816, Thread {
|
struct SA1 : Processor::WDC65816, Thread {
|
||||||
//sa1.cpp
|
//sa1.cpp
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step() -> void;
|
||||||
auto interrupt() -> void override;
|
auto interrupt() -> void override;
|
||||||
|
|
||||||
alwaysinline auto triggerIRQ() -> void;
|
alwaysinline auto triggerIRQ() -> void;
|
||||||
|
@ -36,13 +36,17 @@ struct SA1 : Processor::WDC65816, Thread {
|
||||||
alwaysinline auto idle() -> void override;
|
alwaysinline auto idle() -> void override;
|
||||||
alwaysinline auto idleJump() -> void override;
|
alwaysinline auto idleJump() -> void override;
|
||||||
alwaysinline auto idleBranch() -> void override;
|
alwaysinline auto idleBranch() -> void override;
|
||||||
alwaysinline auto read(uint24 addr) -> uint8 override;
|
alwaysinline auto read(uint24 address) -> uint8 override;
|
||||||
alwaysinline auto write(uint24 addr, uint8 data) -> void override;
|
alwaysinline auto write(uint24 address, uint8 data) -> void override;
|
||||||
auto readVBR(uint24 addr, uint8 data = 0) -> uint8;
|
auto readVBR(uint24 address, uint8 data = 0) -> uint8;
|
||||||
|
auto readDisassembler(uint24 address) -> uint8 override;
|
||||||
|
|
||||||
//io.cpp
|
//io.cpp
|
||||||
auto readIO(uint24 addr, uint8 data) -> uint8;
|
auto readIOCPU(uint24 address, uint8 data) -> uint8;
|
||||||
auto writeIO(uint24 addr, uint8 data) -> void;
|
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
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
|
@ -85,9 +85,9 @@ auto CPU::power(bool reset) -> void {
|
||||||
if(n != 7) channels[n].next = channels[n + 1];
|
if(n != 7) channels[n].next = channels[n + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
counter = {};
|
||||||
io = {};
|
io = {};
|
||||||
alu = {};
|
alu = {};
|
||||||
pipe = {};
|
|
||||||
|
|
||||||
status = {};
|
status = {};
|
||||||
status.lineClocks = lineclocks();
|
status.lineClocks = lineclocks();
|
||||||
|
@ -97,8 +97,6 @@ auto CPU::power(bool reset) -> void {
|
||||||
status.powerPending = reset == 0;
|
status.powerPending = reset == 0;
|
||||||
status.resetPending = reset == 1;
|
status.resetPending = reset == 1;
|
||||||
status.interruptPending = true;
|
status.interruptPending = true;
|
||||||
|
|
||||||
clockCounter = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
||||||
inline auto interruptPending() const -> bool override { return status.interruptPending; }
|
inline auto interruptPending() const -> bool override { return status.interruptPending; }
|
||||||
inline auto pio() const -> uint8 { return io.pio; }
|
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(); }
|
inline auto synchronizing() const -> bool override { return scheduler.synchronizing(); }
|
||||||
|
|
||||||
//cpu.cpp
|
//cpu.cpp
|
||||||
|
@ -14,10 +15,6 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
||||||
inline auto hdmaEnable() -> bool;
|
inline auto hdmaEnable() -> bool;
|
||||||
inline auto hdmaActive() -> bool;
|
inline auto hdmaActive() -> bool;
|
||||||
|
|
||||||
inline auto dmaStep(uint clocks) -> void;
|
|
||||||
inline auto dmaFlush() -> void;
|
|
||||||
inline auto dmaWrite() -> void;
|
|
||||||
|
|
||||||
auto dmaRun() -> void;
|
auto dmaRun() -> void;
|
||||||
auto hdmaReset() -> void;
|
auto hdmaReset() -> void;
|
||||||
auto hdmaSetup() -> void;
|
auto hdmaSetup() -> void;
|
||||||
|
@ -27,7 +24,7 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
||||||
auto idle() -> void override;
|
auto idle() -> void override;
|
||||||
auto read(uint24 addr) -> uint8 override;
|
auto read(uint24 addr) -> uint8 override;
|
||||||
auto write(uint24 addr, uint8 data) -> void 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;
|
auto readDisassembler(uint24 addr) -> uint8 override;
|
||||||
|
|
||||||
//io.cpp
|
//io.cpp
|
||||||
|
@ -41,6 +38,7 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
||||||
auto writeDMA(uint24 address, uint8 data) -> void;
|
auto writeDMA(uint24 address, uint8 data) -> void;
|
||||||
|
|
||||||
//timing.cpp
|
//timing.cpp
|
||||||
|
inline auto dmaClocks() const -> uint;
|
||||||
inline auto dmaCounter() const -> uint;
|
inline auto dmaCounter() const -> uint;
|
||||||
inline auto joypadCounter() const -> uint;
|
inline auto joypadCounter() const -> uint;
|
||||||
|
|
||||||
|
@ -72,7 +70,11 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint version = 2; //allowed: 1, 2
|
uint version = 2; //allowed: 1, 2
|
||||||
uint clockCounter;
|
|
||||||
|
struct Counter {
|
||||||
|
uint cpu = 0;
|
||||||
|
uint dma = 0;
|
||||||
|
} counter;
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
uint clockCount = 0;
|
uint clockCount = 0;
|
||||||
|
@ -81,7 +83,7 @@ private:
|
||||||
bool irqLock = false;
|
bool irqLock = false;
|
||||||
|
|
||||||
uint dramRefreshPosition = 0;
|
uint dramRefreshPosition = 0;
|
||||||
bool dramRefreshed = false;
|
uint dramRefresh = 0; //0 = not refreshed; 1 = refresh active; 2 = refresh inactive
|
||||||
|
|
||||||
uint hdmaSetupPosition = 0;
|
uint hdmaSetupPosition = 0;
|
||||||
bool hdmaSetupTriggered = false;
|
bool hdmaSetupTriggered = false;
|
||||||
|
@ -107,7 +109,6 @@ private:
|
||||||
bool interruptPending = false;
|
bool interruptPending = false;
|
||||||
|
|
||||||
bool dmaActive = false;
|
bool dmaActive = false;
|
||||||
uint dmaClocks = 0;
|
|
||||||
bool dmaPending = false;
|
bool dmaPending = false;
|
||||||
bool hdmaPending = false;
|
bool hdmaPending = false;
|
||||||
bool hdmaMode = 0; //0 = init, 1 = run
|
bool hdmaMode = 0; //0 = init, 1 = run
|
||||||
|
@ -167,15 +168,11 @@ private:
|
||||||
//dma.cpp
|
//dma.cpp
|
||||||
inline auto step(uint clocks) -> void;
|
inline auto step(uint clocks) -> void;
|
||||||
inline auto edge() -> void;
|
inline auto edge() -> void;
|
||||||
inline auto flush() -> void;
|
|
||||||
inline auto write() -> void;
|
|
||||||
|
|
||||||
inline auto validA(uint24 address) -> bool;
|
inline auto validA(uint24 address) -> bool;
|
||||||
inline auto readA(uint24 address) -> uint8;
|
inline auto readA(uint24 address) -> uint8;
|
||||||
inline auto readA(uint24 address, bool valid) -> uint8;
|
|
||||||
inline auto readB(uint8 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) -> void;
|
||||||
inline auto writeA(uint24 address, uint8 data, bool valid) -> void;
|
|
||||||
inline auto writeB(uint8 address, uint8 data, bool valid) -> void;
|
inline auto writeB(uint8 address, uint8 data, bool valid) -> void;
|
||||||
inline auto transfer(uint24 address, uint2 index) -> void;
|
inline auto transfer(uint24 address, uint2 index) -> void;
|
||||||
|
|
||||||
|
@ -237,12 +234,6 @@ private:
|
||||||
|
|
||||||
Channel() : transferSize(0xffff) {}
|
Channel() : transferSize(0xffff) {}
|
||||||
} channels[8];
|
} channels[8];
|
||||||
|
|
||||||
struct Pipe {
|
|
||||||
uint1 valid;
|
|
||||||
uint24 address;
|
|
||||||
uint8 data;
|
|
||||||
} pipe;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -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 {
|
auto CPU::dmaEnable() -> bool {
|
||||||
for(auto& channel : channels) if(channel.dmaEnable) return true;
|
for(auto& channel : channels) if(channel.dmaEnable) return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -28,29 +13,10 @@ auto CPU::hdmaActive() -> bool {
|
||||||
return false;
|
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 {
|
auto CPU::dmaRun() -> void {
|
||||||
dmaWrite();
|
step(8);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
for(auto& channel : channels) channel.dmaRun();
|
for(auto& channel : channels) channel.dmaRun();
|
||||||
dmaFlush();
|
|
||||||
status.irqLock = true;
|
status.irqLock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,26 +25,22 @@ auto CPU::hdmaReset() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::hdmaSetup() -> void {
|
auto CPU::hdmaSetup() -> void {
|
||||||
dmaWrite();
|
step(8);
|
||||||
for(auto& channel : channels) channel.hdmaSetup();
|
for(auto& channel : channels) channel.hdmaSetup();
|
||||||
dmaFlush();
|
|
||||||
status.irqLock = true;
|
status.irqLock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::hdmaRun() -> void {
|
auto CPU::hdmaRun() -> void {
|
||||||
dmaWrite();
|
step(8);
|
||||||
for(auto& channel : channels) channel.hdmaTransfer();
|
for(auto& channel : channels) channel.hdmaTransfer();
|
||||||
for(auto& channel : channels) channel.hdmaAdvance();
|
for(auto& channel : channels) channel.hdmaAdvance();
|
||||||
dmaFlush();
|
|
||||||
status.irqLock = true;
|
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::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 {
|
auto CPU::Channel::validA(uint24 address) -> bool {
|
||||||
//A-bus cannot access the B-bus or CPU I/O registers
|
//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 {
|
auto CPU::Channel::readA(uint24 address) -> uint8 {
|
||||||
return readA(address, validA(address));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::Channel::readA(uint24 address, bool valid) -> uint8 {
|
|
||||||
step(4);
|
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);
|
step(4);
|
||||||
flush();
|
|
||||||
return cpu.r.mdr;
|
return cpu.r.mdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,24 +62,15 @@ auto CPU::Channel::readB(uint8 address, bool valid) -> uint8 {
|
||||||
step(4);
|
step(4);
|
||||||
cpu.r.mdr = valid ? bus.read(0x2100 | address, cpu.r.mdr) : (uint8)0x00;
|
cpu.r.mdr = valid ? bus.read(0x2100 | address, cpu.r.mdr) : (uint8)0x00;
|
||||||
step(4);
|
step(4);
|
||||||
flush();
|
|
||||||
return cpu.r.mdr;
|
return cpu.r.mdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::Channel::writeA(uint24 address, uint8 data) -> void {
|
auto CPU::Channel::writeA(uint24 address, uint8 data) -> void {
|
||||||
return writeA(address, data, validA(address));
|
if(validA(address)) bus.write(address, data);
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::Channel::writeA(uint24 address, uint8 data, bool valid) -> void {
|
|
||||||
cpu.pipe.valid = valid;
|
|
||||||
cpu.pipe.address = address;
|
|
||||||
cpu.pipe.data = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::Channel::writeB(uint8 address, uint8 data, bool valid) -> void {
|
auto CPU::Channel::writeB(uint8 address, uint8 data, bool valid) -> void {
|
||||||
cpu.pipe.valid = valid;
|
if(valid) bus.write(0x2100 | address, data);
|
||||||
cpu.pipe.address = 0x2100 | address;
|
|
||||||
cpu.pipe.data = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::Channel::transfer(uint24 addressA, uint2 index) -> void {
|
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
|
//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;
|
cpu.r.mar = addressA;
|
||||||
if(direction == 0) {
|
if(direction == 0) {
|
||||||
auto data = readA(addressA);
|
auto data = readA(addressA);
|
||||||
|
@ -150,6 +97,9 @@ auto CPU::Channel::transfer(uint24 addressA, uint2 index) -> void {
|
||||||
auto CPU::Channel::dmaRun() -> void {
|
auto CPU::Channel::dmaRun() -> void {
|
||||||
if(!dmaEnable) return;
|
if(!dmaEnable) return;
|
||||||
|
|
||||||
|
step(8);
|
||||||
|
edge();
|
||||||
|
|
||||||
uint2 index = 0;
|
uint2 index = 0;
|
||||||
do {
|
do {
|
||||||
transfer(sourceBank << 16 | sourceAddress, index++);
|
transfer(sourceBank << 16 | sourceAddress, index++);
|
||||||
|
@ -157,8 +107,6 @@ auto CPU::Channel::dmaRun() -> void {
|
||||||
edge();
|
edge();
|
||||||
} while(dmaEnable && --transferSize);
|
} while(dmaEnable && --transferSize);
|
||||||
|
|
||||||
write();
|
|
||||||
edge();
|
|
||||||
dmaEnable = false;
|
dmaEnable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +139,6 @@ auto CPU::Channel::hdmaSetup() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::Channel::hdmaReload() -> void {
|
auto CPU::Channel::hdmaReload() -> void {
|
||||||
cpu.r.rwb = 1;
|
|
||||||
auto data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress);
|
auto data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress);
|
||||||
|
|
||||||
if((uint7)lineCounter == 0) {
|
if((uint7)lineCounter == 0) {
|
||||||
|
@ -202,12 +149,10 @@ auto CPU::Channel::hdmaReload() -> void {
|
||||||
hdmaDoTransfer = !hdmaCompleted;
|
hdmaDoTransfer = !hdmaCompleted;
|
||||||
|
|
||||||
if(indirect) {
|
if(indirect) {
|
||||||
cpu.r.rwb = 1;
|
|
||||||
data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++);
|
data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++);
|
||||||
indirectAddress = data << 8 | 0x00; //todo: should 0x00 be indirectAddress >> 8 ?
|
indirectAddress = data << 8 | 0x00; //todo: should 0x00 be indirectAddress >> 8 ?
|
||||||
if(hdmaCompleted && hdmaFinished()) return;
|
if(hdmaCompleted && hdmaFinished()) return;
|
||||||
|
|
||||||
cpu.r.rwb = 1;
|
|
||||||
data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++);
|
data = readA(cpu.r.mar = sourceBank << 16 | hdmaAddress++);
|
||||||
indirectAddress = data << 8 | indirectAddress >> 8;
|
indirectAddress = data << 8 | indirectAddress >> 8;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,33 @@
|
||||||
auto CPU::idle() -> void {
|
auto CPU::idle() -> void {
|
||||||
status.clockCount = 6;
|
status.clockCount = 6;
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
r.rwb = 0;
|
|
||||||
step(6);
|
step(6);
|
||||||
aluEdge();
|
aluEdge();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::read(uint24 address) -> uint8 {
|
auto CPU::read(uint24 address) -> uint8 {
|
||||||
status.clockCount = speed(address);
|
status.clockCount = wait(address);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
r.rwb = 1;
|
|
||||||
r.mar = address;
|
r.mar = address;
|
||||||
step(status.clockCount - 4);
|
step(status.clockCount - 4);
|
||||||
auto data = bus.read(r.mar, r.mdr);
|
auto data = bus.read(address, r.mdr);
|
||||||
step(4);
|
step(4);
|
||||||
aluEdge();
|
aluEdge();
|
||||||
//$00-3f,80-bf:4000-43ff reads are internal to CPU, and do not update the MDR
|
//$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;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::write(uint24 address, uint8 data) -> void {
|
auto CPU::write(uint24 address, uint8 data) -> void {
|
||||||
aluEdge();
|
aluEdge();
|
||||||
status.clockCount = speed(address);
|
status.clockCount = wait(address);
|
||||||
dmaEdge();
|
dmaEdge();
|
||||||
r.rwb = 1;
|
|
||||||
r.mar = address;
|
r.mar = address;
|
||||||
step(status.clockCount);
|
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 & 0x408000) return address & 0x800000 ? io.romSpeed : 8;
|
||||||
if(address + 0x6000 & 0x4000) return 8;
|
if(address + 0x6000 & 0x4000) return 8;
|
||||||
if(address - 0x4000 & 0x7e00) return 6;
|
if(address - 0x4000 & 0x7e00) return 6;
|
||||||
|
|
|
@ -6,7 +6,9 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.array(wram);
|
s.array(wram);
|
||||||
|
|
||||||
s.integer(version);
|
s.integer(version);
|
||||||
s.integer(clockCounter);
|
|
||||||
|
s.integer(counter.cpu);
|
||||||
|
s.integer(counter.dma);
|
||||||
|
|
||||||
s.integer(status.clockCount);
|
s.integer(status.clockCount);
|
||||||
s.integer(status.lineClocks);
|
s.integer(status.lineClocks);
|
||||||
|
@ -14,7 +16,7 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.integer(status.irqLock);
|
s.integer(status.irqLock);
|
||||||
|
|
||||||
s.integer(status.dramRefreshPosition);
|
s.integer(status.dramRefreshPosition);
|
||||||
s.integer(status.dramRefreshed);
|
s.integer(status.dramRefresh);
|
||||||
|
|
||||||
s.integer(status.hdmaSetupPosition);
|
s.integer(status.hdmaSetupPosition);
|
||||||
s.integer(status.hdmaSetupTriggered);
|
s.integer(status.hdmaSetupTriggered);
|
||||||
|
@ -40,7 +42,6 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.integer(status.interruptPending);
|
s.integer(status.interruptPending);
|
||||||
|
|
||||||
s.integer(status.dmaActive);
|
s.integer(status.dmaActive);
|
||||||
s.integer(status.dmaClocks);
|
|
||||||
s.integer(status.dmaPending);
|
s.integer(status.dmaPending);
|
||||||
s.integer(status.hdmaPending);
|
s.integer(status.hdmaPending);
|
||||||
s.integer(status.hdmaMode);
|
s.integer(status.hdmaMode);
|
||||||
|
@ -102,8 +103,4 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.integer(channel.hdmaCompleted);
|
s.integer(channel.hdmaCompleted);
|
||||||
s.integer(channel.hdmaDoTransfer);
|
s.integer(channel.hdmaDoTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.integer(pipe.valid);
|
|
||||||
s.integer(pipe.address);
|
|
||||||
s.integer(pipe.data);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
auto CPU::dmaCounter() const -> uint { return clockCounter & 7; }
|
//the number of clock cycles that have elapsed since (H)DMA began
|
||||||
auto CPU::joypadCounter() const -> uint { return clockCounter & 255; }
|
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 {
|
auto CPU::step(uint clocks) -> void {
|
||||||
status.irqLock = false;
|
status.irqLock = false;
|
||||||
uint ticks = clocks >> 1;
|
uint ticks = clocks >> 1;
|
||||||
while(ticks--) {
|
while(ticks--) {
|
||||||
clockCounter += 2;
|
counter.cpu += 2;
|
||||||
tick();
|
tick();
|
||||||
if(hcounter() & 2) pollInterrupts();
|
if(hcounter() & 2) pollInterrupts();
|
||||||
if(joypadCounter() == 0) joypadEdge();
|
if(joypadCounter() == 0) joypadEdge();
|
||||||
|
@ -14,13 +30,14 @@ auto CPU::step(uint clocks) -> void {
|
||||||
Thread::step(clocks);
|
Thread::step(clocks);
|
||||||
for(auto peripheral : peripherals) synchronize(*peripheral);
|
for(auto peripheral : peripherals) synchronize(*peripheral);
|
||||||
|
|
||||||
if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) {
|
if(!status.dramRefresh && hcounter() >= status.dramRefreshPosition) {
|
||||||
status.dramRefreshed = true;
|
//note: pattern should technically be 5-3, 5-3, 5-3, 5-3, 5-3 per logic analyzer
|
||||||
r.rwb = 0;
|
//result averages out the same as no coprocessor polls refresh() at > frequency()/2
|
||||||
for(auto _ : range(5)) {
|
status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge();
|
||||||
step(8);
|
status.dramRefresh = 1; step(6); status.dramRefresh = 2; step(2); aluEdge();
|
||||||
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;
|
if(configuration.hacks.coprocessors.delayedSync) return;
|
||||||
|
@ -46,7 +63,7 @@ auto CPU::scanline() -> void {
|
||||||
|
|
||||||
//DRAM refresh occurs once every scanline
|
//DRAM refresh occurs once every scanline
|
||||||
if(version == 2) status.dramRefreshPosition = 530 + 8 - dmaCounter();
|
if(version == 2) status.dramRefreshPosition = 530 + 8 - dmaCounter();
|
||||||
status.dramRefreshed = false;
|
status.dramRefresh = 0;
|
||||||
|
|
||||||
//HDMA triggers once every visible scanline
|
//HDMA triggers once every visible scanline
|
||||||
if(vcounter() < ppu.vdisp()) {
|
if(vcounter() < ppu.vdisp()) {
|
||||||
|
@ -88,13 +105,12 @@ auto CPU::dmaEdge() -> void {
|
||||||
status.hdmaPending = false;
|
status.hdmaPending = false;
|
||||||
if(hdmaEnable()) {
|
if(hdmaEnable()) {
|
||||||
if(!dmaEnable()) {
|
if(!dmaEnable()) {
|
||||||
r.rwb = 0;
|
counter.dma = counter.cpu;
|
||||||
dmaStep(8 - dmaCounter());
|
step(8 - dmaCounter());
|
||||||
}
|
}
|
||||||
status.hdmaMode == 0 ? hdmaSetup() : hdmaRun();
|
status.hdmaMode == 0 ? hdmaSetup() : hdmaRun();
|
||||||
if(!dmaEnable()) {
|
if(!dmaEnable()) {
|
||||||
r.rwb = 0; //unverified
|
step(status.clockCount - dmaClocks() % status.clockCount);
|
||||||
step(status.clockCount - (status.dmaClocks % status.clockCount));
|
|
||||||
status.dmaActive = false;
|
status.dmaActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,11 +119,10 @@ auto CPU::dmaEdge() -> void {
|
||||||
if(status.dmaPending) {
|
if(status.dmaPending) {
|
||||||
status.dmaPending = false;
|
status.dmaPending = false;
|
||||||
if(dmaEnable()) {
|
if(dmaEnable()) {
|
||||||
r.rwb = 0;
|
counter.dma = counter.cpu;
|
||||||
dmaStep(8 - dmaCounter());
|
step(8 - dmaCounter());
|
||||||
dmaRun();
|
dmaRun();
|
||||||
r.rwb = 0; //unverified
|
step(status.clockCount - dmaClocks() % status.clockCount);
|
||||||
step(status.clockCount - (status.dmaClocks % status.clockCount));
|
|
||||||
status.dmaActive = false;
|
status.dmaActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +147,6 @@ auto CPU::dmaEdge() -> void {
|
||||||
|
|
||||||
if(!status.dmaActive) {
|
if(!status.dmaActive) {
|
||||||
if(status.dmaPending || status.hdmaPending) {
|
if(status.dmaPending || status.hdmaPending) {
|
||||||
status.dmaClocks = 0;
|
|
||||||
status.dmaActive = true;
|
status.dmaActive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ struct ProtectableMemory : Memory {
|
||||||
inline auto reset() -> void override {
|
inline auto reset() -> void override {
|
||||||
delete[] self.data;
|
delete[] self.data;
|
||||||
self.data = nullptr;
|
self.data = nullptr;
|
||||||
|
self.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto allocate(uint size, uint8 fill = 0xff) -> void override {
|
inline auto allocate(uint size, uint8 fill = 0xff) -> void override {
|
||||||
|
|
|
@ -2,6 +2,7 @@ struct ReadableMemory : Memory {
|
||||||
inline auto reset() -> void override {
|
inline auto reset() -> void override {
|
||||||
delete[] self.data;
|
delete[] self.data;
|
||||||
self.data = nullptr;
|
self.data = nullptr;
|
||||||
|
self.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto allocate(uint size, uint8 fill = 0xff) -> void override {
|
inline auto allocate(uint size, uint8 fill = 0xff) -> void override {
|
||||||
|
|
|
@ -2,6 +2,7 @@ struct WritableMemory : Memory {
|
||||||
inline auto reset() -> void override {
|
inline auto reset() -> void override {
|
||||||
delete[] self.data;
|
delete[] self.data;
|
||||||
self.data = nullptr;
|
self.data = nullptr;
|
||||||
|
self.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto allocate(uint size, uint8 fill = 0xff) -> void override {
|
inline auto allocate(uint size, uint8 fill = 0xff) -> void override {
|
||||||
|
|
|
@ -141,7 +141,7 @@ auto Program::openRomGameBoy(string name, vfs::file::mode mode) -> vfs::shared::
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name == "time.rtc") {
|
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 {};
|
return {};
|
||||||
|
|
|
@ -69,6 +69,12 @@ inline auto user() -> string {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /home/username/Desktop/
|
||||||
|
// c:/users/username/Desktop/
|
||||||
|
inline auto desktop(string_view name = {}) -> string {
|
||||||
|
return {user(), "Desktop/", name};
|
||||||
|
}
|
||||||
|
|
||||||
// /home/username/.local/share/
|
// /home/username/.local/share/
|
||||||
// ~/Library/Application Support/
|
// ~/Library/Application Support/
|
||||||
// c:/users/username/appdata/roaming/
|
// c:/users/username/appdata/roaming/
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace Math {
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
#include <nall/windows/guard.hpp>
|
#include <nall/windows/guard.hpp>
|
||||||
|
#include <initguid.h>
|
||||||
|
#include <cguid.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#undef NALL_WINDOWS_GUARD_HPP
|
#undef NALL_WINDOWS_GUARD_HPP
|
||||||
|
|
||||||
#undef boolean
|
#undef boolean
|
||||||
|
#undef far
|
||||||
#undef interface
|
#undef interface
|
||||||
|
#undef near
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
#ifdef _WIN32
|
|
||||||
#include <initguid.h>
|
|
||||||
#include <cguid.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ruby/ruby.hpp>
|
#include <ruby/ruby.hpp>
|
||||||
using namespace nall;
|
using namespace nall;
|
||||||
using namespace ruby;
|
using namespace ruby;
|
||||||
|
@ -21,6 +16,7 @@ using namespace ruby;
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <nall/macos/guard.hpp>
|
#include <nall/macos/guard.hpp>
|
||||||
#elif defined(DISPLAY_WINDOWS)
|
#elif defined(DISPLAY_WINDOWS)
|
||||||
|
#define far
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ private:
|
||||||
|
|
||||||
[view lockFocus];
|
[view lockFocus];
|
||||||
|
|
||||||
OpenGL::initialize();
|
OpenGL::initialize(self.shader);
|
||||||
|
|
||||||
int blocking = self.blocking;
|
int blocking = self.blocking;
|
||||||
[[view openGLContext] setValues:&blocking forParameter:NSOpenGLCPSwapInterval];
|
[[view openGLContext] setValues:&blocking forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
|
Loading…
Reference in New Issue