Update to v098r17 release.

byuu says:

Changelog:
- fixed Super Game Boy regression from v096r04 with bottom tile row
  flickering
- fixed GB STAT IRQ regression from previous WIP
  - Altered Space is now playable
  - GBVideoPlayer isn't; but nobody seems to know exactly what weird
    hardware quirk that one relies on to work
- ~3-4% speed improvement in SuperFX games by eliminating function<>
  callback on register assignments
  - most noticeable in Doom in-game; least noticeable on Yoshi's Island
    title screen (darn)
- finished GSU core and SuperFX coprocessor code cleanups
- did some more work cleaning up the LR35902 core and GB CPU code

Just a fair warning: don't get your hopes up on these GB
fixes. Cliffhanger now hangs completely (har har), and none of the
other bugs are fixed. We pretty much did all this work just for Altered
Space. So, I hope you like playing Altered Space.
This commit is contained in:
Tim Allen 2016-06-06 08:10:01 +10:00
parent 3681961ca5
commit 9b452c9f5f
29 changed files with 539 additions and 582 deletions

View File

@ -9,7 +9,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "098.16";
static const string Version = "098.17";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -14,10 +14,10 @@ auto CPU::Enter() -> void {
auto CPU::main() -> void {
interrupt_test();
exec();
instruction();
}
auto CPU::interrupt_raise(CPU::Interrupt id) -> void {
auto CPU::raise(CPU::Interrupt id) -> void {
if(id == Interrupt::Vblank) {
status.interrupt_request_vblank = 1;
if(status.interrupt_enable_vblank) r.halt = false;
@ -44,51 +44,35 @@ auto CPU::interrupt_raise(CPU::Interrupt id) -> void {
}
}
auto CPU::interrupt_lower(CPU::Interrupt id) -> void {
if(id == Interrupt::Stat) {
status.interrupt_request_stat = 0;
}
}
auto CPU::interrupt_test() -> void {
if(!r.ime) return;
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
status.interrupt_request_vblank = 0;
return interrupt_exec(0x0040);
return interrupt(0x0040);
}
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
status.interrupt_request_stat = 0;
return interrupt_exec(0x0048);
return interrupt(0x0048);
}
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
status.interrupt_request_timer = 0;
return interrupt_exec(0x0050);
return interrupt(0x0050);
}
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
status.interrupt_request_serial = 0;
return interrupt_exec(0x0058);
return interrupt(0x0058);
}
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
status.interrupt_request_joypad = 0;
return interrupt_exec(0x0060);
return interrupt(0x0060);
}
}
auto CPU::interrupt_exec(uint16 pc) -> void {
op_io();
op_io();
op_io();
r.ime = 0;
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
r[PC] = pc;
}
auto CPU::stop() -> bool {
if(status.speed_switch) {
status.speed_switch = 0;

View File

@ -3,10 +3,8 @@ struct CPU : Processor::LR35902, Thread, MMIO {
static auto Enter() -> void;
auto main() -> void;
auto interrupt_raise(Interrupt id) -> void;
auto interrupt_lower(Interrupt id) -> void;
auto raise(Interrupt id) -> void;
auto interrupt_test() -> void;
auto interrupt_exec(uint16 pc) -> void;
auto stop() -> bool;
auto power() -> void;
@ -19,9 +17,9 @@ struct CPU : Processor::LR35902, Thread, MMIO {
auto mmio_write(uint16 addr, uint8 data) -> void;
//memory.cpp
auto op_io() -> void;
auto op_read(uint16 addr) -> uint8;
auto op_write(uint16 addr, uint8 data) -> void;
auto io() -> void override;
auto read(uint16 addr) -> uint8 override;
auto write(uint16 addr, uint8 data) -> void override;
auto cycle_edge() -> void;
auto dma_read(uint16 addr) -> uint8;
auto dma_write(uint16 addr, uint8 data) -> void;

View File

@ -1,15 +1,15 @@
auto CPU::op_io() -> void {
auto CPU::io() -> void {
cycle_edge();
add_clocks(4);
}
auto CPU::op_read(uint16 addr) -> uint8 {
auto CPU::read(uint16 addr) -> uint8 {
cycle_edge();
add_clocks(4);
return bus.read(addr);
}
auto CPU::op_write(uint16 addr, uint8 data) -> void {
auto CPU::write(uint16 addr, uint8 data) -> void {
cycle_edge();
add_clocks(4);
bus.write(addr, data);

View File

@ -29,7 +29,7 @@ auto CPU::mmio_joyp_poll() -> void {
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
if(status.p15 == 0) status.joyp &= button ^ 0x0f;
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
if(status.joyp != 0x0f) raise(Interrupt::Joypad);
}
auto CPU::mmio_read(uint16 addr) -> uint8 {

View File

@ -3,9 +3,7 @@
// 154 scanlines/frame
auto CPU::add_clocks(uint clocks) -> void {
if(system.sgb()) system._clocksExecuted += clocks;
while(clocks--) {
for(auto n : range(clocks)) {
if(++status.clock == 0) {
cartridge.mbc3.second();
}
@ -25,14 +23,17 @@ auto CPU::add_clocks(uint clocks) -> void {
if(apu.clock < 0) co_switch(apu.thread);
}
if(system.sgb()) scheduler.exit(Scheduler::Event::Step);
if(system.sgb()) {
system._clocksExecuted += clocks;
scheduler.exit(Scheduler::Event::Step);
}
}
auto CPU::timer_262144hz() -> void {
if(status.timer_enable && status.timer_clock == 1) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
raise(Interrupt::Timer);
}
}
}
@ -41,7 +42,7 @@ auto CPU::timer_65536hz() -> void {
if(status.timer_enable && status.timer_clock == 2) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
raise(Interrupt::Timer);
}
}
}
@ -50,7 +51,7 @@ auto CPU::timer_16384hz() -> void {
if(status.timer_enable && status.timer_clock == 3) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
raise(Interrupt::Timer);
}
}
}
@ -59,7 +60,7 @@ auto CPU::timer_8192hz() -> void {
if(status.serial_transfer && status.serial_clock) {
if(--status.serial_bits == 0) {
status.serial_transfer = 0;
interrupt_raise(Interrupt::Serial);
raise(Interrupt::Serial);
}
}
}
@ -68,7 +69,7 @@ auto CPU::timer_4096hz() -> void {
if(status.timer_enable && status.timer_clock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
interrupt_raise(Interrupt::Timer);
raise(Interrupt::Timer);
}
}
}

View File

@ -37,6 +37,7 @@ auto PPU::cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) ->
auto PPU::cgb_scanline() -> void {
px = 0;
if(!enabled()) return;
const uint Height = (status.ob_size == 0 ? 8 : 16);
sprites = 0;
@ -68,7 +69,7 @@ auto PPU::cgb_run() -> void {
ob.priority = 0;
uint color = 0x7fff;
if(status.display_enable) {
if(enabled()) {
cgb_run_bg();
if(status.window_display_enable) cgb_run_window();
if(status.ob_enable) cgb_run_ob();

View File

@ -19,6 +19,7 @@ auto PPU::dmg_read_tile(bool select, uint x, uint y, uint& data) -> void {
auto PPU::dmg_scanline() -> void {
px = 0;
if(!enabled()) return;
const uint Height = (status.ob_size == 0 ? 8 : 16);
sprites = 0;
@ -59,7 +60,7 @@ auto PPU::dmg_run() -> void {
ob.palette = 0;
uint color = 0;
if(status.display_enable) {
if(enabled()) {
if(status.bg_enable) dmg_run_bg();
if(status.window_display_enable) dmg_run_window();
if(status.ob_enable) dmg_run_ob();

View File

@ -8,6 +8,8 @@ PPU ppu;
#include "cgb.cpp"
#include "serialization.cpp"
auto PPU::enabled() const -> bool { return status.display_enable; }
auto PPU::Enter() -> void {
while(true) scheduler.synchronize(), ppu.main();
}
@ -16,7 +18,7 @@ auto PPU::main() -> void {
status.lx = 0;
interface->lcdScanline(); //Super Game Boy notification
if(status.display_enable && status.ly <= 143) {
if(status.ly <= 143) {
mode(2);
scanline();
wait(92);
@ -28,7 +30,7 @@ auto PPU::main() -> void {
}
mode(0);
cpu.hblank();
if(enabled()) cpu.hblank();
wait(204);
} else {
mode(1);
@ -38,7 +40,7 @@ auto PPU::main() -> void {
status.ly++;
if(status.ly == 144) {
cpu.interrupt_raise(CPU::Interrupt::Vblank);
if(enabled()) cpu.raise(CPU::Interrupt::Vblank);
scheduler.exit(Scheduler::Event::Frame);
}
@ -48,35 +50,25 @@ auto PPU::main() -> void {
}
auto PPU::mode(uint mode) -> void {
if(!enabled()) mode = 1; //force blank
status.mode = mode;
}
auto PPU::stat() -> void {
bool irq = status.irq;
if(status.mode == 0) { //hblank
status.irq = status.interrupt_hblank;
}
status.irq = status.interrupt_hblank && status.mode == 0;
status.irq |= status.interrupt_vblank && status.mode == 1;
status.irq |= status.interrupt_oam && status.mode == 2;
status.irq |= status.interrupt_lyc && coincidence();
if(status.mode == 1) { //vblank
status.irq = status.interrupt_vblank || (status.interrupt_lyc && coincidence());
}
if(status.mode == 2) { //oam
status.irq = status.interrupt_oam || (status.interrupt_lyc && coincidence());
}
if(status.mode == 3) { //render
status.irq = false;
}
if(!irq && status.irq) {
cpu.interrupt_raise(CPU::Interrupt::Stat);
} else if(!status.irq) {
cpu.interrupt_lower(CPU::Interrupt::Stat);
}
if(!irq && status.irq) cpu.raise(CPU::Interrupt::Stat);
}
auto PPU::coincidence() -> bool {
//LYC of zero triggers on LYC=153
return (status.lyc && status.ly == status.lyc) || (!status.lyc && status.ly == 153);
uint ly = status.ly;
if(ly == 153 && status.lx >= 92) ly = 0; //LYC=0 triggers early during LY=153
return ly == status.lyc;
}
auto PPU::refresh() -> void {
@ -85,6 +77,7 @@ auto PPU::refresh() -> void {
auto PPU::wait(uint clocks) -> void {
while(clocks--) {
stat();
if(status.dma_active) {
uint hi = status.dma_clock++;
uint lo = hi & (cpu.status.speed_double ? 1 : 3);

View File

@ -1,7 +1,10 @@
struct PPU : Thread, MMIO {
auto enabled() const -> bool;
static auto Enter() -> void;
auto main() -> void;
auto mode(uint) -> void;
auto stat() -> void;
auto coincidence() -> bool;
auto refresh() -> void;
auto wait(uint clocks) -> void;

View File

@ -1,21 +1,14 @@
auto GSU::disassemble_opcode(char* output) -> void {
auto GSU::disassembleOpcode(char* output) -> void {
*output = 0;
if(!regs.sfr.alt2) {
if(!regs.sfr.alt1) {
disassemble_alt0(output);
} else {
disassemble_alt1(output);
}
} else {
if(!regs.sfr.alt1) {
disassemble_alt2(output);
} else {
disassemble_alt3(output);
}
switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) {
case 0: disassembleAlt0(output); break;
case 1: disassembleAlt1(output); break;
case 2: disassembleAlt2(output); break;
case 3: disassembleAlt3(output); break;
}
unsigned length = strlen(output);
uint length = strlen(output);
while(length++ < 20) strcat(output, " ");
}
@ -34,10 +27,10 @@ auto GSU::disassemble_opcode(char* output) -> void {
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
#define op0 regs.pipeline
#define op1 bus_read((regs.pbr << 16) + regs.r[15] + 0)
#define op2 bus_read((regs.pbr << 16) + regs.r[15] + 1)
#define op1 read((regs.pbr << 16) + regs.r[15] + 0)
#define op2 read((regs.pbr << 16) + regs.r[15] + 1)
auto GSU::disassemble_alt0(char* output) -> void {
auto GSU::disassembleAlt0(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
@ -94,7 +87,7 @@ auto GSU::disassemble_alt0(char* output) -> void {
strcat(output, t);
}
auto GSU::disassemble_alt1(char* output) -> void {
auto GSU::disassembleAlt1(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
@ -151,7 +144,7 @@ auto GSU::disassemble_alt1(char* output) -> void {
strcat(output, t);
}
auto GSU::disassemble_alt2(char* output) -> void {
auto GSU::disassembleAlt2(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
@ -208,7 +201,7 @@ auto GSU::disassemble_alt2(char* output) -> void {
strcat(output, t);
}
auto GSU::disassemble_alt3(char* output) -> void {
auto GSU::disassembleAlt3(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;

View File

@ -16,7 +16,11 @@ auto GSU::power() -> void {
}
auto GSU::reset() -> void {
for(auto& r : regs.r) r = 0x0000;
for(auto& r : regs.r) {
r.data = 0x0000;
r.modified = false;
}
regs.sfr = 0x0000;
regs.pbr = 0x00;
regs.rombr = 0x00;

View File

@ -13,15 +13,15 @@ struct GSU {
virtual auto rpix(uint8 x, uint8 y) -> uint8 = 0;
virtual auto pipe() -> uint8 = 0;
virtual auto rombuffer_sync() -> void = 0;
virtual auto rombuffer_read() -> uint8 = 0;
virtual auto rambuffer_sync() -> void = 0;
virtual auto rambuffer_read(uint16 addr) -> uint8 = 0;
virtual auto rambuffer_write(uint16 addr, uint8 data) -> void = 0;
virtual auto cache_flush() -> void = 0;
virtual auto syncROMBuffer() -> void = 0;
virtual auto readROMBuffer() -> uint8 = 0;
virtual auto syncRAMBuffer() -> void = 0;
virtual auto readRAMBuffer(uint16 addr) -> uint8 = 0;
virtual auto writeRAMBuffer(uint16 addr, uint8 data) -> void = 0;
virtual auto flushCache() -> void = 0;
virtual auto bus_read(uint24 addr, uint8 data = 0x00) -> uint8 = 0;
virtual auto bus_write(uint24 addr, uint8 data) -> void = 0;
virtual auto read(uint24 addr, uint8 data = 0x00) -> uint8 = 0;
virtual auto write(uint24 addr, uint8 data) -> void = 0;
//gsu.cpp
auto power() -> void;
@ -76,11 +76,11 @@ struct GSU {
auto serialize(serializer&) -> void;
//disassembler.cpp
auto disassemble_opcode(char* output) -> void;
auto disassemble_alt0(char* output) -> void;
auto disassemble_alt1(char* output) -> void;
auto disassemble_alt2(char* output) -> void;
auto disassemble_alt3(char* output) -> void;
auto disassembleOpcode(char* output) -> void;
auto disassembleAlt0(char* output) -> void;
auto disassembleAlt1(char* output) -> void;
auto disassembleAlt2(char* output) -> void;
auto disassembleAlt3(char* output) -> void;
};
}

View File

@ -18,7 +18,7 @@ auto GSU::op_nop() {
auto GSU::op_cache() {
if(regs.cbr != (regs.r[15] & 0xfff0)) {
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
flushCache();
}
regs.reset();
}
@ -80,8 +80,8 @@ auto GSU::op_with(uint n) {
//$30-3b(alt1) stb (rN)
auto GSU::op_store(uint n) {
regs.ramaddr = regs.r[n];
rambuffer_write(regs.ramaddr, regs.sr());
if(!regs.sfr.alt1) rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
writeRAMBuffer(regs.ramaddr, regs.sr());
if(!regs.sfr.alt1) writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8);
regs.reset();
}
@ -117,8 +117,8 @@ auto GSU::op_alt3() {
//$40-4b(alt1) ldb (rN)
auto GSU::op_load(uint n) {
regs.ramaddr = regs.r[n];
regs.dr() = rambuffer_read(regs.ramaddr);
if(!regs.sfr.alt1) regs.dr() |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.dr() = readRAMBuffer(regs.ramaddr);
if(!regs.sfr.alt1) regs.dr() |= readRAMBuffer(regs.ramaddr ^ 1) << 8;
regs.reset();
}
@ -230,8 +230,8 @@ auto GSU::op_mult_umult(uint n) {
//$90 sbk
auto GSU::op_sbk() {
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
writeRAMBuffer(regs.ramaddr ^ 0, regs.sr() >> 0);
writeRAMBuffer(regs.ramaddr ^ 1, regs.sr() >> 8);
regs.reset();
}
@ -278,7 +278,7 @@ auto GSU::op_jmp_ljmp(uint n) {
regs.pbr = regs.r[n] & 0x7f;
regs.r[15] = regs.sr();
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
flushCache();
}
regs.reset();
}
@ -310,12 +310,12 @@ auto GSU::op_fmult_lmult() {
auto GSU::op_ibt_lms_sms(uint n) {
if(regs.sfr.alt1) {
regs.ramaddr = pipe() << 1;
uint8 lo = rambuffer_read(regs.ramaddr ^ 0) << 0;
regs.r[n] = rambuffer_read(regs.ramaddr ^ 1) << 8 | lo;
uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0;
regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo;
} else if(regs.sfr.alt2) {
regs.ramaddr = pipe() << 1;
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0);
writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8);
} else {
regs.r[n] = (int8)pipe();
}
@ -369,12 +369,12 @@ auto GSU::op_inc(uint n) {
//$df(alt3) romb
auto GSU::op_getc_ramb_romb() {
if(!regs.sfr.alt2) {
regs.colr = color(rombuffer_read());
regs.colr = color(readROMBuffer());
} else if(!regs.sfr.alt1) {
rambuffer_sync();
syncRAMBuffer();
regs.rambr = regs.sr() & 0x01;
} else {
rombuffer_sync();
syncROMBuffer();
regs.rombr = regs.sr() & 0x7f;
}
regs.reset();
@ -394,10 +394,10 @@ auto GSU::op_dec(uint n) {
//$ef(alt3) getbs
auto GSU::op_getb() {
switch(regs.sfr.alt2 << 1 | regs.sfr.alt1 << 0) {
case 0: regs.dr() = rombuffer_read(); break;
case 1: regs.dr() = rombuffer_read() << 8 | (uint8)regs.sr(); break;
case 2: regs.dr() = (regs.sr() & 0xff00) | rombuffer_read(); break;
case 3: regs.dr() = (int8)rombuffer_read(); break;
case 0: regs.dr() = readROMBuffer(); break;
case 1: regs.dr() = readROMBuffer() << 8 | (uint8)regs.sr(); break;
case 2: regs.dr() = (regs.sr() & 0xff00) | readROMBuffer(); break;
case 3: regs.dr() = (int8)readROMBuffer(); break;
}
regs.reset();
}
@ -409,13 +409,13 @@ auto GSU::op_iwt_lm_sm(uint n) {
if(regs.sfr.alt1) {
regs.ramaddr = pipe() << 0;
regs.ramaddr |= pipe() << 8;
uint8 lo = rambuffer_read(regs.ramaddr ^ 0) << 0;
regs.r[n] = rambuffer_read(regs.ramaddr ^ 1) << 8 | lo;
uint8 lo = readRAMBuffer(regs.ramaddr ^ 0) << 0;
regs.r[n] = readRAMBuffer(regs.ramaddr ^ 1) << 8 | lo;
} else if(regs.sfr.alt2) {
regs.ramaddr = pipe() << 0;
regs.ramaddr |= pipe() << 8;
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
writeRAMBuffer(regs.ramaddr ^ 0, regs.r[n] >> 0);
writeRAMBuffer(regs.ramaddr ^ 1, regs.r[n] >> 8);
} else {
uint8 lo = pipe();
regs.r[n] = pipe() << 8 | lo;

View File

@ -1,41 +1,39 @@
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
struct reg16_t {
struct Register {
uint16 data = 0;
function<auto (uint16) -> void> modify;
bool modified = false;
inline operator unsigned() const {
inline operator uint() const {
return data;
}
inline auto assign(uint16 i) -> uint16 {
if(modify) modify(i);
else data = i;
return data;
inline auto assign(uint value) -> uint16 {
modified = true;
return data = value;
}
inline auto operator++() { return assign(data + 1); }
inline auto operator--() { return assign(data - 1); }
inline auto operator++(int) { unsigned r = data; assign(data + 1); return r; }
inline auto operator--(int) { unsigned r = data; assign(data - 1); return r; }
inline auto operator = (unsigned i) { return assign(i); }
inline auto operator |= (unsigned i) { return assign(data | i); }
inline auto operator ^= (unsigned i) { return assign(data ^ i); }
inline auto operator &= (unsigned i) { return assign(data & i); }
inline auto operator <<= (unsigned i) { return assign(data << i); }
inline auto operator >>= (unsigned i) { return assign(data >> i); }
inline auto operator += (unsigned i) { return assign(data + i); }
inline auto operator -= (unsigned i) { return assign(data - i); }
inline auto operator *= (unsigned i) { return assign(data * i); }
inline auto operator /= (unsigned i) { return assign(data / i); }
inline auto operator %= (unsigned i) { return assign(data % i); }
inline auto operator++(int) { uint r = data; assign(data + 1); return r; }
inline auto operator--(int) { uint r = data; assign(data - 1); return r; }
inline auto operator = (uint i) { return assign(i); }
inline auto operator |= (uint i) { return assign(data | i); }
inline auto operator ^= (uint i) { return assign(data ^ i); }
inline auto operator &= (uint i) { return assign(data & i); }
inline auto operator <<= (uint i) { return assign(data << i); }
inline auto operator >>= (uint i) { return assign(data >> i); }
inline auto operator += (uint i) { return assign(data + i); }
inline auto operator -= (uint i) { return assign(data - i); }
inline auto operator *= (uint i) { return assign(data * i); }
inline auto operator /= (uint i) { return assign(data / i); }
inline auto operator %= (uint i) { return assign(data % i); }
inline auto operator = (const reg16_t& i) { return assign(i); }
inline auto operator = (const Register& value) { return assign(value); }
reg16_t() = default;
reg16_t(const reg16_t&) = delete;
Register() = default;
Register(const Register&) = delete;
};
struct sfr_t {
struct SFR {
bool irq; //interrupt flag
bool b; //WITH flag
bool ih; //immediate higher 8-bit flag
@ -49,12 +47,12 @@ struct sfr_t {
bool cy; //carry flag
bool z; //zero flag
operator unsigned() const {
operator uint() const {
return (irq << 15) | (b << 12) | (ih << 11) | (il << 10) | (alt2 << 9) | (alt1 << 8)
| (r << 6) | (g << 5) | (ov << 4) | (s << 3) | (cy << 2) | (z << 1);
}
auto& operator=(uint16_t data) {
auto& operator=(uint data) {
irq = data & 0x8000;
b = data & 0x1000;
ih = data & 0x0800;
@ -71,17 +69,17 @@ struct sfr_t {
}
};
struct scmr_t {
unsigned ht;
struct SCMR {
uint ht;
bool ron;
bool ran;
unsigned md;
uint md;
operator unsigned() const {
operator uint() const {
return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md);
}
auto& operator=(uint8 data) {
auto& operator=(uint data) {
ht = (bool)(data & 0x20) << 1;
ht |= (bool)(data & 0x04) << 0;
ron = data & 0x10;
@ -91,18 +89,18 @@ struct scmr_t {
}
};
struct por_t {
struct POR {
bool obj;
bool freezehigh;
bool highnibble;
bool dither;
bool transparent;
operator unsigned() const {
operator uint() const {
return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent);
}
auto& operator=(uint8 data) {
auto& operator=(uint data) {
obj = data & 0x10;
freezehigh = data & 0x08;
highnibble = data & 0x04;
@ -112,48 +110,49 @@ struct por_t {
}
};
struct cfgr_t {
struct CFGR {
bool irq;
bool ms0;
operator unsigned() const {
operator uint() const {
return (irq << 7) | (ms0 << 5);
}
auto& operator=(uint8 data) {
auto& operator=(uint data) {
irq = data & 0x80;
ms0 = data & 0x20;
return *this;
}
};
struct regs_t {
struct Registers {
uint8 pipeline;
uint16 ramaddr;
reg16_t r[16]; //general purpose registers
sfr_t sfr; //status flag register
Register r[16]; //general purpose registers
SFR sfr; //status flag register
uint8 pbr; //program bank register
uint8 rombr; //game pack ROM bank register
bool rambr; //game pack RAM bank register
uint16 cbr; //cache base register
uint8 scbr; //screen base register
scmr_t scmr; //screen mode register
SCMR scmr; //screen mode register
uint8 colr; //color register
por_t por; //plot option register
POR por; //plot option register
bool bramr; //back-up RAM register
uint8 vcr; //version code register
cfgr_t cfgr; //config register
CFGR cfgr; //config register
bool clsr; //clock select register
unsigned romcl; //clock ticks until romdr is valid
uint romcl; //clock ticks until romdr is valid
uint8 romdr; //ROM buffer data register
unsigned ramcl; //clock ticks until ramdr is valid
uint ramcl; //clock ticks until ramdr is valid
uint16 ramar; //RAM buffer address register
uint8 ramdr; //RAM buffer data register
unsigned sreg, dreg;
uint sreg;
uint dreg;
auto& sr() { return r[sreg]; } //source register (from)
auto& dr() { return r[dreg]; } //destination register (to)
@ -167,12 +166,12 @@ struct regs_t {
}
} regs;
struct cache_t {
struct Cache {
uint8 buffer[512];
bool valid[32];
} cache;
struct pixelcache_t {
struct PixelCache {
uint16 offset;
uint8 bitpend;
uint8 data[8];

View File

@ -2,22 +2,10 @@ auto GSU::serialize(serializer& s) -> void {
s.integer(regs.pipeline);
s.integer(regs.ramaddr);
s.integer(regs.r[ 0].data);
s.integer(regs.r[ 1].data);
s.integer(regs.r[ 2].data);
s.integer(regs.r[ 3].data);
s.integer(regs.r[ 4].data);
s.integer(regs.r[ 5].data);
s.integer(regs.r[ 6].data);
s.integer(regs.r[ 7].data);
s.integer(regs.r[ 8].data);
s.integer(regs.r[ 9].data);
s.integer(regs.r[10].data);
s.integer(regs.r[11].data);
s.integer(regs.r[12].data);
s.integer(regs.r[13].data);
s.integer(regs.r[14].data);
s.integer(regs.r[15].data);
for(auto n : range(16)) {
s.integer(regs.r[n].data);
s.integer(regs.r[n].modified);
}
s.integer(regs.sfr.irq);
s.integer(regs.sfr.b);
@ -72,9 +60,9 @@ auto GSU::serialize(serializer& s) -> void {
s.array(cache.buffer);
s.array(cache.valid);
for(unsigned i = 0; i < 2; i++) {
s.integer(pixelcache[i].offset);
s.integer(pixelcache[i].bitpend);
s.array(pixelcache[i].data);
for(uint n : range(2)) {
s.integer(pixelcache[n].offset);
s.integer(pixelcache[n].bitpend);
s.array(pixelcache[n].data);
}
}

View File

@ -20,10 +20,10 @@ auto LR35902::disassemble(uint16 pc) -> string {
}
auto LR35902::disassembleOpcode(uint16 pc) -> string {
uint8 opcode = debugger_read(pc);
uint8 p0 = debugger_read(pc + 1);
uint8 p1 = debugger_read(pc + 2);
uint8 p2 = debugger_read(pc + 3);
uint8 opcode = debuggerRead(pc);
uint8 p0 = debuggerRead(pc + 1);
uint8 p1 = debuggerRead(pc + 2);
uint8 p2 = debuggerRead(pc + 3);
switch(opcode) {
case 0x00: return { "nop" };
@ -288,10 +288,10 @@ auto LR35902::disassembleOpcode(uint16 pc) -> string {
}
auto LR35902::disassembleOpcodeCB(uint16 pc) -> string {
uint8 opcode = debugger_read(pc);
uint8 p0 = debugger_read(pc + 1);
uint8 p1 = debugger_read(pc + 2);
uint8 p2 = debugger_read(pc + 3);
uint8 opcode = debuggerRead(pc);
uint8 p0 = debuggerRead(pc + 1);
uint8 p1 = debuggerRead(pc + 2);
uint8 p2 = debuggerRead(pc + 3);
switch(opcode) {
case 0x00: return { "rlc b" };

View File

@ -2,7 +2,7 @@ auto LR35902::op_xx() {
}
auto LR35902::op_cb() {
execCB();
instructionCB();
}
//8-bit load commands
@ -12,105 +12,105 @@ auto LR35902::op_ld_r_r(uint x, uint y) {
}
auto LR35902::op_ld_r_n(uint x) {
r[x] = op_read(r[PC]++);
r[x] = read(r[PC]++);
}
auto LR35902::op_ld_r_hl(uint x) {
r[x] = op_read(r[HL]);
r[x] = read(r[HL]);
}
auto LR35902::op_ld_hl_r(uint x) {
op_write(r[HL], r[x]);
write(r[HL], r[x]);
}
auto LR35902::op_ld_hl_n() {
op_write(r[HL], op_read(r[PC]++));
write(r[HL], read(r[PC]++));
}
auto LR35902::op_ld_a_rr(uint x) {
r[A] = op_read(r[x]);
r[A] = read(r[x]);
}
auto LR35902::op_ld_a_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
r[A] = op_read((hi << 8) | (lo << 0));
uint8 lo = read(r[PC]++);
uint8 hi = read(r[PC]++);
r[A] = read((hi << 8) | (lo << 0));
}
auto LR35902::op_ld_rr_a(uint x) {
op_write(r[x], r[A]);
write(r[x], r[A]);
}
auto LR35902::op_ld_nn_a() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
op_write((hi << 8) | (lo << 0), r[A]);
uint8 lo = read(r[PC]++);
uint8 hi = read(r[PC]++);
write((hi << 8) | (lo << 0), r[A]);
}
auto LR35902::op_ld_a_ffn() {
r[A] = op_read(0xff00 + op_read(r[PC]++));
r[A] = read(0xff00 + read(r[PC]++));
}
auto LR35902::op_ld_ffn_a() {
op_write(0xff00 + op_read(r[PC]++), r[A]);
write(0xff00 + read(r[PC]++), r[A]);
}
auto LR35902::op_ld_a_ffc() {
r[A] = op_read(0xff00 + r[C]);
r[A] = read(0xff00 + r[C]);
}
auto LR35902::op_ld_ffc_a() {
op_write(0xff00 + r[C], r[A]);
write(0xff00 + r[C], r[A]);
}
auto LR35902::op_ldi_hl_a() {
op_write(r[HL], r[A]);
write(r[HL], r[A]);
r[HL]++;
}
auto LR35902::op_ldi_a_hl() {
r[A] = op_read(r[HL]);
r[A] = read(r[HL]);
r[HL]++;
}
auto LR35902::op_ldd_hl_a() {
op_write(r[HL], r[A]);
write(r[HL], r[A]);
r[HL]--;
}
auto LR35902::op_ldd_a_hl() {
r[A] = op_read(r[HL]);
r[A] = read(r[HL]);
r[HL]--;
}
//16-bit load commands
auto LR35902::op_ld_rr_nn(uint x) {
r[x] = op_read(r[PC]++) << 0;
r[x] |= op_read(r[PC]++) << 8;
r[x] = read(r[PC]++) << 0;
r[x] |= read(r[PC]++) << 8;
}
auto LR35902::op_ld_nn_sp() {
uint16 addr = op_read(r[PC]++) << 0;
addr |= op_read(r[PC]++) << 8;
op_write(addr + 0, r[SP] >> 0);
op_write(addr + 1, r[SP] >> 8);
uint16 addr = read(r[PC]++) << 0;
addr |= read(r[PC]++) << 8;
write(addr + 0, r[SP] >> 0);
write(addr + 1, r[SP] >> 8);
}
auto LR35902::op_ld_sp_hl() {
r[SP] = r[HL];
op_io();
io();
}
auto LR35902::op_push_rr(uint x) {
op_io();
op_write(--r[SP], r[x] >> 8);
op_write(--r[SP], r[x] >> 0);
io();
write(--r[SP], r[x] >> 8);
write(--r[SP], r[x] >> 0);
}
auto LR35902::op_pop_rr(uint x) {
r[x] = op_read(r[SP]++) << 0;
r[x] |= op_read(r[SP]++) << 8;
r[x] = read(r[SP]++) << 0;
r[x] |= read(r[SP]++) << 8;
}
//8-bit arithmetic commands
@ -126,8 +126,8 @@ auto LR35902::opi_add_a(uint8 x) {
}
auto LR35902::op_add_a_r(uint x) { opi_add_a(r[x]); }
auto LR35902::op_add_a_n() { opi_add_a(op_read(r[PC]++)); }
auto LR35902::op_add_a_hl() { opi_add_a(op_read(r[HL])); }
auto LR35902::op_add_a_n() { opi_add_a(read(r[PC]++)); }
auto LR35902::op_add_a_hl() { opi_add_a(read(r[HL])); }
auto LR35902::opi_adc_a(uint8 x) {
uint16 rh = r[A] + x + r.f.c;
@ -140,8 +140,8 @@ auto LR35902::opi_adc_a(uint8 x) {
}
auto LR35902::op_adc_a_r(uint x) { opi_adc_a(r[x]); }
auto LR35902::op_adc_a_n() { opi_adc_a(op_read(r[PC]++)); }
auto LR35902::op_adc_a_hl() { opi_adc_a(op_read(r[HL])); }
auto LR35902::op_adc_a_n() { opi_adc_a(read(r[PC]++)); }
auto LR35902::op_adc_a_hl() { opi_adc_a(read(r[HL])); }
auto LR35902::opi_sub_a(uint8 x) {
uint16 rh = r[A] - x;
@ -154,8 +154,8 @@ auto LR35902::opi_sub_a(uint8 x) {
}
auto LR35902::op_sub_a_r(uint x) { opi_sub_a(r[x]); }
auto LR35902::op_sub_a_n() { opi_sub_a(op_read(r[PC]++)); }
auto LR35902::op_sub_a_hl() { opi_sub_a(op_read(r[HL])); }
auto LR35902::op_sub_a_n() { opi_sub_a(read(r[PC]++)); }
auto LR35902::op_sub_a_hl() { opi_sub_a(read(r[HL])); }
auto LR35902::opi_sbc_a(uint8 x) {
uint16 rh = r[A] - x - r.f.c;
@ -168,8 +168,8 @@ auto LR35902::opi_sbc_a(uint8 x) {
}
auto LR35902::op_sbc_a_r(uint x) { opi_sbc_a(r[x]); }
auto LR35902::op_sbc_a_n() { opi_sbc_a(op_read(r[PC]++)); }
auto LR35902::op_sbc_a_hl() { opi_sbc_a(op_read(r[HL])); }
auto LR35902::op_sbc_a_n() { opi_sbc_a(read(r[PC]++)); }
auto LR35902::op_sbc_a_hl() { opi_sbc_a(read(r[HL])); }
auto LR35902::opi_and_a(uint8 x) {
r[A] &= x;
@ -180,8 +180,8 @@ auto LR35902::opi_and_a(uint8 x) {
}
auto LR35902::op_and_a_r(uint x) { opi_and_a(r[x]); }
auto LR35902::op_and_a_n() { opi_and_a(op_read(r[PC]++)); }
auto LR35902::op_and_a_hl() { opi_and_a(op_read(r[HL])); }
auto LR35902::op_and_a_n() { opi_and_a(read(r[PC]++)); }
auto LR35902::op_and_a_hl() { opi_and_a(read(r[HL])); }
auto LR35902::opi_xor_a(uint8 x) {
r[A] ^= x;
@ -192,8 +192,8 @@ auto LR35902::opi_xor_a(uint8 x) {
}
auto LR35902::op_xor_a_r(uint x) { opi_xor_a(r[x]); }
auto LR35902::op_xor_a_n() { opi_xor_a(op_read(r[PC]++)); }
auto LR35902::op_xor_a_hl() { opi_xor_a(op_read(r[HL])); }
auto LR35902::op_xor_a_n() { opi_xor_a(read(r[PC]++)); }
auto LR35902::op_xor_a_hl() { opi_xor_a(read(r[HL])); }
auto LR35902::opi_or_a(uint8 x) {
r[A] |= x;
@ -204,8 +204,8 @@ auto LR35902::opi_or_a(uint8 x) {
}
auto LR35902::op_or_a_r(uint x) { opi_or_a(r[x]); }
auto LR35902::op_or_a_n() { opi_or_a(op_read(r[PC]++)); }
auto LR35902::op_or_a_hl() { opi_or_a(op_read(r[HL])); }
auto LR35902::op_or_a_n() { opi_or_a(read(r[PC]++)); }
auto LR35902::op_or_a_hl() { opi_or_a(read(r[HL])); }
auto LR35902::opi_cp_a(uint8 x) {
uint16 rh = r[A] - x;
@ -217,8 +217,8 @@ auto LR35902::opi_cp_a(uint8 x) {
}
auto LR35902::op_cp_a_r(uint x) { opi_cp_a(r[x]); }
auto LR35902::op_cp_a_n() { opi_cp_a(op_read(r[PC]++)); }
auto LR35902::op_cp_a_hl() { opi_cp_a(op_read(r[HL])); }
auto LR35902::op_cp_a_n() { opi_cp_a(read(r[PC]++)); }
auto LR35902::op_cp_a_hl() { opi_cp_a(read(r[HL])); }
auto LR35902::op_inc_r(uint x) {
r[x]++;
@ -228,8 +228,8 @@ auto LR35902::op_inc_r(uint x) {
}
auto LR35902::op_inc_hl() {
uint8 n = op_read(r[HL]);
op_write(r[HL], ++n);
uint8 n = read(r[HL]);
write(r[HL], ++n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = (n & 0x0f) == 0x00;
@ -243,8 +243,8 @@ auto LR35902::op_dec_r(uint x) {
}
auto LR35902::op_dec_hl() {
uint8 n = op_read(r[HL]);
op_write(r[HL], --n);
uint8 n = read(r[HL]);
write(r[HL], --n);
r.f.z = n == 0;
r.f.n = 1;
r.f.h = (n & 0x0f) == 0x0f;
@ -277,7 +277,7 @@ auto LR35902::op_cpl() {
//16-bit arithmetic commands
auto LR35902::op_add_hl_rr(uint x) {
op_io();
io();
uint32 rb = (r[HL] + r[x]);
uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff);
r[HL] = rb;
@ -287,34 +287,34 @@ auto LR35902::op_add_hl_rr(uint x) {
}
auto LR35902::op_inc_rr(uint x) {
op_io();
io();
r[x]++;
}
auto LR35902::op_dec_rr(uint x) {
op_io();
io();
r[x]--;
}
auto LR35902::op_add_sp_n() {
int n = (int8)op_read(r[PC]++);
int n = (int8)read(r[PC]++);
r.f.z = 0;
r.f.n = 0;
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
r[SP] += n;
op_io();
op_io();
io();
io();
}
auto LR35902::op_ld_hl_sp_n() {
int n = (int8)op_read(r[PC]++);
int n = (int8)read(r[PC]++);
r.f.z = 0;
r.f.n = 0;
r.f.h = ((r[SP] & 0x0f) + (n & 0x0f)) > 0x0f;
r.f.c = ((r[SP] & 0xff) + (n & 0xff)) > 0xff;
r[HL] = r[SP] + n;
op_io();
io();
}
//rotate/shift commands
@ -362,9 +362,9 @@ auto LR35902::op_rlc_r(uint x) {
}
auto LR35902::op_rlc_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
n = (n << 1) | (n >> 7);
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -381,10 +381,10 @@ auto LR35902::op_rl_r(uint x) {
}
auto LR35902::op_rl_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
bool c = n & 0x80;
n = (n << 1) | (r.f.c << 0);
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -400,9 +400,9 @@ auto LR35902::op_rrc_r(uint x) {
}
auto LR35902::op_rrc_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
n = (n >> 1) | (n << 7);
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -419,10 +419,10 @@ auto LR35902::op_rr_r(uint x) {
}
auto LR35902::op_rr_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
bool c = n & 0x01;
n = (n >> 1) | (r.f.c << 7);
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -439,10 +439,10 @@ auto LR35902::op_sla_r(uint x) {
}
auto LR35902::op_sla_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
bool c = n & 0x80;
n <<= 1;
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -458,9 +458,9 @@ auto LR35902::op_swap_r(uint x) {
}
auto LR35902::op_swap_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
n = (n << 4) | (n >> 4);
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -477,10 +477,10 @@ auto LR35902::op_sra_r(uint x) {
}
auto LR35902::op_sra_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
bool c = n & 0x01;
n = (int8)n >> 1;
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -497,10 +497,10 @@ auto LR35902::op_srl_r(uint x) {
}
auto LR35902::op_srl_hl() {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
bool c = n & 0x01;
n >>= 1;
op_write(r[HL], n);
write(r[HL], n);
r.f.z = n == 0;
r.f.n = 0;
r.f.h = 0;
@ -516,7 +516,7 @@ auto LR35902::op_bit_n_r(uint b, uint x) {
}
auto LR35902::op_bit_n_hl(uint b) {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
r.f.z = (n & (1 << b)) == 0;
r.f.n = 0;
r.f.h = 1;
@ -527,9 +527,9 @@ auto LR35902::op_set_n_r(uint b, uint x) {
}
auto LR35902::op_set_n_hl(uint b) {
uint8 n = op_read(r[HL]);
uint8 n = read(r[HL]);
n |= 1 << b;
op_write(r[HL], n);
write(r[HL], n);
}
auto LR35902::op_res_n_r(uint b, uint x) {
@ -537,9 +537,9 @@ auto LR35902::op_res_n_r(uint b, uint x) {
}
auto LR35902::op_res_n_hl(uint b) {
uint n = op_read(r[HL]);
uint n = read(r[HL]);
n &= ~(1 << b);
op_write(r[HL], n);
write(r[HL], n);
}
//control commands
@ -561,13 +561,13 @@ auto LR35902::op_nop() {
auto LR35902::op_halt() {
r.halt = true;
while(r.halt == true) op_io();
while(r.halt) io();
}
auto LR35902::op_stop() {
if(stop()) return;
r.stop = true;
while(r.stop == true) op_io();
while(r.stop) io();
}
auto LR35902::op_di() {
@ -582,10 +582,10 @@ auto LR35902::op_ei() {
//jump commands
auto LR35902::op_jp_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
uint8 lo = read(r[PC]++);
uint8 hi = read(r[PC]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
io();
}
auto LR35902::op_jp_hl() {
@ -593,76 +593,76 @@ auto LR35902::op_jp_hl() {
}
auto LR35902::op_jp_f_nn(uint x, bool y) {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
uint8 lo = read(r[PC]++);
uint8 hi = read(r[PC]++);
if(r.f[x] == y) {
r[PC] = (hi << 8) | (lo << 0);
op_io();
io();
}
}
auto LR35902::op_jr_n() {
int8 n = op_read(r[PC]++);
int8 n = read(r[PC]++);
r[PC] += n;
op_io();
io();
}
auto LR35902::op_jr_f_n(uint x, bool y) {
int8 n = op_read(r[PC]++);
int8 n = read(r[PC]++);
if(r.f[x] == y) {
r[PC] += n;
op_io();
io();
}
}
auto LR35902::op_call_nn() {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
op_io();
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
uint8 lo = read(r[PC]++);
uint8 hi = read(r[PC]++);
io();
write(--r[SP], r[PC] >> 8);
write(--r[SP], r[PC] >> 0);
r[PC] = (hi << 8) | (lo << 0);
}
auto LR35902::op_call_f_nn(uint x, bool y) {
uint8 lo = op_read(r[PC]++);
uint8 hi = op_read(r[PC]++);
uint8 lo = read(r[PC]++);
uint8 hi = read(r[PC]++);
if(r.f[x] == y) {
op_io();
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
io();
write(--r[SP], r[PC] >> 8);
write(--r[SP], r[PC] >> 0);
r[PC] = (hi << 8) | (lo << 0);
}
}
auto LR35902::op_ret() {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
uint8 lo = read(r[SP]++);
uint8 hi = read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
io();
}
auto LR35902::op_ret_f(uint x, bool y) {
op_io();
io();
if(r.f[x] == y) {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
uint8 lo = read(r[SP]++);
uint8 hi = read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
io();
}
}
auto LR35902::op_reti() {
uint8 lo = op_read(r[SP]++);
uint8 hi = op_read(r[SP]++);
uint8 lo = read(r[SP]++);
uint8 hi = read(r[SP]++);
r[PC] = (hi << 8) | (lo << 0);
op_io();
io();
r.ime = 1;
}
auto LR35902::op_rst_n(uint n) {
op_io();
op_write(--r[SP], r[PC] >> 8);
op_write(--r[SP], r[PC] >> 0);
io();
write(--r[SP], r[PC] >> 8);
write(--r[SP], r[PC] >> 0);
r[PC] = n;
}

View File

@ -14,9 +14,18 @@ auto LR35902::power() -> void {
r.ime = false;
}
auto LR35902::exec() -> void {
uint8 opcode = op_read(r[PC]++);
switch(opcode) {
auto LR35902::interrupt(uint16 vector) -> void {
io();
io();
io();
r.ime = 0;
write(--r[SP], r[PC] >> 8);
write(--r[SP], r[PC] >> 0);
r[PC] = vector;
}
auto LR35902::instruction() -> void {
switch(auto opcode = read(r[PC]++)) {
case 0x00: return op_nop();
case 0x01: return op_ld_rr_nn(BC);
case 0x02: return op_ld_rr_a(BC);
@ -276,9 +285,8 @@ auto LR35902::exec() -> void {
}
}
auto LR35902::execCB() -> void {
uint8 opcode = op_read(r[PC]++);
switch(opcode) {
auto LR35902::instructionCB() -> void {
switch(auto opcode = read(r[PC]++)) {
case 0x00: return op_rlc_r(B);
case 0x01: return op_rlc_r(C);
case 0x02: return op_rlc_r(D);

View File

@ -5,15 +5,16 @@
namespace Processor {
struct LR35902 {
virtual auto op_io() -> void = 0;
virtual auto op_read(uint16 addr) -> uint8 = 0;
virtual auto op_write(uint16 addr, uint8 data) -> void = 0;
virtual auto io() -> void = 0;
virtual auto read(uint16 addr) -> uint8 = 0;
virtual auto write(uint16 addr, uint8 data) -> void = 0;
virtual auto stop() -> bool = 0;
virtual auto debugger_read(uint16 addr) -> uint8 { return 0; }
virtual auto debuggerRead(uint16 addr) -> uint8 { return 0; }
auto power() -> void;
auto exec() -> void;
auto execCB() -> void;
auto interrupt(uint16 vector) -> void;
auto instruction() -> void;
auto instructionCB() -> void;
auto serialize(serializer&) -> void;

View File

@ -1,11 +1,11 @@
#define call (this->*op)
auto SPC700::op_adjust(fps op, uint8_t& r) -> void {
auto SPC700::op_adjust(fps op, uint8_t& r) {
io();
r = call(r);
}
auto SPC700::op_adjust_addr(fps op) -> void {
auto SPC700::op_adjust_addr(fps op) {
dp.l = readPC();
dp.h = readPC();
rd = read(dp);
@ -13,14 +13,14 @@ auto SPC700::op_adjust_addr(fps op) -> void {
write(dp, rd);
}
auto SPC700::op_adjust_dp(fps op) -> void {
auto SPC700::op_adjust_dp(fps op) {
dp = readPC();
rd = readDP(dp);
rd = call(rd);
writeDP(dp, rd);
}
auto SPC700::op_adjust_dpw(int n) -> void {
auto SPC700::op_adjust_dpw(int n) {
dp = readPC();
rd.w = readDP(dp) + n;
writeDP(dp++, rd.l);
@ -30,7 +30,7 @@ auto SPC700::op_adjust_dpw(int n) -> void {
regs.p.z = rd == 0;
}
auto SPC700::op_adjust_dpx(fps op) -> void {
auto SPC700::op_adjust_dpx(fps op) {
dp = readPC();
io();
rd = readDP(dp + regs.x);
@ -38,7 +38,7 @@ auto SPC700::op_adjust_dpx(fps op) -> void {
writeDP(dp + regs.x, rd);
}
auto SPC700::op_branch(bool condition) -> void {
auto SPC700::op_branch(bool condition) {
rd = readPC();
if(!condition) return;
io();
@ -46,7 +46,7 @@ auto SPC700::op_branch(bool condition) -> void {
regs.pc += (int8)rd;
}
auto SPC700::op_branch_bit() -> void {
auto SPC700::op_branch_bit() {
dp = readPC();
sp = readDP(dp);
rd = readPC();
@ -57,26 +57,26 @@ auto SPC700::op_branch_bit() -> void {
regs.pc += (int8)rd;
}
auto SPC700::op_pull(uint8_t& r) -> void {
auto SPC700::op_pull(uint8_t& r) {
io();
io();
r = readSP();
}
auto SPC700::op_push(uint8 r) -> void {
auto SPC700::op_push(uint8 r) {
io();
io();
writeSP(r);
}
auto SPC700::op_read_addr(fpb op, uint8_t& r) -> void {
auto SPC700::op_read_addr(fpb op, uint8_t& r) {
dp.l = readPC();
dp.h = readPC();
rd = read(dp);
r = call(r, rd);
}
auto SPC700::op_read_addri(fpb op, uint8_t& r) -> void {
auto SPC700::op_read_addri(fpb op, uint8_t& r) {
dp.l = readPC();
dp.h = readPC();
io();
@ -84,25 +84,25 @@ auto SPC700::op_read_addri(fpb op, uint8_t& r) -> void {
regs.a = call(regs.a, rd);
}
auto SPC700::op_read_const(fpb op, uint8_t& r) -> void {
auto SPC700::op_read_const(fpb op, uint8_t& r) {
rd = readPC();
r = call(r, rd);
}
auto SPC700::op_read_dp(fpb op, uint8_t& r) -> void {
auto SPC700::op_read_dp(fpb op, uint8_t& r) {
dp = readPC();
rd = readDP(dp);
r = call(r, rd);
}
auto SPC700::op_read_dpi(fpb op, uint8_t& r, uint8_t& i) -> void {
auto SPC700::op_read_dpi(fpb op, uint8_t& r, uint8_t& i) {
dp = readPC();
io();
rd = readDP(dp + i);
r = call(r, rd);
}
auto SPC700::op_read_dpw(fpw op) -> void {
auto SPC700::op_read_dpw(fpw op) {
dp = readPC();
rd.l = readDP(dp++);
if(op != &SPC700::op_cpw) io();
@ -110,7 +110,7 @@ auto SPC700::op_read_dpw(fpw op) -> void {
regs.ya = call(regs.ya, rd);
}
auto SPC700::op_read_idpx(fpb op) -> void {
auto SPC700::op_read_idpx(fpb op) {
dp = readPC() + regs.x;
io();
sp.l = readDP(dp++);
@ -119,7 +119,7 @@ auto SPC700::op_read_idpx(fpb op) -> void {
regs.a = call(regs.a, rd);
}
auto SPC700::op_read_idpy(fpb op) -> void {
auto SPC700::op_read_idpy(fpb op) {
dp = readPC();
io();
sp.l = readDP(dp++);
@ -128,13 +128,13 @@ auto SPC700::op_read_idpy(fpb op) -> void {
regs.a = call(regs.a, rd);
}
auto SPC700::op_read_ix(fpb op) -> void {
auto SPC700::op_read_ix(fpb op) {
io();
rd = readDP(regs.x);
regs.a = call(regs.a, rd);
}
auto SPC700::op_set_addr_bit() -> void {
auto SPC700::op_set_addr_bit() {
dp.l = readPC();
dp.h = readPC();
bit = dp >> 13;
@ -169,19 +169,19 @@ auto SPC700::op_set_addr_bit() -> void {
}
}
auto SPC700::op_set_bit() -> void {
auto SPC700::op_set_bit() {
dp = readPC();
rd = readDP(dp) & ~(1 << (opcode >> 5));
writeDP(dp, rd | (!(opcode & 0x10) << (opcode >> 5)));
}
auto SPC700::op_set_flag(bool& flag, bool data) -> void {
auto SPC700::op_set_flag(bool& flag, bool data) {
io();
if(&flag == &regs.p.i) io();
flag = data;
}
auto SPC700::op_test_addr(bool set) -> void {
auto SPC700::op_test_addr(bool set) {
dp.l = readPC();
dp.h = readPC();
rd = read(dp);
@ -191,7 +191,7 @@ auto SPC700::op_test_addr(bool set) -> void {
write(dp, set ? rd | regs.a : rd & ~regs.a);
}
auto SPC700::op_transfer(uint8_t& from, uint8_t& to) -> void {
auto SPC700::op_transfer(uint8_t& from, uint8_t& to) {
io();
to = from;
if(&to == &regs.s) return;
@ -199,14 +199,14 @@ auto SPC700::op_transfer(uint8_t& from, uint8_t& to) -> void {
regs.p.z = (to == 0);
}
auto SPC700::op_write_addr(uint8_t& r) -> void {
auto SPC700::op_write_addr(uint8_t& r) {
dp.l = readPC();
dp.h = readPC();
read(dp);
write(dp, r);
}
auto SPC700::op_write_addri(uint8_t& i) -> void {
auto SPC700::op_write_addri(uint8_t& i) {
dp.l = readPC();
dp.h = readPC();
io();
@ -215,20 +215,20 @@ auto SPC700::op_write_addri(uint8_t& i) -> void {
write(dp, regs.a);
}
auto SPC700::op_write_dp(uint8_t& r) -> void {
auto SPC700::op_write_dp(uint8_t& r) {
dp = readPC();
readDP(dp);
writeDP(dp, r);
}
auto SPC700::op_write_dpi(uint8_t& r, uint8_t& i) -> void {
auto SPC700::op_write_dpi(uint8_t& r, uint8_t& i) {
dp = readPC() + i;
io();
readDP(dp);
writeDP(dp, r);
}
auto SPC700::op_write_dp_const(fpb op) -> void {
auto SPC700::op_write_dp_const(fpb op) {
rd = readPC();
dp = readPC();
wr = readDP(dp);
@ -236,7 +236,7 @@ auto SPC700::op_write_dp_const(fpb op) -> void {
op != &SPC700::op_cmp ? writeDP(dp, wr) : io();
}
auto SPC700::op_write_dp_dp(fpb op) -> void {
auto SPC700::op_write_dp_dp(fpb op) {
sp = readPC();
rd = readDP(sp);
dp = readPC();
@ -245,7 +245,7 @@ auto SPC700::op_write_dp_dp(fpb op) -> void {
op != &SPC700::op_cmp ? writeDP(dp, wr) : io();
}
auto SPC700::op_write_ix_iy(fpb op) -> void {
auto SPC700::op_write_ix_iy(fpb op) {
io();
rd = readDP(regs.y);
wr = readDP(regs.x);
@ -255,7 +255,7 @@ auto SPC700::op_write_ix_iy(fpb op) -> void {
//
auto SPC700::op_bne_dp() -> void {
auto SPC700::op_bne_dp() {
dp = readPC();
sp = readDP(dp);
rd = readPC();
@ -266,7 +266,7 @@ auto SPC700::op_bne_dp() -> void {
regs.pc += (int8)rd;
}
auto SPC700::op_bne_dpdec() -> void {
auto SPC700::op_bne_dpdec() {
dp = readPC();
wr = readDP(dp);
writeDP(dp, --wr);
@ -277,7 +277,7 @@ auto SPC700::op_bne_dpdec() -> void {
regs.pc += (int8)rd;
}
auto SPC700::op_bne_dpx() -> void {
auto SPC700::op_bne_dpx() {
dp = readPC();
io();
sp = readDP(dp + regs.x);
@ -289,7 +289,7 @@ auto SPC700::op_bne_dpx() -> void {
regs.pc += (int8)rd;
}
auto SPC700::op_bne_ydec() -> void {
auto SPC700::op_bne_ydec() {
rd = readPC();
io();
io();
@ -299,7 +299,7 @@ auto SPC700::op_bne_ydec() -> void {
regs.pc += (int8)rd;
}
auto SPC700::op_brk() -> void {
auto SPC700::op_brk() {
rd.l = read(0xffde);
rd.h = read(0xffdf);
io();
@ -312,19 +312,19 @@ auto SPC700::op_brk() -> void {
regs.p.i = 0;
}
auto SPC700::op_clv() -> void {
auto SPC700::op_clv() {
io();
regs.p.v = 0;
regs.p.h = 0;
}
auto SPC700::op_cmc() -> void {
auto SPC700::op_cmc() {
io();
io();
regs.p.c = !regs.p.c;
}
auto SPC700::op_daa() -> void {
auto SPC700::op_daa() {
io();
io();
if(regs.p.c || (regs.a) > 0x99) {
@ -338,7 +338,7 @@ auto SPC700::op_daa() -> void {
regs.p.z = (regs.a == 0);
}
auto SPC700::op_das() -> void {
auto SPC700::op_das() {
io();
io();
if(!regs.p.c || (regs.a) > 0x99) {
@ -352,7 +352,7 @@ auto SPC700::op_das() -> void {
regs.p.z = (regs.a == 0);
}
auto SPC700::op_div_ya_x() -> void {
auto SPC700::op_div_ya_x() {
io();
io();
io();
@ -383,13 +383,13 @@ auto SPC700::op_div_ya_x() -> void {
regs.p.z = (regs.a == 0);
}
auto SPC700::op_jmp_addr() -> void {
auto SPC700::op_jmp_addr() {
rd.l = readPC();
rd.h = readPC();
regs.pc = rd;
}
auto SPC700::op_jmp_iaddrx() -> void {
auto SPC700::op_jmp_iaddrx() {
dp.l = readPC();
dp.h = readPC();
io();
@ -399,7 +399,7 @@ auto SPC700::op_jmp_iaddrx() -> void {
regs.pc = rd;
}
auto SPC700::op_jsp_dp() -> void {
auto SPC700::op_jsp_dp() {
rd = readPC();
io();
io();
@ -408,7 +408,7 @@ auto SPC700::op_jsp_dp() -> void {
regs.pc = 0xff00 | rd;
}
auto SPC700::op_jsr_addr() -> void {
auto SPC700::op_jsr_addr() {
rd.l = readPC();
rd.h = readPC();
io();
@ -419,7 +419,7 @@ auto SPC700::op_jsr_addr() -> void {
regs.pc = rd;
}
auto SPC700::op_jst() -> void {
auto SPC700::op_jst() {
dp = 0xffde - ((opcode >> 4) << 1);
rd.l = read(dp++);
rd.h = read(dp++);
@ -431,7 +431,7 @@ auto SPC700::op_jst() -> void {
regs.pc = rd;
}
auto SPC700::op_lda_ixinc() -> void {
auto SPC700::op_lda_ixinc() {
io();
regs.a = readDP(regs.x++);
io();
@ -439,7 +439,7 @@ auto SPC700::op_lda_ixinc() -> void {
regs.p.z = regs.a == 0;
}
auto SPC700::op_mul_ya() -> void {
auto SPC700::op_mul_ya() {
io();
io();
io();
@ -456,17 +456,17 @@ auto SPC700::op_mul_ya() -> void {
regs.p.z = (regs.y == 0);
}
auto SPC700::op_nop() -> void {
auto SPC700::op_nop() {
io();
}
auto SPC700::op_plp() -> void {
auto SPC700::op_plp() {
io();
io();
regs.p = readSP();
}
auto SPC700::op_rti() -> void {
auto SPC700::op_rti() {
regs.p = readSP();
rd.l = readSP();
rd.h = readSP();
@ -475,7 +475,7 @@ auto SPC700::op_rti() -> void {
regs.pc = rd;
}
auto SPC700::op_rts() -> void {
auto SPC700::op_rts() {
rd.l = readSP();
rd.h = readSP();
io();
@ -483,7 +483,7 @@ auto SPC700::op_rts() -> void {
regs.pc = rd;
}
auto SPC700::op_sta_idpx() -> void {
auto SPC700::op_sta_idpx() {
sp = readPC() + regs.x;
io();
dp.l = readDP(sp++);
@ -492,7 +492,7 @@ auto SPC700::op_sta_idpx() -> void {
write(dp, regs.a);
}
auto SPC700::op_sta_idpy() -> void {
auto SPC700::op_sta_idpy() {
sp = readPC();
dp.l = readDP(sp++);
dp.h = readDP(sp++);
@ -502,33 +502,33 @@ auto SPC700::op_sta_idpy() -> void {
write(dp, regs.a);
}
auto SPC700::op_sta_ix() -> void {
auto SPC700::op_sta_ix() {
io();
readDP(regs.x);
writeDP(regs.x, regs.a);
}
auto SPC700::op_sta_ixinc() -> void {
auto SPC700::op_sta_ixinc() {
io();
io();
writeDP(regs.x++, regs.a);
}
auto SPC700::op_stw_dp() -> void {
auto SPC700::op_stw_dp() {
dp = readPC();
readDP(dp);
writeDP(dp++, regs.a);
writeDP(dp++, regs.y);
}
auto SPC700::op_wait() -> void {
auto SPC700::op_wait() {
while(true) {
io();
io();
}
}
auto SPC700::op_xcn() -> void {
auto SPC700::op_xcn() {
io();
io();
io();

View File

@ -45,65 +45,65 @@ protected:
auto op_ldw(uint16, uint16) -> uint16;
auto op_sbw(uint16, uint16) -> uint16;
auto op_adjust(fps, uint8_t&) -> void;
auto op_adjust_addr(fps) -> void;
auto op_adjust_dp(fps) -> void;
auto op_adjust_dpw(int) -> void;
auto op_adjust_dpx(fps) -> void;
auto op_branch(bool) -> void;
auto op_branch_bit() -> void;
auto op_pull(uint8_t&) -> void;
auto op_push(uint8) -> void;
auto op_read_addr(fpb, uint8_t&) -> void;
auto op_read_addri(fpb, uint8_t&) -> void;
auto op_read_const(fpb, uint8_t&) -> void;
auto op_read_dp(fpb, uint8_t&) -> void;
auto op_read_dpi(fpb, uint8_t&, uint8_t&) -> void;
auto op_read_dpw(fpw) -> void;
auto op_read_idpx(fpb) -> void;
auto op_read_idpy(fpb) -> void;
auto op_read_ix(fpb) -> void;
auto op_set_addr_bit() -> void;
auto op_set_bit() -> void;
auto op_set_flag(bool&, bool) -> void;
auto op_test_addr(bool) -> void;
auto op_transfer(uint8_t&, uint8_t&) -> void;
auto op_write_addr(uint8_t&) -> void;
auto op_write_addri(uint8_t&) -> void;
auto op_write_dp(uint8_t&) -> void;
auto op_write_dpi(uint8_t&, uint8_t&) -> void;
auto op_write_dp_const(fpb) -> void;
auto op_write_dp_dp(fpb) -> void;
auto op_write_ix_iy(fpb) -> void;
auto op_adjust(fps, uint8_t&);
auto op_adjust_addr(fps);
auto op_adjust_dp(fps);
auto op_adjust_dpw(int);
auto op_adjust_dpx(fps);
auto op_branch(bool);
auto op_branch_bit();
auto op_pull(uint8_t&);
auto op_push(uint8);
auto op_read_addr(fpb, uint8_t&);
auto op_read_addri(fpb, uint8_t&);
auto op_read_const(fpb, uint8_t&);
auto op_read_dp(fpb, uint8_t&);
auto op_read_dpi(fpb, uint8_t&, uint8_t&);
auto op_read_dpw(fpw);
auto op_read_idpx(fpb);
auto op_read_idpy(fpb);
auto op_read_ix(fpb);
auto op_set_addr_bit();
auto op_set_bit();
auto op_set_flag(bool&, bool);
auto op_test_addr(bool);
auto op_transfer(uint8_t&, uint8_t&);
auto op_write_addr(uint8_t&);
auto op_write_addri(uint8_t&);
auto op_write_dp(uint8_t&);
auto op_write_dpi(uint8_t&, uint8_t&);
auto op_write_dp_const(fpb);
auto op_write_dp_dp(fpb);
auto op_write_ix_iy(fpb);
auto op_bne_dp() -> void;
auto op_bne_dpdec() -> void;
auto op_bne_dpx() -> void;
auto op_bne_ydec() -> void;
auto op_brk() -> void;
auto op_clv() -> void;
auto op_cmc() -> void;
auto op_daa() -> void;
auto op_das() -> void;
auto op_div_ya_x() -> void;
auto op_jmp_addr() -> void;
auto op_jmp_iaddrx() -> void;
auto op_jsp_dp() -> void;
auto op_jsr_addr() -> void;
auto op_jst() -> void;
auto op_lda_ixinc() -> void;
auto op_mul_ya() -> void;
auto op_nop() -> void;
auto op_plp() -> void;
auto op_rti() -> void;
auto op_rts() -> void;
auto op_sta_idpx() -> void;
auto op_sta_idpy() -> void;
auto op_sta_ix() -> void;
auto op_sta_ixinc() -> void;
auto op_stw_dp() -> void;
auto op_wait() -> void;
auto op_xcn() -> void;
auto op_bne_dp();
auto op_bne_dpdec();
auto op_bne_dpx();
auto op_bne_ydec();
auto op_brk();
auto op_clv();
auto op_cmc();
auto op_daa();
auto op_das();
auto op_div_ya_x();
auto op_jmp_addr();
auto op_jmp_iaddrx();
auto op_jsp_dp();
auto op_jsr_addr();
auto op_jst();
auto op_lda_ixinc();
auto op_mul_ya();
auto op_nop();
auto op_plp();
auto op_rti();
auto op_rts();
auto op_sta_idpx();
auto op_sta_idpy();
auto op_sta_ix();
auto op_sta_ixinc();
auto op_stw_dp();
auto op_wait();
auto op_xcn();
};
}

View File

@ -30,7 +30,7 @@ auto SuperFX::plot(uint8 x, uint8 y) -> void {
uint16 offset = (y << 5) + (x >> 3);
if(offset != pixelcache[0].offset) {
pixelcache_flush(pixelcache[1]);
flushPixelCache(pixelcache[1]);
pixelcache[1] = pixelcache[0];
pixelcache[0].bitpend = 0x00;
pixelcache[0].offset = offset;
@ -40,64 +40,64 @@ auto SuperFX::plot(uint8 x, uint8 y) -> void {
pixelcache[0].data[x] = color;
pixelcache[0].bitpend |= 1 << x;
if(pixelcache[0].bitpend == 0xff) {
pixelcache_flush(pixelcache[1]);
flushPixelCache(pixelcache[1]);
pixelcache[1] = pixelcache[0];
pixelcache[0].bitpend = 0x00;
}
}
auto SuperFX::rpix(uint8 x, uint8 y) -> uint8 {
pixelcache_flush(pixelcache[1]);
pixelcache_flush(pixelcache[0]);
flushPixelCache(pixelcache[1]);
flushPixelCache(pixelcache[0]);
unsigned cn; //character number
uint cn; //character number
switch(regs.por.obj ? 3 : regs.scmr.ht) {
case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break;
case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break;
case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break;
case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break;
}
unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
uint bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
uint addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
uint8 data = 0x00;
x = (x & 7) ^ 7;
for(unsigned n = 0; n < bpp; n++) {
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
for(uint n : range(bpp)) {
uint byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
step(regs.clsr ? 5 : 6);
data |= ((bus_read(addr + byte) >> x) & 1) << n;
data |= ((read(addr + byte) >> x) & 1) << n;
}
return data;
}
auto SuperFX::pixelcache_flush(pixelcache_t& cache) -> void {
auto SuperFX::flushPixelCache(PixelCache& cache) -> void {
if(cache.bitpend == 0x00) return;
uint8 x = cache.offset << 3;
uint8 y = cache.offset >> 5;
unsigned cn; //character number
uint cn; //character number
switch(regs.por.obj ? 3 : regs.scmr.ht) {
case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break;
case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break;
case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break;
case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break;
}
unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
uint bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
uint addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
for(unsigned n = 0; n < bpp; n++) {
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
for(uint n : range(bpp)) {
uint byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
uint8 data = 0x00;
for(unsigned x = 0; x < 8; x++) data |= ((cache.data[x] >> n) & 1) << x;
for(uint x : range(8)) data |= ((cache.data[x] >> n) & 1) << x;
if(cache.bitpend != 0xff) {
step(regs.clsr ? 5 : 6);
data &= cache.bitpend;
data |= bus_read(addr + byte) & ~cache.bitpend;
data |= read(addr + byte) & ~cache.bitpend;
}
step(regs.clsr ? 5 : 6);
bus_write(addr + byte, data);
write(addr + byte, data);
}
cache.bitpend = 0x00;

View File

@ -1,10 +1,10 @@
auto SuperFX::bus_read(uint24 addr, uint8 data) -> uint8 {
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff
auto SuperFX::read(uint24 addr, uint8 data) -> uint8 {
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff,:8000-ffff
while(!regs.scmr.ron && !scheduler.synchronizing()) {
step(6);
synchronizeCPU();
}
return rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
return rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & romMask);
}
if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff
@ -12,7 +12,7 @@ auto SuperFX::bus_read(uint24 addr, uint8 data) -> uint8 {
step(6);
synchronizeCPU();
}
return rom.read(addr & rom_mask);
return rom.read(addr & romMask);
}
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
@ -20,31 +20,31 @@ auto SuperFX::bus_read(uint24 addr, uint8 data) -> uint8 {
step(6);
synchronizeCPU();
}
return ram.read(addr & ram_mask);
return ram.read(addr & ramMask);
}
return data;
}
auto SuperFX::bus_write(uint24 addr, uint8 data) -> void {
auto SuperFX::write(uint24 addr, uint8 data) -> void {
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
while(!regs.scmr.ran && !scheduler.synchronizing()) {
step(6);
synchronizeCPU();
}
return ram.write(addr & ram_mask, data);
return ram.write(addr & ramMask, data);
}
}
auto SuperFX::op_read(uint16 addr) -> uint8 {
auto SuperFX::readOpcode(uint16 addr) -> uint8 {
uint16 offset = addr - regs.cbr;
if(offset < 512) {
if(cache.valid[offset >> 4] == false) {
unsigned dp = offset & 0xfff0;
unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
for(unsigned n = 0; n < 16; n++) {
uint dp = offset & 0xfff0;
uint sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
for(uint n : range(16)) {
step(regs.clsr ? 5 : 6);
cache.buffer[dp++] = bus_read(sp++);
cache.buffer[dp++] = read(sp++);
}
cache.valid[offset >> 4] = true;
} else {
@ -54,55 +54,43 @@ auto SuperFX::op_read(uint16 addr) -> uint8 {
}
if(regs.pbr <= 0x5f) {
//$[00-5f]:[0000-ffff] ROM
rombuffer_sync();
//$00-5f:0000-ffff ROM
syncROMBuffer();
step(regs.clsr ? 5 : 6);
return bus_read((regs.pbr << 16) + addr);
return read(regs.pbr << 16 | addr);
} else {
//$[60-7f]:[0000-ffff] RAM
rambuffer_sync();
//$60-7f:0000-ffff RAM
syncRAMBuffer();
step(regs.clsr ? 5 : 6);
return bus_read((regs.pbr << 16) + addr);
return read(regs.pbr << 16 | addr);
}
}
auto SuperFX::peekpipe() -> uint8 {
uint8 result = regs.pipeline;
regs.pipeline = op_read(regs.r[15]);
r15_modified = false;
regs.pipeline = readOpcode(regs.r[15]);
regs.r[15].modified = false;
return result;
}
auto SuperFX::pipe() -> uint8 {
uint8 result = regs.pipeline;
regs.pipeline = op_read(++regs.r[15]);
r15_modified = false;
regs.pipeline = readOpcode(++regs.r[15]);
regs.r[15].modified = false;
return result;
}
auto SuperFX::cache_flush() -> void {
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;
auto SuperFX::flushCache() -> void {
for(uint n : range(32)) cache.valid[n] = false;
}
auto SuperFX::cache_mmio_read(uint16 addr) -> uint8 {
auto SuperFX::readCache(uint16 addr) -> uint8 {
addr = (addr + regs.cbr) & 511;
return cache.buffer[addr];
}
auto SuperFX::cache_mmio_write(uint16 addr, uint8 data) -> void {
auto SuperFX::writeCache(uint16 addr, uint8 data) -> void {
addr = (addr + regs.cbr) & 511;
cache.buffer[addr] = data;
if((addr & 15) == 15) cache.valid[addr >> 4] = true;
}
auto SuperFX::memory_reset() -> void {
rom_mask = rom.size() - 1;
ram_mask = ram.size() - 1;
for(unsigned n = 0; n < 512; n++) cache.buffer[n] = 0x00;
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;
for(unsigned n = 0; n < 2; n++) {
pixelcache[n].offset = ~0;
pixelcache[n].bitpend = 0x00;
}
}

View File

@ -3,7 +3,7 @@ auto SuperFX::readIO(uint24 addr, uint8) -> uint8 {
addr = 0x3000 | addr.bits(0,9);
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache_mmio_read(addr - 0x3100);
return readCache(addr - 0x3100);
}
if(addr >= 0x3000 && addr <= 0x301f) {
@ -55,7 +55,7 @@ auto SuperFX::writeIO(uint24 addr, uint8 data) -> void {
addr = 0x3000 | addr.bits(0,9);
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache_mmio_write(addr - 0x3100, data);
return writeCache(addr - 0x3100, data);
}
if(addr >= 0x3000 && addr <= 0x301f) {
@ -65,6 +65,7 @@ auto SuperFX::writeIO(uint24 addr, uint8 data) -> void {
} else {
regs.r[n] = (data << 8) | (regs.r[n] & 0xff);
}
if(n == 14) updateROMBuffer();
if(addr == 0x301f) regs.sfr.g = 1;
return;
@ -76,7 +77,7 @@ auto SuperFX::writeIO(uint24 addr, uint8 data) -> void {
regs.sfr = (regs.sfr & 0xff00) | (data << 0);
if(g == 1 && regs.sfr.g == 0) {
regs.cbr = 0x0000;
cache_flush();
flushCache();
}
} break;
@ -90,7 +91,7 @@ auto SuperFX::writeIO(uint24 addr, uint8 data) -> void {
case 0x3034: {
regs.pbr = data & 0x7f;
cache_flush();
flushCache();
} break;
case 0x3037: {

View File

@ -3,5 +3,4 @@ auto SuperFX::serialize(serializer& s) -> void {
Thread::serialize(s);
s.array(ram.data(), ram.size());
s.integer(r15_modified);
}

View File

@ -16,13 +16,22 @@ auto SuperFX::Enter() -> void {
auto SuperFX::main() -> void {
if(regs.sfr.g == 0) return step(6);
instruction(peekpipe());
if(!r15_modified) regs.r[15]++;
if(regs.r[14].modified) {
regs.r[14].modified = false;
updateROMBuffer();
}
if(regs.r[15].modified) {
regs.r[15].modified = false;
} else {
regs.r[15]++;
}
}
auto SuperFX::init() -> void {
regs.r[14].modify = {&SuperFX::r14_modify, this};
regs.r[15].modify = {&SuperFX::r15_modify, this};
}
auto SuperFX::load() -> void {
@ -40,8 +49,23 @@ auto SuperFX::power() -> void {
auto SuperFX::reset() -> void {
GSU::reset();
create(SuperFX::Enter, system.cpuFrequency());
memory_reset();
timing_reset();
romMask = rom.size() - 1;
ramMask = ram.size() - 1;
for(uint n : range(512)) cache.buffer[n] = 0x00;
for(uint n : range(32)) cache.valid[n] = false;
for(uint n : range(2)) {
pixelcache[n].offset = ~0;
pixelcache[n].bitpend = 0x00;
}
regs.romcl = 0;
regs.romdr = 0;
regs.ramcl = 0;
regs.ramar = 0;
regs.ramdr = 0;
}
}

View File

@ -25,45 +25,39 @@ struct SuperFX : Processor::GSU, Cothread {
};
//core.cpp
auto stop() -> void;
auto color(uint8 source) -> uint8;
auto plot(uint8 x, uint8 y) -> void;
auto rpix(uint8 x, uint8 y) -> uint8;
auto pixelcache_flush(pixelcache_t& cache) -> void;
auto stop() -> void override;
auto color(uint8 source) -> uint8 override;
auto plot(uint8 x, uint8 y) -> void override;
auto rpix(uint8 x, uint8 y) -> uint8 override;
auto flushPixelCache(PixelCache& cache) -> void;
//memory.cpp
auto bus_read(uint24 addr, uint8 data = 0x00) -> uint8 override;
auto bus_write(uint24 addr, uint8 data) -> void override;
auto read(uint24 addr, uint8 data = 0x00) -> uint8 override;
auto write(uint24 addr, uint8 data) -> void override;
auto op_read(uint16 addr) -> uint8;
auto readOpcode(uint16 addr) -> uint8;
alwaysinline auto peekpipe() -> uint8;
alwaysinline auto pipe() -> uint8;
alwaysinline auto pipe() -> uint8 override;
auto cache_flush() -> void;
auto cache_mmio_read(uint16 addr) -> uint8;
auto cache_mmio_write(uint16 addr, uint8 data) -> void;
auto memory_reset() -> void;
auto flushCache() -> void override;
auto readCache(uint16 addr) -> uint8;
auto writeCache(uint16 addr, uint8 data) -> void;
//mmio.cpp
auto readIO(uint24 addr, uint8 data) -> uint8;
auto writeIO(uint24 addr, uint8 data) -> void;
//timing.cpp
auto step(uint clocks) -> void;
auto step(uint clocks) -> void override;
auto rombuffer_sync() -> void;
auto rombuffer_update() -> void;
auto rombuffer_read() -> uint8;
auto syncROMBuffer() -> void override;
auto readROMBuffer() -> uint8 override;
auto updateROMBuffer() -> void;
auto rambuffer_sync() -> void;
auto rambuffer_read(uint16 addr) -> uint8;
auto rambuffer_write(uint16 addr, uint8 data) -> void;
auto r14_modify(uint16) -> void;
auto r15_modify(uint16) -> void;
auto timing_reset() -> void;
auto syncRAMBuffer() -> void override;
auto readRAMBuffer(uint16 addr) -> uint8 override;
auto writeRAMBuffer(uint16 addr, uint8 data) -> void override;
//serialization.cpp
auto serialize(serializer&) -> void;
@ -72,10 +66,8 @@ struct SuperFX : Processor::GSU, Cothread {
CPURAM cpuram;
private:
uint rom_mask; //rom_size - 1
uint ram_mask; //ram_size - 1
bool r15_modified = false;
uint romMask;
uint ramMask;
};
extern SuperFX superfx;

View File

@ -3,14 +3,14 @@ auto SuperFX::step(uint clocks) -> void {
regs.romcl -= min(clocks, regs.romcl);
if(regs.romcl == 0) {
regs.sfr.r = 0;
regs.romdr = bus_read((regs.rombr << 16) + regs.r[14]);
regs.romdr = read((regs.rombr << 16) + regs.r[14]);
}
}
if(regs.ramcl) {
regs.ramcl -= min(clocks, regs.ramcl);
if(regs.ramcl == 0) {
bus_write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr);
write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr);
}
}
@ -18,53 +18,32 @@ auto SuperFX::step(uint clocks) -> void {
synchronizeCPU();
}
auto SuperFX::rombuffer_sync() -> void {
auto SuperFX::syncROMBuffer() -> void {
if(regs.romcl) step(regs.romcl);
}
auto SuperFX::rombuffer_update() -> void {
auto SuperFX::readROMBuffer() -> uint8 {
syncROMBuffer();
return regs.romdr;
}
auto SuperFX::updateROMBuffer() -> void {
regs.sfr.r = 1;
regs.romcl = regs.clsr ? 5 : 6;
}
auto SuperFX::rombuffer_read() -> uint8 {
rombuffer_sync();
return regs.romdr;
}
auto SuperFX::rambuffer_sync() -> void {
auto SuperFX::syncRAMBuffer() -> void {
if(regs.ramcl) step(regs.ramcl);
}
auto SuperFX::rambuffer_read(uint16 addr) -> uint8 {
rambuffer_sync();
return bus_read(0x700000 + (regs.rambr << 16) + addr);
auto SuperFX::readRAMBuffer(uint16 addr) -> uint8 {
syncRAMBuffer();
return read(0x700000 + (regs.rambr << 16) + addr);
}
auto SuperFX::rambuffer_write(uint16 addr, uint8 data) -> void {
rambuffer_sync();
auto SuperFX::writeRAMBuffer(uint16 addr, uint8 data) -> void {
syncRAMBuffer();
regs.ramcl = regs.clsr ? 5 : 6;
regs.ramar = addr;
regs.ramdr = data;
}
auto SuperFX::r14_modify(uint16 data) -> void {
regs.r[14].data = data;
rombuffer_update();
}
auto SuperFX::r15_modify(uint16 data) -> void {
regs.r[15].data = data;
r15_modified = true;
}
auto SuperFX::timing_reset() -> void {
r15_modified = false;
regs.romcl = 0;
regs.romdr = 0;
regs.ramcl = 0;
regs.ramar = 0;
regs.ramdr = 0;
}