Commit c2d0ed4c authored by Tim Allen's avatar Tim Allen

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 ROMROM, 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.
parent 3d34517f
Pipeline #29773745 failed with stage
in 12 minutes and 50 seconds
......@@ -28,7 +28,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.61";
static const string Version = "106.62";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";
......
......@@ -4,6 +4,7 @@
namespace Processor {
#include "registers.cpp"
#include "instruction.cpp"
#include "instructions.cpp"
#include "serialization.cpp"
......@@ -24,7 +25,7 @@ auto HG51B::wait(uint24 address) -> uint {
auto HG51B::main() -> void {
if(io.lock) return step(1);
if(io.suspend.enable) return suspend();
if(io.cache.enable) return cache();
if(io.cache.enable) return cache(), void();
if(io.dma.enable) return dma();
if(io.halt) return step(1);
return execute();
......@@ -37,55 +38,56 @@ auto HG51B::step(uint clocks) -> void {
} else {
io.bus.enable = 0;
io.bus.pending = 0;
if(io.bus.reading) io.bus.reading = 0, r.busData = read(io.bus.address);
if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.busData);
if(io.bus.reading) io.bus.reading = 0, r.mdr = read(io.bus.address);
if(io.bus.writing) io.bus.writing = 0, write(io.bus.address, r.mdr);
}
}
}
auto HG51B::execute() -> void {
uint24 address = io.cache.base + r.pb * 512;
if(io.cache.address[io.cache.page] != address) {
io.cache.page ^= 1;
if(io.cache.address[io.cache.page] != address) {
if(io.cache.lock[io.cache.page]) {
io.cache.page ^= 1;
if(io.cache.lock[io.cache.page]) return halt();
}
cache();
}
}
opcode = programRAM[io.cache.page][r.pc];
if(!cache()) return halt();
auto opcode = programRAM[io.cache.page][r.pc];
advance();
step(1);
instruction();
instructionTable[opcode]();
}
auto HG51B::advance() -> void {
if(++r.pc == 0) {
if(io.cache.page == 1) return halt();
io.cache.page = 1;
if(io.cache.lock[io.cache.page]) return halt();
r.pb = r.p;
if(!cache()) return halt();
}
}
auto HG51B::suspend() -> void {
if(!io.suspend.duration) return step(1); //indefinite
step(io.suspend.duration);
io.suspend.enable = 0;
io.suspend.duration = 0;
io.suspend.enable = 0;
}
auto HG51B::cache() -> void {
auto HG51B::cache() -> bool {
uint24 address = io.cache.base + r.pb * 512;
//try to use the current page ...
if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true;
//if it's not valid, try to use the other page ...
io.cache.page ^= 1;
if(io.cache.address[io.cache.page] == address) return io.cache.enable = 0, true;
//if it's not valid, try to load into the other page ...
if(io.cache.lock[io.cache.page]) io.cache.page ^= 1;
//if it's locked, try to load into the first page ...
if(io.cache.lock[io.cache.page]) return io.cache.enable = 0, false;
io.cache.address[io.cache.page] = address;
for(uint offset : range(256)) {
step(wait(address)); programRAM[io.cache.page][offset].byte(0) = read(address++);
step(wait(address)); programRAM[io.cache.page][offset].byte(1) = read(address++);
}
io.cache.enable = 0;
return io.cache.enable = 0, true;
}
auto HG51B::dma() -> void {
......
#pragma once
//Hitachi HG51B169 (HG51BS family/derivative?)
//Hitachi HG51B S169
namespace Processor {
struct HG51B {
//instruction.cpp
HG51B();
//hg51b.cpp
virtual auto step(uint clocks) -> void;
virtual auto isROM(uint24 address) -> bool = 0;
virtual auto isRAM(uint24 address) -> bool = 0;
......@@ -17,49 +21,115 @@ struct HG51B {
auto execute() -> void;
auto advance() -> void;
auto suspend() -> void;
auto cache() -> void;
auto cache() -> bool;
auto dma() -> void;
auto running() const -> bool;
auto busy() const -> bool;
auto power() -> void;
//instructions.cpp
auto push() -> void;
auto pull() -> void;
auto algorithmADD(uint24 x, uint24 y) -> uint24;
auto algorithmAND(uint24 x, uint24 y) -> uint24;
auto algorithmASR(uint24 a, uint5 s) -> uint24;
auto algorithmMUL(int24 x, int24 y) -> uint48;
auto algorithmOR(uint24 x, uint24 y) -> uint24;
auto algorithmROR(uint24 a, uint5 s) -> uint24;
auto algorithmSHL(uint24 a, uint5 s) -> uint24;
auto algorithmSHR(uint24 a, uint5 s) -> uint24;
auto algorithmSUB(uint24 x, uint24 y) -> uint24;
auto algorithmSX(uint24 x) -> uint24;
auto algorithmXNOR(uint24 x, uint24 y) -> uint24;
auto algorithmXOR(uint24 x, uint24 y) -> uint24;
auto instructionADD(uint7 reg, uint5 shift) -> void;
auto instructionADD(uint8 imm, uint5 shift) -> void;
auto instructionAND(uint7 reg, uint5 shift) -> void;
auto instructionAND(uint8 imm, uint5 shift) -> void;
auto instructionASR(uint7 reg) -> void;
auto instructionASR(uint5 imm) -> void;
auto instructionCLEAR() -> void;
auto instructionCMP(uint7 reg, uint5 shift) -> void;
auto instructionCMP(uint8 imm, uint5 shift) -> void;
auto instructionCMPR(uint7 reg, uint5 shift) -> void;
auto instructionCMPR(uint8 imm, uint5 shift) -> void;
auto instructionHALT() -> void;
auto instructionINC(uint24& reg) -> void;
auto instructionJMP(uint8 data, uint1 far, const uint1& take) -> void;
auto instructionJSR(uint8 data, uint1 far, const uint1& take) -> void;
auto instructionLD(uint24& out, uint7 reg) -> void;
auto instructionLD(uint15& out, uint4 reg) -> void;
auto instructionLD(uint24& out, uint8 imm) -> void;
auto instructionLD(uint15& out, uint8 imm) -> void;
auto instructionLDL(uint15& out, uint8 imm) -> void;
auto instructionLDH(uint15& out, uint7 imm) -> void;
auto instructionMUL(uint7 reg) -> void;
auto instructionMUL(uint8 imm) -> void;
auto instructionNOP() -> void;
auto instructionOR(uint7 reg, uint5 shift) -> void;
auto instructionOR(uint8 imm, uint5 shift) -> void;
auto instructionRDRAM(uint2 byte, uint24& a) -> void;
auto instructionRDRAM(uint2 byte, uint8 imm) -> void;
auto instructionRDROM(uint24& reg) -> void;
auto instructionRDROM(uint10 imm) -> void;
auto instructionROR(uint7 reg) -> void;
auto instructionROR(uint5 imm) -> void;
auto instructionRTS() -> void;
auto instructionSHL(uint7 reg) -> void;
auto instructionSHL(uint5 imm) -> void;
auto instructionSHR(uint7 reg) -> void;
auto instructionSHR(uint5 imm) -> void;
auto instructionSKIP(uint1 take, const uint1& flag) -> void;
auto instructionST(uint7 reg, uint24& in) -> void;
auto instructionSUB(uint7 reg, uint5 shift) -> void;
auto instructionSUB(uint8 imm, uint5 shift) -> void;
auto instructionSUBR(uint7 reg, uint5 shift) -> void;
auto instructionSUBR(uint8 imm, uint5 shift) -> void;
auto instructionSWAP(uint24& a, uint4 reg) -> void;
auto instructionSXB() -> void;
auto instructionSXW() -> void;
auto instructionWAIT() -> void;
auto instructionWRRAM(uint2 byte, uint24& a) -> void;
auto instructionWRRAM(uint2 byte, uint8 imm) -> void;
auto instructionXNOR(uint7 reg, uint5 shift) -> void;
auto instructionXNOR(uint8 imm, uint5 shift) -> void;
auto instructionXOR(uint7 reg, uint5 shift) -> void;
auto instructionXOR(uint8 imm, uint5 shift) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
uint16 programRAM[2][256];
uint16 programRAM[2][256]; //instruction cache
uint24 dataROM[1024];
uint8 dataRAM[3072];
protected:
auto push() -> void;
auto pull() -> void;
auto sa() -> uint;
auto ri() -> uint;
auto np() -> void;
auto instruction() -> void;
//registers.cpp
auto readRegister(uint7 address) -> uint24;
auto writeRegister(uint7 address, uint24 data) -> void;
protected:
struct Registers {
uint16 p;
uint16 pb; //program bank
uint15 pb; //program bank
uint8 pc; //program counter
boolean n; //negative
boolean z; //zero
boolean c; //carry
boolean v; //overflow
boolean i; //interrupt
uint24 a; //accumulator
uint24 acch;
uint24 accl;
uint24 busData;
uint24 romData;
uint24 ramData;
uint24 busAddress;
uint24 ramAddress;
uint24 gpr[16];
uint24 a; //accumulator
uint15 p; //page register
uint48 mul; //multiplier
uint24 mdr; //bus memory data register
uint24 rom; //data ROM data buffer
uint24 ram; //data RAM data buffer
uint24 mar; //bus memory address register
uint24 dpr; //data RAM address pointer
uint24 gpr[16]; //general purpose registers
} r;
struct IO {
......@@ -83,9 +153,9 @@ protected:
uint1 enable;
uint1 page;
uint1 lock[2];
uint24 address[2];
uint24 base;
uint16 pb;
uint24 address[2]; //cache address is in bytes; so 24-bit
uint24 base; //base address is also in bytes
uint15 pb;
uint8 pc;
} cache;
......@@ -105,8 +175,8 @@ protected:
} bus;
} io;
uint24 stack[8];
uint16 opcode;
uint23 stack[8];
function<void ()> instructionTable[65536];
};
}
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 .... ....");