mirror of
https://github.com/libretro/bsnes-libretro-cplusplus98.git
synced 2025-04-13 07:30:47 +00:00
snes::
This commit is contained in:
parent
3b29d40426
commit
ce9e66b27a
@ -90,6 +90,30 @@ void CPU::op_irq(uint16 vector) {
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
|
||||
read = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
regs.a = 0x0000;
|
||||
regs.x = 0x0000;
|
||||
|
@ -1,5 +1,7 @@
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO {
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
public:
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum{ Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
@ -20,6 +22,7 @@ public:
|
||||
debugvirtual void op_write(unsigned addr, uint8 data);
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -8,13 +8,11 @@ void CPUDebugger::op_step() {
|
||||
opcode_pc = regs.pc;
|
||||
|
||||
opcode_edge = true;
|
||||
if(debugger.step_cpu) {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
if(step_event && step_event()) {
|
||||
debugger.break_event = Debugger::BreakEvent::CPUStep;
|
||||
scheduler.exit(Scheduler::ExitReason::DebuggerEvent);
|
||||
} else {
|
||||
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00);
|
||||
}
|
||||
if(step_event) step_event();
|
||||
opcode_edge = false;
|
||||
|
||||
CPU::op_step();
|
||||
|
@ -2,7 +2,7 @@ class CPUDebugger : public CPU, public ChipDebugger {
|
||||
public:
|
||||
bool property(unsigned id, string &name, string &value);
|
||||
|
||||
function<void ()> step_event;
|
||||
function<bool ()> step_event;
|
||||
|
||||
enum Usage {
|
||||
UsageRead = 0x80,
|
||||
|
@ -5,6 +5,8 @@ void CPU::serialize(serializer &s) {
|
||||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
|
||||
queue.serialize(s);
|
||||
s.array(port_data);
|
||||
|
||||
|
@ -40,7 +40,7 @@ void DSP::write(uint8 addr, uint8 data) {
|
||||
}
|
||||
|
||||
void DSP::power() {
|
||||
spc_dsp.init(memory::apuram.data());
|
||||
spc_dsp.init(smp.apuram);
|
||||
spc_dsp.reset();
|
||||
spc_dsp.set_output(samplebuffer, 8192);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
data = memory::vram[addr];
|
||||
data = vram[addr];
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
@ -39,12 +39,12 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
data = 0x00;
|
||||
} else if(v == (!overscan() ? 224 : 239)) {
|
||||
if(h == 1362) {
|
||||
data = memory::vram[addr];
|
||||
data = vram[addr];
|
||||
} else {
|
||||
data = 0x00;
|
||||
}
|
||||
} else {
|
||||
data = memory::vram[addr];
|
||||
data = vram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,15 +53,15 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
|
||||
|
||||
void PPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(regs.display_disabled == true) {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v == 0) {
|
||||
if(h <= 4) {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
} else if(h == 6) {
|
||||
memory::vram[addr] = cpu.regs.mdr;
|
||||
vram[addr] = cpu.regs.mdr;
|
||||
} else {
|
||||
//no write
|
||||
}
|
||||
@ -71,10 +71,10 @@ void PPU::vram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(h <= 4) {
|
||||
//no write
|
||||
} else {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
}
|
||||
} else {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,12 +85,12 @@ uint8 PPU::oam_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
data = memory::oam[addr];
|
||||
data = oam[addr];
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
data = memory::oam[regs.ioamaddr];
|
||||
data = oam[regs.ioamaddr];
|
||||
} else {
|
||||
data = memory::oam[addr];
|
||||
data = oam[addr];
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,14 +104,14 @@ void PPU::oam_mmio_write(uint16 addr, uint8 data) {
|
||||
sprite_list_valid = false;
|
||||
|
||||
if(regs.display_disabled == true) {
|
||||
memory::oam[addr] = data;
|
||||
oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
} else {
|
||||
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
|
||||
memory::oam[regs.ioamaddr] = data;
|
||||
oam[regs.ioamaddr] = data;
|
||||
update_sprite_list(regs.ioamaddr, data);
|
||||
} else {
|
||||
memory::oam[addr] = data;
|
||||
oam[addr] = data;
|
||||
update_sprite_list(addr, data);
|
||||
}
|
||||
}
|
||||
@ -122,14 +122,14 @@ uint8 PPU::cgram_mmio_read(uint16 addr) {
|
||||
uint8 data;
|
||||
|
||||
if(1 || regs.display_disabled == true) {
|
||||
data = memory::cgram[addr];
|
||||
data = cgram[addr];
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
|
||||
data = memory::cgram[regs.icgramaddr] & 0x7f;
|
||||
data = cgram[regs.icgramaddr] & 0x7f;
|
||||
} else {
|
||||
data = memory::cgram[addr];
|
||||
data = cgram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,14 +142,14 @@ void PPU::cgram_mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr & 1) data &= 0x7f;
|
||||
|
||||
if(1 || regs.display_disabled == true) {
|
||||
memory::cgram[addr] = data;
|
||||
cgram[addr] = data;
|
||||
} else {
|
||||
uint16 v = cpu.vcounter();
|
||||
uint16 h = cpu.hcounter();
|
||||
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
|
||||
memory::cgram[regs.icgramaddr] = data & 0x7f;
|
||||
cgram[regs.icgramaddr] = data & 0x7f;
|
||||
} else {
|
||||
memory::cgram[addr] = data;
|
||||
cgram[addr] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,13 +122,21 @@ void PPU::frame() {
|
||||
framecounter = (frameskip == 0 ? 0 : (framecounter + 1) % frameskip);
|
||||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
ppu1_version = config.ppu1.version;
|
||||
ppu2_version = config.ppu2.version;
|
||||
|
||||
for(unsigned i = 0; i < memory::vram.size(); i++) memory::vram[i] = 0x00;
|
||||
for(unsigned i = 0; i < memory::oam.size(); i++) memory::oam[i] = 0x00;
|
||||
for(unsigned i = 0; i < memory::cgram.size(); i++) memory::cgram[i] = 0x00;
|
||||
foreach(n, vram) n = 0x00;
|
||||
foreach(n, oam) n = 0x00;
|
||||
foreach(n, cgram) n = 0x00;
|
||||
flush_tiledata_cache();
|
||||
|
||||
region = (system.region.i == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL
|
||||
|
@ -1,5 +1,9 @@
|
||||
class PPU : public Processor, public PPUcounter, public MMIO {
|
||||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8 vram[128 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
enum{ Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
@ -56,6 +60,7 @@ public:
|
||||
void render_scanline();
|
||||
void frame();
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -32,7 +32,7 @@ uint16 PPU::bg_get_tile(uint16 x, uint16 y) {
|
||||
if(x & 0x20) pos += bg_info[bg].scx;
|
||||
|
||||
const uint16 addr = regs.bg_scaddr[bg] + (pos << 1);
|
||||
return memory::vram[addr] + (memory::vram[addr + 1] << 8);
|
||||
return vram[addr] + (vram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
#define setpixel_main(x) \
|
||||
|
@ -32,8 +32,8 @@ void PPU::render_bg_tile(uint16 tile_num) {
|
||||
unsigned pos = tile_num * 16;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = memory::vram[pos ];
|
||||
d1 = memory::vram[pos + 1];
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
render_bg_tile_line_2bpp(0x80);
|
||||
render_bg_tile_line_2bpp(0x40);
|
||||
render_bg_tile_line_2bpp(0x20);
|
||||
@ -52,10 +52,10 @@ void PPU::render_bg_tile(uint16 tile_num) {
|
||||
unsigned pos = tile_num * 32;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = memory::vram[pos ];
|
||||
d1 = memory::vram[pos + 1];
|
||||
d2 = memory::vram[pos + 16];
|
||||
d3 = memory::vram[pos + 17];
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
render_bg_tile_line_4bpp(0x80);
|
||||
render_bg_tile_line_4bpp(0x40);
|
||||
render_bg_tile_line_4bpp(0x20);
|
||||
@ -74,14 +74,14 @@ void PPU::render_bg_tile(uint16 tile_num) {
|
||||
unsigned pos = tile_num * 64;
|
||||
unsigned y = 8;
|
||||
while(y--) {
|
||||
d0 = memory::vram[pos ];
|
||||
d1 = memory::vram[pos + 1];
|
||||
d2 = memory::vram[pos + 16];
|
||||
d3 = memory::vram[pos + 17];
|
||||
d4 = memory::vram[pos + 32];
|
||||
d5 = memory::vram[pos + 33];
|
||||
d6 = memory::vram[pos + 48];
|
||||
d7 = memory::vram[pos + 49];
|
||||
d0 = vram[pos ];
|
||||
d1 = vram[pos + 1];
|
||||
d2 = vram[pos + 16];
|
||||
d3 = vram[pos + 17];
|
||||
d4 = vram[pos + 32];
|
||||
d5 = vram[pos + 33];
|
||||
d6 = vram[pos + 48];
|
||||
d7 = vram[pos + 49];
|
||||
render_bg_tile_line_8bpp(0x80);
|
||||
render_bg_tile_line_8bpp(0x40);
|
||||
render_bg_tile_line_8bpp(0x20);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
inline uint16 PPU::get_palette(uint8 index) {
|
||||
const unsigned addr = index << 1;
|
||||
return memory::cgram[addr] + (memory::cgram[addr + 1] << 8);
|
||||
return cgram[addr] + (cgram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
//p = 00000bgr <palette data>
|
||||
|
@ -71,8 +71,8 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
case 2: { //palette color 0 outside of screen area
|
||||
if((px | py) & ~1023) {
|
||||
@ -82,8 +82,8 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
} break;
|
||||
case 3: { //character 0 repetition outside of screen area
|
||||
@ -94,9 +94,9 @@ void PPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
tile = vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
palette = vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,10 @@ void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
|
||||
s.integer(ppu1_version);
|
||||
s.integer(ppu2_version);
|
||||
|
||||
|
@ -11,7 +11,7 @@ unsigned PPU::Background::get_tile(unsigned hoffset, unsigned voffset) {
|
||||
if(tile_x & 0x20) tile_pos += scx;
|
||||
|
||||
const uint16 tiledata_addr = regs.screen_addr + (tile_pos << 1);
|
||||
return (memory::vram[tiledata_addr + 0] << 0) + (memory::vram[tiledata_addr + 1] << 8);
|
||||
return (ppu.vram[tiledata_addr + 0] << 0) + (ppu.vram[tiledata_addr + 1] << 8);
|
||||
}
|
||||
|
||||
void PPU::Background::offset_per_tile(unsigned x, unsigned y, unsigned &hoffset, unsigned &voffset) {
|
||||
|
@ -43,8 +43,8 @@ void PPU::Background::render_mode7() {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@ -56,8 +56,8 @@ void PPU::Background::render_mode7() {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -70,9 +70,9 @@ void PPU::Background::render_mode7() {
|
||||
py &= 1023;
|
||||
tx = ((px >> 3) & 127);
|
||||
ty = ((py >> 3) & 127);
|
||||
tile = memory::vram[(ty * 128 + tx) << 1];
|
||||
tile = ppu.vram[(ty * 128 + tx) << 1];
|
||||
}
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
28
snes/alt/ppu-performance/cache/cache.cpp
vendored
28
snes/alt/ppu-performance/cache/cache.cpp
vendored
@ -8,8 +8,8 @@ uint8* PPU::Cache::tile_2bpp(unsigned tile) {
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1;
|
||||
while(y--) {
|
||||
d0 = memory::vram[offset + 0];
|
||||
d1 = memory::vram[offset + 1];
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
@ -37,10 +37,10 @@ uint8* PPU::Cache::tile_4bpp(unsigned tile) {
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1, d2, d3;
|
||||
while(y--) {
|
||||
d0 = memory::vram[offset + 0];
|
||||
d1 = memory::vram[offset + 1];
|
||||
d2 = memory::vram[offset + 16];
|
||||
d3 = memory::vram[offset + 17];
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
d2 = ppu.vram[offset + 16];
|
||||
d3 = ppu.vram[offset + 17];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
@ -70,14 +70,14 @@ uint8* PPU::Cache::tile_8bpp(unsigned tile) {
|
||||
unsigned y = 8;
|
||||
unsigned color, d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
while(y--) {
|
||||
d0 = memory::vram[offset + 0];
|
||||
d1 = memory::vram[offset + 1];
|
||||
d2 = memory::vram[offset + 16];
|
||||
d3 = memory::vram[offset + 17];
|
||||
d4 = memory::vram[offset + 32];
|
||||
d5 = memory::vram[offset + 33];
|
||||
d6 = memory::vram[offset + 48];
|
||||
d7 = memory::vram[offset + 49];
|
||||
d0 = ppu.vram[offset + 0];
|
||||
d1 = ppu.vram[offset + 1];
|
||||
d2 = ppu.vram[offset + 16];
|
||||
d3 = ppu.vram[offset + 17];
|
||||
d4 = ppu.vram[offset + 32];
|
||||
d5 = ppu.vram[offset + 33];
|
||||
d6 = ppu.vram[offset + 48];
|
||||
d7 = ppu.vram[offset + 49];
|
||||
#define render_line(mask) \
|
||||
color = !!(d0 & mask) << 0; \
|
||||
color |= !!(d1 & mask) << 1; \
|
||||
|
@ -22,14 +22,14 @@ uint16 PPU::get_vram_addr() {
|
||||
}
|
||||
|
||||
uint8 PPU::vram_read(unsigned addr) {
|
||||
if(regs.display_disable) return memory::vram[addr];
|
||||
if(cpu.vcounter() >= display.height) return memory::vram[addr];
|
||||
if(regs.display_disable) return vram[addr];
|
||||
if(cpu.vcounter() >= display.height) return vram[addr];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void PPU::vram_write(unsigned addr, uint8 data) {
|
||||
if(regs.display_disable || cpu.vcounter() >= display.height) {
|
||||
memory::vram[addr] = data;
|
||||
vram[addr] = data;
|
||||
cache.tilevalid[0][addr >> 4] = false;
|
||||
cache.tilevalid[1][addr >> 5] = false;
|
||||
cache.tilevalid[2][addr >> 6] = false;
|
||||
@ -39,24 +39,24 @@ void PPU::vram_write(unsigned addr, uint8 data) {
|
||||
|
||||
uint8 PPU::oam_read(unsigned addr) {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(regs.display_disable) return memory::oam[addr];
|
||||
if(cpu.vcounter() >= display.height) return memory::oam[addr];
|
||||
return memory::oam[0x0218];
|
||||
if(regs.display_disable) return oam[addr];
|
||||
if(cpu.vcounter() >= display.height) return oam[addr];
|
||||
return oam[0x0218];
|
||||
}
|
||||
|
||||
void PPU::oam_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(!regs.display_disable && cpu.vcounter() < display.height) addr = 0x0218;
|
||||
memory::oam[addr] = data;
|
||||
oam.update_list(addr, data);
|
||||
oam[addr] = data;
|
||||
sprite.update_list(addr, data);
|
||||
}
|
||||
|
||||
uint8 PPU::cgram_read(unsigned addr) {
|
||||
return memory::cgram[addr];
|
||||
return cgram[addr];
|
||||
}
|
||||
|
||||
void PPU::cgram_write(unsigned addr, uint8 data) {
|
||||
memory::cgram[addr] = data;
|
||||
cgram[addr] = data;
|
||||
}
|
||||
|
||||
void PPU::mmio_update_video_mode() {
|
||||
@ -66,7 +66,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10;
|
||||
bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5;
|
||||
bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4;
|
||||
oam.regs.priority0 = 3; oam.regs.priority1 = 6; oam.regs.priority2 = 9; oam.regs.priority3 = 12;
|
||||
sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12;
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
@ -78,12 +78,12 @@ void PPU::mmio_update_video_mode() {
|
||||
bg1.regs.priority0 = 5; bg1.regs.priority1 = 8;
|
||||
bg2.regs.priority0 = 4; bg2.regs.priority1 = 7;
|
||||
bg3.regs.priority0 = 1; bg3.regs.priority1 = 10;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 3; oam.regs.priority2 = 6; oam.regs.priority3 = 9;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9;
|
||||
} else {
|
||||
bg1.regs.priority0 = 6; bg1.regs.priority1 = 9;
|
||||
bg2.regs.priority0 = 5; bg2.regs.priority1 = 8;
|
||||
bg3.regs.priority0 = 1; bg3.regs.priority1 = 3;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 7; oam.regs.priority3 = 10;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10;
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -94,7 +94,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 3: {
|
||||
@ -104,7 +104,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 4: {
|
||||
@ -114,7 +114,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 5: {
|
||||
@ -124,7 +124,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 8;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8;
|
||||
} break;
|
||||
|
||||
case 6: {
|
||||
@ -133,7 +133,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 6;
|
||||
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6;
|
||||
} break;
|
||||
|
||||
case 7: {
|
||||
@ -143,7 +143,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 2;
|
||||
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 5;
|
||||
sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5;
|
||||
} else {
|
||||
bg1.regs.mode = Background::Mode::Mode7;
|
||||
bg2.regs.mode = Background::Mode::Mode7;
|
||||
@ -151,7 +151,7 @@ void PPU::mmio_update_video_mode() {
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 3;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 7;
|
||||
sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -193,7 +193,7 @@ uint8 PPU::mmio_read(unsigned addr) {
|
||||
case 0x2138: { //OAMDATAREAD
|
||||
regs.ppu1_mdr = oam_read(regs.oam_addr);
|
||||
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
|
||||
oam.set_first();
|
||||
sprite.set_first();
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
|
||||
@ -251,8 +251,8 @@ uint8 PPU::mmio_read(unsigned addr) {
|
||||
|
||||
case 0x213e: { //STAT77
|
||||
regs.ppu1_mdr &= 0x10;
|
||||
regs.ppu1_mdr |= oam.regs.time_over << 7;
|
||||
regs.ppu1_mdr |= oam.regs.range_over << 6;
|
||||
regs.ppu1_mdr |= sprite.regs.time_over << 7;
|
||||
regs.ppu1_mdr |= sprite.regs.range_over << 6;
|
||||
regs.ppu1_mdr |= 0x01; //version
|
||||
return regs.ppu1_mdr;
|
||||
}
|
||||
@ -283,30 +283,30 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
|
||||
switch(addr & 0xffff) {
|
||||
case 0x2100: { //INIDISP
|
||||
if(regs.display_disable && cpu.vcounter() == display.height) oam.address_reset();
|
||||
if(regs.display_disable && cpu.vcounter() == display.height) sprite.address_reset();
|
||||
regs.display_disable = data & 0x80;
|
||||
regs.display_brightness = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2101: { //OBSEL
|
||||
oam.regs.base_size = (data >> 5) & 7;
|
||||
oam.regs.nameselect = (data >> 3) & 3;
|
||||
oam.regs.tiledata_addr = (data & 3) << 14;
|
||||
oam.list_valid = false;
|
||||
sprite.regs.base_size = (data >> 5) & 7;
|
||||
sprite.regs.nameselect = (data >> 3) & 3;
|
||||
sprite.regs.tiledata_addr = (data & 3) << 14;
|
||||
sprite.list_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2102: { //OAMADDL
|
||||
regs.oam_baseaddr = (regs.oam_baseaddr & 0x0100) | (data << 0);
|
||||
oam.address_reset();
|
||||
sprite.address_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x2103: { //OAMADDH
|
||||
regs.oam_priority = data & 0x80;
|
||||
regs.oam_baseaddr = ((data & 1) << 8) | (regs.oam_baseaddr & 0x00ff);
|
||||
oam.address_reset();
|
||||
sprite.address_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
oam_write((regs.oam_addr & ~1) + 1, data);
|
||||
}
|
||||
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
|
||||
oam.set_first();
|
||||
sprite.set_first();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -561,10 +561,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
screen.window.two_invert = data & 0x40;
|
||||
screen.window.one_enable = data & 0x20;
|
||||
screen.window.one_invert = data & 0x10;
|
||||
oam.window.two_enable = data & 0x08;
|
||||
oam.window.two_invert = data & 0x04;
|
||||
oam.window.one_enable = data & 0x02;
|
||||
oam.window.one_invert = data & 0x01;
|
||||
sprite.window.two_enable = data & 0x08;
|
||||
sprite.window.two_invert = data & 0x04;
|
||||
sprite.window.one_enable = data & 0x02;
|
||||
sprite.window.one_invert = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -598,12 +598,12 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
|
||||
case 0x212b: { //WOBJLOG
|
||||
screen.window.mask = (data >> 2) & 3;
|
||||
oam.window.mask = (data >> 0) & 3;
|
||||
sprite.window.mask = (data >> 0) & 3;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x212c: { //TM
|
||||
oam.regs.main_enable = data & 0x10;
|
||||
sprite.regs.main_enable = data & 0x10;
|
||||
bg4.regs.main_enable = data & 0x08;
|
||||
bg3.regs.main_enable = data & 0x04;
|
||||
bg2.regs.main_enable = data & 0x02;
|
||||
@ -612,7 +612,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x212d: { //TS
|
||||
oam.regs.sub_enable = data & 0x10;
|
||||
sprite.regs.sub_enable = data & 0x10;
|
||||
bg4.regs.sub_enable = data & 0x08;
|
||||
bg3.regs.sub_enable = data & 0x04;
|
||||
bg2.regs.sub_enable = data & 0x02;
|
||||
@ -621,7 +621,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x212e: { //TMW
|
||||
oam.window.main_enable = data & 0x10;
|
||||
sprite.window.main_enable = data & 0x10;
|
||||
bg4.window.main_enable = data & 0x08;
|
||||
bg3.window.main_enable = data & 0x04;
|
||||
bg2.window.main_enable = data & 0x02;
|
||||
@ -630,7 +630,7 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
case 0x212f: { //TSW
|
||||
oam.window.sub_enable = data & 0x10;
|
||||
sprite.window.sub_enable = data & 0x10;
|
||||
bg4.window.sub_enable = data & 0x08;
|
||||
bg3.window.sub_enable = data & 0x04;
|
||||
bg2.window.sub_enable = data & 0x02;
|
||||
@ -671,10 +671,10 @@ void PPU::mmio_write(unsigned addr, uint8 data) {
|
||||
regs.mode7_extbg = data & 0x40;
|
||||
regs.pseudo_hires = data & 0x08;
|
||||
regs.overscan = data & 0x04;
|
||||
oam.regs.interlace = data & 0x02;
|
||||
sprite.regs.interlace = data & 0x02;
|
||||
regs.interlace = data & 0x01;
|
||||
mmio_update_video_mode();
|
||||
oam.list_valid = false;
|
||||
sprite.list_valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -695,17 +695,17 @@ void PPU::mmio_reset() {
|
||||
regs.latch_hcounter = 0;
|
||||
regs.latch_vcounter = 0;
|
||||
|
||||
oam.regs.first_sprite = 0;
|
||||
oam.list_valid = false;
|
||||
sprite.regs.first_sprite = 0;
|
||||
sprite.list_valid = false;
|
||||
|
||||
//$2100
|
||||
regs.display_disable = true;
|
||||
regs.display_brightness = 0;
|
||||
|
||||
//$2101
|
||||
oam.regs.base_size = 0;
|
||||
oam.regs.nameselect = 0;
|
||||
oam.regs.tiledata_addr = 0;
|
||||
sprite.regs.base_size = 0;
|
||||
sprite.regs.nameselect = 0;
|
||||
sprite.regs.tiledata_addr = 0;
|
||||
|
||||
//$2102-$2103
|
||||
regs.oam_baseaddr = 0;
|
||||
@ -799,10 +799,10 @@ void PPU::mmio_reset() {
|
||||
bg4.window.two_enable = 0;
|
||||
bg4.window.two_invert = 0;
|
||||
|
||||
oam.window.one_enable = 0;
|
||||
oam.window.one_invert = 0;
|
||||
oam.window.two_enable = 0;
|
||||
oam.window.two_invert = 0;
|
||||
sprite.window.one_enable = 0;
|
||||
sprite.window.one_invert = 0;
|
||||
sprite.window.two_enable = 0;
|
||||
sprite.window.two_invert = 0;
|
||||
|
||||
screen.window.one_enable = 0;
|
||||
screen.window.one_invert = 0;
|
||||
@ -820,7 +820,7 @@ void PPU::mmio_reset() {
|
||||
bg2.window.mask = 0;
|
||||
bg3.window.mask = 0;
|
||||
bg4.window.mask = 0;
|
||||
oam.window.mask = 0;
|
||||
sprite.window.mask = 0;
|
||||
screen.window.mask = 0;
|
||||
|
||||
//$212c
|
||||
@ -828,28 +828,28 @@ void PPU::mmio_reset() {
|
||||
bg2.regs.main_enable = 0;
|
||||
bg3.regs.main_enable = 0;
|
||||
bg4.regs.main_enable = 0;
|
||||
oam.regs.main_enable = 0;
|
||||
sprite.regs.main_enable = 0;
|
||||
|
||||
//$212d
|
||||
bg1.regs.sub_enable = 0;
|
||||
bg2.regs.sub_enable = 0;
|
||||
bg3.regs.sub_enable = 0;
|
||||
bg4.regs.sub_enable = 0;
|
||||
oam.regs.sub_enable = 0;
|
||||
sprite.regs.sub_enable = 0;
|
||||
|
||||
//$212e
|
||||
bg1.window.main_enable = 0;
|
||||
bg2.window.main_enable = 0;
|
||||
bg3.window.main_enable = 0;
|
||||
bg4.window.main_enable = 0;
|
||||
oam.window.main_enable = 0;
|
||||
sprite.window.main_enable = 0;
|
||||
|
||||
//$212f
|
||||
bg1.window.sub_enable = 0;
|
||||
bg2.window.sub_enable = 0;
|
||||
bg3.window.sub_enable = 0;
|
||||
bg4.window.sub_enable = 0;
|
||||
oam.window.sub_enable = 0;
|
||||
sprite.window.sub_enable = 0;
|
||||
|
||||
//$2130
|
||||
screen.window.main_mask = 0;
|
||||
@ -878,12 +878,12 @@ void PPU::mmio_reset() {
|
||||
regs.mode7_extbg = 0;
|
||||
regs.pseudo_hires = 0;
|
||||
regs.overscan = 0;
|
||||
oam.regs.interlace = 0;
|
||||
sprite.regs.interlace = 0;
|
||||
regs.interlace = 0;
|
||||
|
||||
//$213e
|
||||
oam.regs.time_over = 0;
|
||||
oam.regs.range_over = 0;
|
||||
sprite.regs.time_over = 0;
|
||||
sprite.regs.range_over = 0;
|
||||
|
||||
mmio_update_video_mode();
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
|
||||
struct Regs {
|
||||
//internal
|
||||
uint8 ppu1_mdr;
|
||||
@ -86,6 +92,4 @@ uint8 cgram_read(unsigned addr);
|
||||
void cgram_write(unsigned addr, uint8 data);
|
||||
|
||||
void mmio_update_video_mode();
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
void mmio_reset();
|
||||
|
@ -68,7 +68,7 @@ void PPU::render_scanline() {
|
||||
bg2.render();
|
||||
bg3.render();
|
||||
bg4.render();
|
||||
oam.render();
|
||||
sprite.render();
|
||||
screen.render();
|
||||
}
|
||||
|
||||
@ -76,21 +76,29 @@ void PPU::scanline() {
|
||||
display.width = !hires() ? 256 : 512;
|
||||
display.height = !overscan() ? 225 : 240;
|
||||
if(vcounter() == 0) frame();
|
||||
if(vcounter() == display.height && regs.display_disable == false) oam.address_reset();
|
||||
if(vcounter() == display.height && regs.display_disable == false) sprite.address_reset();
|
||||
}
|
||||
|
||||
void PPU::frame() {
|
||||
oam.frame();
|
||||
sprite.frame();
|
||||
system.frame();
|
||||
display.interlace = regs.interlace;
|
||||
display.overscan = regs.overscan;
|
||||
display.framecounter = display.frameskip == 0 ? 0 : (display.framecounter + 1) % display.frameskip;
|
||||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
foreach(n, memory::vram) n = 0;
|
||||
foreach(n, memory::oam) n = 0;
|
||||
foreach(n, memory::cgram) n = 0;
|
||||
foreach(n, vram) n = 0;
|
||||
foreach(n, oam) n = 0;
|
||||
foreach(n, cgram) n = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -113,10 +121,10 @@ void PPU::layer_enable(unsigned layer, unsigned priority, bool enable) {
|
||||
case 9: bg3.priority1_enable = enable; break;
|
||||
case 12: bg4.priority0_enable = enable; break;
|
||||
case 13: bg4.priority1_enable = enable; break;
|
||||
case 16: oam.priority0_enable = enable; break;
|
||||
case 17: oam.priority1_enable = enable; break;
|
||||
case 18: oam.priority2_enable = enable; break;
|
||||
case 19: oam.priority3_enable = enable; break;
|
||||
case 16: sprite.priority0_enable = enable; break;
|
||||
case 17: sprite.priority1_enable = enable; break;
|
||||
case 18: sprite.priority2_enable = enable; break;
|
||||
case 19: sprite.priority3_enable = enable; break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,7 +139,7 @@ bg1(*this, Background::ID::BG1),
|
||||
bg2(*this, Background::ID::BG2),
|
||||
bg3(*this, Background::ID::BG3),
|
||||
bg4(*this, Background::ID::BG4),
|
||||
oam(*this),
|
||||
sprite(*this),
|
||||
screen(*this) {
|
||||
surface = new uint16[512 * 512];
|
||||
output = surface + 16 * 512;
|
||||
|
@ -3,8 +3,12 @@
|
||||
|
||||
class PPU;
|
||||
|
||||
class PPU : public Processor, public PPUcounter, public MMIO {
|
||||
class PPU : public Processor, public PPUcounter {
|
||||
public:
|
||||
uint8 vram[64 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
enum{ Threaded = true };
|
||||
alwaysinline void step(unsigned clocks);
|
||||
alwaysinline void synchronize_cpu();
|
||||
@ -15,6 +19,7 @@ public:
|
||||
bool hires() const;
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
void scanline();
|
||||
@ -43,7 +48,7 @@ private:
|
||||
Background bg2;
|
||||
Background bg3;
|
||||
Background bg4;
|
||||
Sprite oam;
|
||||
Sprite sprite;
|
||||
Screen screen;
|
||||
|
||||
struct Display {
|
||||
|
@ -2,11 +2,10 @@
|
||||
|
||||
unsigned PPU::Screen::get_palette(unsigned color) {
|
||||
#if defined(ARCH_LSB)
|
||||
static uint16 *cgram = (uint16*)memory::cgram.data();
|
||||
return cgram[color];
|
||||
return ((uint16*)ppu.cgram)[color];
|
||||
#else
|
||||
color <<= 1;
|
||||
return (memory::cgram[color + 0] << 0) + (memory::cgram[color + 1] << 8);
|
||||
return (ppu.cgram[color + 0] << 0) + (ppu.cgram[color + 1] << 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,16 @@ void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(cgram);
|
||||
|
||||
cache.serialize(s);
|
||||
bg1.serialize(s);
|
||||
bg2.serialize(s);
|
||||
bg3.serialize(s);
|
||||
bg4.serialize(s);
|
||||
oam.serialize(s);
|
||||
sprite.serialize(s);
|
||||
screen.serialize(s);
|
||||
|
||||
s.integer(display.interlace);
|
||||
|
@ -9,18 +9,11 @@ namespace SNES {
|
||||
#include "xml.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
namespace memory {
|
||||
MappedRAM cartrom, cartram, cartrtc;
|
||||
MappedRAM bsxflash, bsxram, bsxpram;
|
||||
MappedRAM stArom, stAram;
|
||||
MappedRAM stBrom, stBram;
|
||||
};
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) {
|
||||
mode.i = cartridge_mode;
|
||||
region.i = Region::NTSC;
|
||||
void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
||||
mode = cartridge_mode;
|
||||
region = Region::NTSC;
|
||||
ram_size = 0;
|
||||
|
||||
has_bsx_slot = false;
|
||||
@ -37,48 +30,25 @@ void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) {
|
||||
has_msu1 = false;
|
||||
has_serial = false;
|
||||
|
||||
nvram.reset();
|
||||
|
||||
parse_xml(xml_list);
|
||||
//print(xml_list[0], "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
|
||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||
nvram.append({ "srm", ram.data(), ram.size() });
|
||||
}
|
||||
|
||||
if(has_srtc || has_spc7110rtc) {
|
||||
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
|
||||
}
|
||||
rom.write_protect(true);
|
||||
ram.write_protect(false);
|
||||
|
||||
if(mode.i == Mode::Bsx) {
|
||||
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
|
||||
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
|
||||
}
|
||||
|
||||
if(mode.i == Mode::SufamiTurbo) {
|
||||
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||
}
|
||||
|
||||
memory::cartrom.write_protect(true);
|
||||
memory::cartram.write_protect(false);
|
||||
memory::cartrtc.write_protect(false);
|
||||
memory::bsxflash.write_protect(true);
|
||||
memory::bsxram.write_protect(false);
|
||||
memory::bsxpram.write_protect(false);
|
||||
memory::stArom.write_protect(true);
|
||||
memory::stAram.write_protect(false);
|
||||
memory::stBrom.write_protect(true);
|
||||
memory::stBram.write_protect(false);
|
||||
|
||||
unsigned checksum = ~0; foreach(n, memory::cartrom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0) foreach(n, memory::bsxflash) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::stArom.size() != 0 && memory::stArom.size() != ~0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
|
||||
crc32 = ~checksum;
|
||||
crc32 = crc32_calculate(rom.data(), rom.size());
|
||||
|
||||
sha256_ctx sha;
|
||||
uint8_t shahash[32];
|
||||
sha256_init(&sha);
|
||||
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
|
||||
sha256_chunk(&sha, rom.data(), rom.size());
|
||||
sha256_final(&sha);
|
||||
sha256_hash(&sha, shahash);
|
||||
|
||||
@ -86,24 +56,15 @@ void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) {
|
||||
foreach(n, shahash) hash << hex<2>(n);
|
||||
sha256 = hash;
|
||||
|
||||
bus.load_cart();
|
||||
system.load();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
memory::cartrom.reset();
|
||||
memory::cartram.reset();
|
||||
memory::cartrtc.reset();
|
||||
memory::bsxflash.reset();
|
||||
memory::bsxram.reset();
|
||||
memory::bsxpram.reset();
|
||||
memory::stArom.reset();
|
||||
memory::stAram.reset();
|
||||
memory::stBrom.reset();
|
||||
memory::stBram.reset();
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
|
||||
if(loaded == false) return;
|
||||
bus.unload_cart();
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,9 @@ public:
|
||||
PAL,
|
||||
} i; };
|
||||
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
|
||||
//assigned externally to point to file-system datafiles (msu1 and serial)
|
||||
//example: "/path/to/filename.sfc" would set this to "/path/to/filename"
|
||||
readwrite<string> basename;
|
||||
@ -39,9 +42,20 @@ public:
|
||||
readonly<bool> has_msu1;
|
||||
readonly<bool> has_serial;
|
||||
|
||||
struct NonVolatileRAM {
|
||||
const string id;
|
||||
uint8_t *data;
|
||||
unsigned size;
|
||||
unsigned slot;
|
||||
NonVolatileRAM() : id(""), data(0), size(0), slot(0) {}
|
||||
NonVolatileRAM(const string id, uint8_t *data, unsigned size, unsigned slot = 0)
|
||||
: id(id), data(data), size(size), slot(slot) {}
|
||||
};
|
||||
linear_vector<NonVolatileRAM> nvram;
|
||||
|
||||
struct Mapping {
|
||||
Memory *memory;
|
||||
MMIO *mmio;
|
||||
function<uint8 (unsigned)> read;
|
||||
function<void (unsigned, uint8)> write;
|
||||
Bus::MapMode mode;
|
||||
unsigned banklo;
|
||||
unsigned bankhi;
|
||||
@ -51,10 +65,10 @@ public:
|
||||
unsigned size;
|
||||
|
||||
Mapping();
|
||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
||||
Mapping(Memory&);
|
||||
Mapping(MMIO&);
|
||||
};
|
||||
array<Mapping> mapping;
|
||||
linear_vector<Mapping> mapping;
|
||||
|
||||
void load(Mode::e, const lstring&);
|
||||
void unload();
|
||||
@ -92,11 +106,4 @@ private:
|
||||
void xml_parse_mode(Mapping&, const string&);
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
extern MappedRAM cartrom, cartram, cartrtc;
|
||||
extern MappedRAM bsxflash, bsxram, bsxpram;
|
||||
extern MappedRAM stArom, stAram;
|
||||
extern MappedRAM stBrom, stBram;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
@ -1,29 +1,7 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
|
||||
s.array(memory::cartram.data(), memory::cartram.size());
|
||||
}
|
||||
|
||||
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
|
||||
s.array(memory::cartrtc.data(), memory::cartrtc.size());
|
||||
}
|
||||
|
||||
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
|
||||
s.array(memory::bsxram.data(), memory::bsxram.size());
|
||||
}
|
||||
|
||||
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
|
||||
s.array(memory::bsxpram.data(), memory::bsxpram.size());
|
||||
}
|
||||
|
||||
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
|
||||
s.array(memory::stAram.data(), memory::stAram.size());
|
||||
}
|
||||
|
||||
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
|
||||
s.array(memory::stBram.data(), memory::stBram.size());
|
||||
}
|
||||
if(ram.data()) s.array(ram.data(), ram.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -63,13 +63,14 @@ void Cartridge::parse_xml_gameboy(const char *data) {
|
||||
void Cartridge::xml_parse_rom(xml_element &root) {
|
||||
foreach(leaf, root.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cartrom);
|
||||
Mapping m(rom);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = rom.size() - m.offset;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
@ -82,13 +83,14 @@ void Cartridge::xml_parse_ram(xml_element &root) {
|
||||
|
||||
foreach(leaf, root.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cartram);
|
||||
Mapping m(ram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size - m.offset;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
@ -107,7 +109,7 @@ void Cartridge::xml_parse_icd2(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m((Memory&)icd2);
|
||||
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -123,7 +125,7 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::fxrom);
|
||||
Mapping m(superfx.rom);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
@ -140,20 +142,21 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::fxram);
|
||||
Mapping m(superfx.ram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(superfx);
|
||||
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -168,29 +171,44 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
has_sa1 = true;
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "rom") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::vsprom);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
if(node.name == "mcu") {
|
||||
foreach(subnode, node.element) {
|
||||
if(subnode.name == "rom") {
|
||||
foreach(leaf, subnode.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(subnode.name == "ram") {
|
||||
foreach(leaf, subnode.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "iram") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cpuiram);
|
||||
Mapping m(sa1.cpuiram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = 2048;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
@ -201,20 +219,21 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::cc1bwram);
|
||||
Mapping m(sa1.cpubwram);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.size == 0) m.size = ram_size;
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(sa1);
|
||||
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -276,33 +295,36 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "dr") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "mask") necdsp.drmask = hex(attr.content);
|
||||
if(attr.name == "test") necdsp.drtest = hex(attr.content);
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.name == "sr") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "mask") necdsp.srmask = hex(attr.content);
|
||||
if(attr.name == "test") necdsp.srtest = hex(attr.content);
|
||||
} else if(node.name == "sr") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.name == "dp") {
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
|
||||
if(attr.name == "test") necdsp.dptest = hex(attr.content);
|
||||
} else if(node.name == "dp") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.name == "map") {
|
||||
Mapping m(necdsp);
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
|
||||
if(program == "") {
|
||||
@ -323,7 +345,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
|
||||
if(node.name == "slot") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(memory::bsxflash);
|
||||
Mapping m(bsxflash.memory);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
@ -333,10 +355,20 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(bsxcart);
|
||||
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -364,27 +396,29 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
||||
if(slot.name == "rom") {
|
||||
foreach(leaf, slot.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(slotid == 0 ? memory::stArom : memory::stBrom);
|
||||
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
|
||||
Mapping m(memory);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.memory->size() > 0) mapping.append(m);
|
||||
if(memory.size() > 0) mapping.append(m);
|
||||
}
|
||||
}
|
||||
} else if(slot.name == "ram") {
|
||||
foreach(leaf, slot.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(slotid == 0 ? memory::stAram : memory::stBram);
|
||||
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
|
||||
Mapping m(memory);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
if(attr.name == "offset") m.offset = hex(attr.content);
|
||||
if(attr.name == "size") m.size = hex(attr.content);
|
||||
}
|
||||
if(m.memory->size() > 0) mapping.append(m);
|
||||
if(memory.size() > 0) mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -398,7 +432,7 @@ void Cartridge::xml_parse_srtc(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m(srtc);
|
||||
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -414,7 +448,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
|
||||
if(node.name == "mcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m((Memory&)sdd1);
|
||||
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -424,7 +458,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m((MMIO&)sdd1);
|
||||
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -443,7 +477,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
if(node.name == "dcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110dcu);
|
||||
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -453,7 +487,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
} else if(node.name == "mcu") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110mcu);
|
||||
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "offset") spc7110.data_rom_offset = hex(attr.content);
|
||||
@ -464,7 +498,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
} else if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110);
|
||||
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -478,7 +512,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110ram);
|
||||
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
if(attr.name == "mode") xml_parse_mode(m, attr.content);
|
||||
@ -493,7 +527,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
|
||||
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(spc7110);
|
||||
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -509,7 +543,7 @@ void Cartridge::xml_parse_cx4(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m(cx4);
|
||||
Mapping m({ &Cx4::read, &cx4 }, { &Cx4::write, &cx4 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -523,7 +557,7 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map") {
|
||||
Mapping m(obc1);
|
||||
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -533,22 +567,11 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_setarisc(xml_element &root) {
|
||||
unsigned program = 0;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "program") {
|
||||
if(attr.content == "ST-0018") {
|
||||
program = 1;
|
||||
has_st0018 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MMIO *map[2] = { 0, &st0018 };
|
||||
has_st0018 = true;
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "map" && map[program]) {
|
||||
Mapping m(*map[program]);
|
||||
if(node.name == "map") {
|
||||
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
@ -561,16 +584,12 @@ void Cartridge::xml_parse_msu1(xml_element &root) {
|
||||
has_msu1 = true;
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m(msu1);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
if(node.name == "map") {
|
||||
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
|
||||
foreach(attr, node.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -611,22 +630,20 @@ void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping() {
|
||||
memory = 0;
|
||||
mmio = 0;
|
||||
mode.i = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(Memory &memory_) {
|
||||
memory = &memory_;
|
||||
mmio = 0;
|
||||
Cartridge::Mapping::Mapping(Memory &memory) {
|
||||
read = { &Memory::read, &memory };
|
||||
write = { &Memory::write, &memory };
|
||||
mode.i = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(MMIO &mmio_) {
|
||||
memory = 0;
|
||||
mmio = &mmio_;
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
|
||||
read = read_;
|
||||
write = write_;
|
||||
mode.i = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
}
|
||||
|
@ -1,2 +0,0 @@
|
||||
bool Cheat::active() const { return cheat_enabled; }
|
||||
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }
|
@ -15,7 +15,7 @@ void Cheat::enable(bool state) {
|
||||
}
|
||||
|
||||
void Cheat::synchronize() {
|
||||
memset(bitmask, 0x00, sizeof bitmask);
|
||||
memcpy(bus.lookup, lookup, 16 * 1024 * 1024);
|
||||
code_enabled = false;
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
@ -26,16 +26,16 @@ void Cheat::synchronize() {
|
||||
code_enabled = true;
|
||||
|
||||
unsigned addr = mirror(code.addr[n]);
|
||||
bitmask[addr >> 3] |= 1 << (addr & 7);
|
||||
bus.lookup[addr] = 0xff;
|
||||
if((addr & 0xffe000) == 0x7e0000) {
|
||||
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
|
||||
unsigned mirroraddr;
|
||||
for(unsigned x = 0; x <= 0x3f; x++) {
|
||||
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
|
||||
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
|
||||
bus.lookup[mirroraddr] = 0xff;
|
||||
|
||||
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
|
||||
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
|
||||
bus.lookup[mirroraddr] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,7 @@ void Cheat::synchronize() {
|
||||
cheat_enabled = system_enabled && code_enabled;
|
||||
}
|
||||
|
||||
bool Cheat::read(unsigned addr, uint8 &data) const {
|
||||
uint8 Cheat::read(unsigned addr) const {
|
||||
addr = mirror(addr);
|
||||
|
||||
for(unsigned i = 0; i < size(); i++) {
|
||||
@ -53,20 +53,37 @@ bool Cheat::read(unsigned addr, uint8 &data) const {
|
||||
|
||||
for(unsigned n = 0; n < code.addr.size(); n++) {
|
||||
if(addr == mirror(code.addr[n])) {
|
||||
data = code.data[n];
|
||||
return true;
|
||||
return code.data[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void Cheat::init() {
|
||||
bus.reader[0xff] = [](unsigned addr) {
|
||||
bus.reader[cheat.lookup[addr]](bus.target[addr]);
|
||||
return cheat.read(addr);
|
||||
};
|
||||
|
||||
bus.writer[0xff] = [](unsigned addr, uint8 data) {
|
||||
return bus.writer[cheat.lookup[addr]](bus.target[addr], data);
|
||||
};
|
||||
|
||||
memcpy(lookup, bus.lookup, 16 * 1024 * 1024);
|
||||
}
|
||||
|
||||
Cheat::Cheat() {
|
||||
lookup = new uint8[16 * 1024 * 1024];
|
||||
system_enabled = true;
|
||||
synchronize();
|
||||
}
|
||||
|
||||
Cheat::~Cheat() {
|
||||
delete[] lookup;
|
||||
}
|
||||
|
||||
//===============
|
||||
//encode / decode
|
||||
//===============
|
||||
|
@ -14,18 +14,17 @@ public:
|
||||
bool enabled() const;
|
||||
void enable(bool);
|
||||
void synchronize();
|
||||
bool read(unsigned, uint8&) const;
|
||||
|
||||
inline bool active() const;
|
||||
inline bool exists(unsigned addr) const;
|
||||
uint8 read(unsigned) const;
|
||||
void init();
|
||||
|
||||
Cheat();
|
||||
~Cheat();
|
||||
|
||||
static bool decode(const char*, unsigned&, uint8&, Type&);
|
||||
static bool encode(string&, unsigned, uint8, Type);
|
||||
|
||||
private:
|
||||
uint8 bitmask[0x200000];
|
||||
uint8 *lookup;
|
||||
bool system_enabled;
|
||||
bool code_enabled;
|
||||
bool cheat_enabled;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#define BSX_CPP
|
||||
namespace SNES {
|
||||
#include "bsx_base.cpp"
|
||||
#include "bsx_cart.cpp"
|
||||
#include "bsx_flash.cpp"
|
||||
#include "satellaview/satellaview.cpp"
|
||||
#include "cartridge/cartridge.cpp"
|
||||
#include "flash/flash.cpp"
|
||||
}
|
||||
|
@ -1,71 +1,3 @@
|
||||
class BSXBase : public MMIO {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
uint8 r2188, r2189, r218a, r218b;
|
||||
uint8 r218c, r218d, r218e, r218f;
|
||||
uint8 r2190, r2191, r2192, r2193;
|
||||
uint8 r2194, r2195, r2196, r2197;
|
||||
uint8 r2198, r2199, r219a, r219b;
|
||||
uint8 r219c, r219d, r219e, r219f;
|
||||
|
||||
uint8 r2192_counter;
|
||||
uint8 r2192_hour, r2192_minute, r2192_second;
|
||||
} regs;
|
||||
};
|
||||
|
||||
class BSXCart : public MMIO {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
BSXCart();
|
||||
~BSXCart();
|
||||
|
||||
private:
|
||||
struct {
|
||||
uint8 r[16];
|
||||
} regs;
|
||||
|
||||
void update_memory_map();
|
||||
};
|
||||
|
||||
class BSXFlash : public Memory {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
unsigned command;
|
||||
uint8 write_old;
|
||||
uint8 write_new;
|
||||
|
||||
bool flash_enable;
|
||||
bool read_enable;
|
||||
bool write_enable;
|
||||
} regs;
|
||||
};
|
||||
|
||||
extern BSXBase bsxbase;
|
||||
extern BSXCart bsxcart;
|
||||
extern BSXFlash bsxflash;
|
||||
#include "satellaview/satellaview.hpp"
|
||||
#include "cartridge/cartridge.hpp"
|
||||
#include "flash/flash.hpp"
|
||||
|
@ -1,140 +0,0 @@
|
||||
#ifdef BSX_CPP
|
||||
|
||||
BSXBase bsxbase;
|
||||
|
||||
void BSXBase::init() {
|
||||
}
|
||||
|
||||
void BSXBase::enable() {
|
||||
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
|
||||
}
|
||||
|
||||
void BSXBase::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void BSXBase::reset() {
|
||||
memset(®s, 0x00, sizeof regs);
|
||||
}
|
||||
|
||||
uint8 BSXBase::mmio_read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
case 0x2188: return regs.r2188;
|
||||
case 0x2189: return regs.r2189;
|
||||
case 0x218a: return regs.r218a;
|
||||
case 0x218c: return regs.r218c;
|
||||
case 0x218e: return regs.r218e;
|
||||
case 0x218f: return regs.r218f;
|
||||
case 0x2190: return regs.r2190;
|
||||
|
||||
case 0x2192: {
|
||||
unsigned counter = regs.r2192_counter++;
|
||||
if(regs.r2192_counter >= 18) regs.r2192_counter = 0;
|
||||
|
||||
if(counter == 0) {
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
tm *t = localtime(&rawtime);
|
||||
|
||||
regs.r2192_hour = t->tm_hour;
|
||||
regs.r2192_minute = t->tm_min;
|
||||
regs.r2192_second = t->tm_sec;
|
||||
}
|
||||
|
||||
switch(counter) {
|
||||
case 0: return 0x00; //???
|
||||
case 1: return 0x00; //???
|
||||
case 2: return 0x00; //???
|
||||
case 3: return 0x00; //???
|
||||
case 4: return 0x00; //???
|
||||
case 5: return 0x01;
|
||||
case 6: return 0x01;
|
||||
case 7: return 0x00;
|
||||
case 8: return 0x00;
|
||||
case 9: return 0x00;
|
||||
case 10: return regs.r2192_second;
|
||||
case 11: return regs.r2192_minute;
|
||||
case 12: return regs.r2192_hour;
|
||||
case 13: return 0x00; //???
|
||||
case 14: return 0x00; //???
|
||||
case 15: return 0x00; //???
|
||||
case 16: return 0x00; //???
|
||||
case 17: return 0x00; //???
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x2193: return regs.r2193 & ~0x0c;
|
||||
case 0x2194: return regs.r2194;
|
||||
case 0x2196: return regs.r2196;
|
||||
case 0x2197: return regs.r2197;
|
||||
case 0x2199: return regs.r2199;
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void BSXBase::mmio_write(unsigned addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
case 0x2188: {
|
||||
regs.r2188 = data;
|
||||
} break;
|
||||
|
||||
case 0x2189: {
|
||||
regs.r2189 = data;
|
||||
} break;
|
||||
|
||||
case 0x218a: {
|
||||
regs.r218a = data;
|
||||
} break;
|
||||
|
||||
case 0x218b: {
|
||||
regs.r218b = data;
|
||||
} break;
|
||||
|
||||
case 0x218c: {
|
||||
regs.r218c = data;
|
||||
} break;
|
||||
|
||||
case 0x218e: {
|
||||
regs.r218e = data;
|
||||
} break;
|
||||
|
||||
case 0x218f: {
|
||||
regs.r218e >>= 1;
|
||||
regs.r218e = regs.r218f - regs.r218e;
|
||||
regs.r218f >>= 1;
|
||||
} break;
|
||||
|
||||
case 0x2191: {
|
||||
regs.r2191 = data;
|
||||
regs.r2192_counter = 0;
|
||||
} break;
|
||||
|
||||
case 0x2192: {
|
||||
regs.r2190 = 0x80;
|
||||
} break;
|
||||
|
||||
case 0x2193: {
|
||||
regs.r2193 = data;
|
||||
} break;
|
||||
|
||||
case 0x2194: {
|
||||
regs.r2194 = data;
|
||||
} break;
|
||||
|
||||
case 0x2197: {
|
||||
regs.r2197 = data;
|
||||
} break;
|
||||
|
||||
case 0x2199: {
|
||||
regs.r2199 = data;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,96 +0,0 @@
|
||||
#ifdef BSX_CPP
|
||||
|
||||
BSXCart bsxcart;
|
||||
|
||||
void BSXCart::init() {
|
||||
}
|
||||
|
||||
void BSXCart::enable() {
|
||||
}
|
||||
|
||||
void BSXCart::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void BSXCart::reset() {
|
||||
for(unsigned i = 0; i < 16; i++) regs.r[i] = 0x00;
|
||||
regs.r[0x07] = 0x80;
|
||||
regs.r[0x08] = 0x80;
|
||||
|
||||
update_memory_map();
|
||||
}
|
||||
|
||||
void BSXCart::update_memory_map() {
|
||||
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)memory::bsxpram;
|
||||
|
||||
if((regs.r[0x02] & 0x80) == 0x00) {
|
||||
//LoROM mapping
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
||||
} else {
|
||||
//HiROM mapping
|
||||
bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
|
||||
}
|
||||
|
||||
if(regs.r[0x03] & 0x80) {
|
||||
bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
|
||||
//bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
if((regs.r[0x05] & 0x80) == 0x00) {
|
||||
bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
if((regs.r[0x06] & 0x80) == 0x00) {
|
||||
bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
if(regs.r[0x07] & 0x80) {
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
|
||||
}
|
||||
|
||||
if(regs.r[0x08] & 0x80) {
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
|
||||
bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
|
||||
}
|
||||
|
||||
uint8 BSXCart::mmio_read(unsigned addr) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
return regs.r[n];
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
return memory::bsxram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void BSXCart::mmio_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
regs.r[n] = data;
|
||||
if(n == 0x0e && data & 0x80) update_memory_map();
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
return memory::bsxram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||
}
|
||||
}
|
||||
|
||||
BSXCart::BSXCart() {
|
||||
}
|
||||
|
||||
BSXCart::~BSXCart() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,119 +0,0 @@
|
||||
#ifdef BSX_CPP
|
||||
|
||||
BSXFlash bsxflash;
|
||||
|
||||
void BSXFlash::init() {}
|
||||
void BSXFlash::enable() {}
|
||||
|
||||
void BSXFlash::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void BSXFlash::reset() {
|
||||
regs.command = 0;
|
||||
regs.write_old = 0x00;
|
||||
regs.write_new = 0x00;
|
||||
|
||||
regs.flash_enable = false;
|
||||
regs.read_enable = false;
|
||||
regs.write_enable = false;
|
||||
memory::bsxflash.write_protect(!regs.write_enable);
|
||||
}
|
||||
|
||||
unsigned BSXFlash::size() const {
|
||||
return memory::bsxflash.size();
|
||||
}
|
||||
|
||||
uint8 BSXFlash::read(unsigned addr) {
|
||||
if(addr == 0x0002) {
|
||||
if(regs.flash_enable) return 0x80;
|
||||
}
|
||||
|
||||
if(addr == 0x5555) {
|
||||
if(regs.flash_enable) return 0x80;
|
||||
}
|
||||
|
||||
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
|
||||
//read flash cartridge vendor information
|
||||
switch(addr - 0xff00) {
|
||||
case 0x00: return 0x4d;
|
||||
case 0x01: return 0x00;
|
||||
case 0x02: return 0x50;
|
||||
case 0x03: return 0x00;
|
||||
case 0x04: return 0x00;
|
||||
case 0x05: return 0x00;
|
||||
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
|
||||
case 0x07: return 0x00;
|
||||
default: return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
return memory::bsxflash.read(addr);
|
||||
}
|
||||
|
||||
void BSXFlash::write(unsigned addr, uint8 data) {
|
||||
//there exist both read-only and read-write BS-X flash cartridges ...
|
||||
//unfortunately, the vendor info is not stored inside memory dumps
|
||||
//of BS-X flashcarts, so it is impossible to determine whether a
|
||||
//given flashcart is writeable.
|
||||
//however, it has been observed that LoROM-mapped BS-X carts always
|
||||
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
||||
//read-only flashcarts.
|
||||
//below is an unfortunately necessary workaround to this problem.
|
||||
//if(cartridge.mapper() == Cartridge::BSCHiROM) return;
|
||||
|
||||
if((addr & 0xff0000) == 0) {
|
||||
regs.write_old = regs.write_new;
|
||||
regs.write_new = data;
|
||||
|
||||
if(regs.write_enable && regs.write_old == regs.write_new) {
|
||||
return memory::bsxflash.write(addr, data);
|
||||
}
|
||||
} else {
|
||||
if(regs.write_enable) {
|
||||
return memory::bsxflash.write(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
if(addr == 0x0000) {
|
||||
regs.command <<= 8;
|
||||
regs.command |= data;
|
||||
|
||||
if((regs.command & 0xffff) == 0x38d0) {
|
||||
regs.flash_enable = true;
|
||||
regs.read_enable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(addr == 0x2aaa) {
|
||||
regs.command <<= 8;
|
||||
regs.command |= data;
|
||||
}
|
||||
|
||||
if(addr == 0x5555) {
|
||||
regs.command <<= 8;
|
||||
regs.command |= data;
|
||||
|
||||
if((regs.command & 0xffffff) == 0xaa5570) {
|
||||
regs.write_enable = false;
|
||||
}
|
||||
|
||||
if((regs.command & 0xffffff) == 0xaa55a0) {
|
||||
regs.write_old = 0x00;
|
||||
regs.write_new = 0x00;
|
||||
regs.flash_enable = true;
|
||||
regs.write_enable = true;
|
||||
}
|
||||
|
||||
if((regs.command & 0xffffff) == 0xaa55f0) {
|
||||
regs.flash_enable = false;
|
||||
regs.read_enable = false;
|
||||
regs.write_enable = false;
|
||||
}
|
||||
|
||||
memory::bsxflash.write_protect(!regs.write_enable);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -14,6 +14,7 @@ struct Coprocessor : Processor {
|
||||
#include <snes/chip/cx4/cx4.hpp>
|
||||
#include <snes/chip/obc1/obc1.hpp>
|
||||
#include <snes/chip/st0018/st0018.hpp>
|
||||
#include <snes/chip/sufamiturbo/sufamiturbo.hpp>
|
||||
#include <snes/chip/msu1/msu1.hpp>
|
||||
#include <snes/chip/serial/serial.hpp>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
class Cx4 : public Memory {
|
||||
class Cx4 {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
|
@ -32,12 +32,10 @@ void ICD2::init() {
|
||||
}
|
||||
|
||||
void ICD2::enable() {
|
||||
mmio[0] = memory::mmio.handle(0x2181);
|
||||
mmio[1] = memory::mmio.handle(0x2182);
|
||||
mmio[2] = memory::mmio.handle(0x420b);
|
||||
memory::mmio.map(0x2181, *this);
|
||||
memory::mmio.map(0x2182, *this);
|
||||
memory::mmio.map(0x420b, *this);
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
|
||||
}
|
||||
|
||||
void ICD2::power() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
class ICD2 : public GameBoy::Interface, public Coprocessor, public MMIO, public Memory {
|
||||
class ICD2 : public GameBoy::Interface, public Coprocessor {
|
||||
public:
|
||||
unsigned revision;
|
||||
|
||||
@ -10,6 +10,9 @@ public:
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifdef ICD2_CPP
|
||||
|
||||
uint8 ICD2::mmio_read(unsigned addr) {
|
||||
if((uint16)addr == 0x2181) return mmio[0]->mmio_read(addr);
|
||||
if((uint16)addr == 0x2182) return mmio[1]->mmio_read(addr);
|
||||
if((uint16)addr == 0x420b) return mmio[2]->mmio_read(addr);
|
||||
if((uint16)addr == 0x2181) return cpu.mmio_read(addr);
|
||||
if((uint16)addr == 0x2182) return cpu.mmio_read(addr);
|
||||
if((uint16)addr == 0x420b) return cpu.mmio_read(addr);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
@ -30,9 +30,9 @@ void ICD2::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
if((uint16)addr == 0x2181) return mmio[0]->mmio_write(addr, r2181 = data);
|
||||
if((uint16)addr == 0x2182) return mmio[1]->mmio_write(addr, r2182 = data);
|
||||
if((uint16)addr == 0x420b) return mmio[2]->mmio_write(addr, data);
|
||||
if((uint16)addr == 0x2181) return cpu.mmio_write(addr, r2181 = data);
|
||||
if((uint16)addr == 0x2182) return cpu.mmio_write(addr, r2182 = data);
|
||||
if((uint16)addr == 0x420b) return cpu.mmio_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 ICD2::read(unsigned addr) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
uint8 r2181;
|
||||
uint8 r2182;
|
||||
MMIO *mmio[3];
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
@ -13,7 +12,5 @@ uint8 r6007;
|
||||
uint8 r7000[16];
|
||||
unsigned r7800;
|
||||
uint8 mlt_req;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 vram[320];
|
||||
|
@ -49,14 +49,15 @@ void MSU1::init() {
|
||||
}
|
||||
|
||||
void MSU1::enable() {
|
||||
audio.coprocessor_enable(true);
|
||||
audio.coprocessor_frequency(44100.0);
|
||||
|
||||
if(datafile.open()) datafile.close();
|
||||
datafile.open(string(cartridge.basename(), ".msu"), file::mode_read);
|
||||
}
|
||||
|
||||
void MSU1::power() {
|
||||
audio.coprocessor_enable(true);
|
||||
audio.coprocessor_frequency(44100.0);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -129,7 +130,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
|
||||
if(addr == 0x2005) {
|
||||
mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode_read)) {
|
||||
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode_read)) {
|
||||
uint32 header = audiofile.readm(4);
|
||||
if(header != 0x4d535531) { //verify 'MSU1' header
|
||||
audiofile.close();
|
||||
|
@ -1,4 +1,4 @@
|
||||
class MSU1 : public Coprocessor, public MMIO {
|
||||
class MSU1 : public Coprocessor {
|
||||
public:
|
||||
static void Enter();
|
||||
void enter();
|
||||
|
@ -21,7 +21,7 @@ void MSU1::serialize(serializer &s) {
|
||||
}
|
||||
|
||||
if(audiofile.open()) audiofile.close();
|
||||
if(audiofile.open(string(cartridge.basename(), "-", mmio.audio_track, ".pcm"), file::mode_read)) {
|
||||
if(audiofile.open(string(cartridge.basename(), "-", (unsigned)mmio.audio_track, ".pcm"), file::mode_read)) {
|
||||
audiofile.seek(mmio.audio_offset);
|
||||
}
|
||||
}
|
||||
|
@ -48,46 +48,44 @@ string NECDSP::disassemble(uint14 ip) {
|
||||
case 1: output << "b"; break;
|
||||
}
|
||||
|
||||
if(1||dst) {
|
||||
output << "\n mov ";
|
||||
output << "\n mov ";
|
||||
|
||||
switch(src) {
|
||||
case 0: output << "trb,"; break;
|
||||
case 1: output << "a,"; break;
|
||||
case 2: output << "b,"; break;
|
||||
case 3: output << "tr,"; break;
|
||||
case 4: output << "dp,"; break;
|
||||
case 5: output << "rp,"; break;
|
||||
case 6: output << "ro,"; break;
|
||||
case 7: output << "sgn,"; break;
|
||||
case 8: output << "dr,"; break;
|
||||
case 9: output << "drnf,"; break;
|
||||
case 10: output << "sr,"; break;
|
||||
case 11: output << "sim,"; break;
|
||||
case 12: output << "sil,"; break;
|
||||
case 13: output << "k,"; break;
|
||||
case 14: output << "l,"; break;
|
||||
case 15: output << "mem,"; break;
|
||||
}
|
||||
switch(src) {
|
||||
case 0: output << "trb,"; break;
|
||||
case 1: output << "a,"; break;
|
||||
case 2: output << "b,"; break;
|
||||
case 3: output << "tr,"; break;
|
||||
case 4: output << "dp,"; break;
|
||||
case 5: output << "rp,"; break;
|
||||
case 6: output << "ro,"; break;
|
||||
case 7: output << "sgn,"; break;
|
||||
case 8: output << "dr,"; break;
|
||||
case 9: output << "drnf,"; break;
|
||||
case 10: output << "sr,"; break;
|
||||
case 11: output << "sim,"; break;
|
||||
case 12: output << "sil,"; break;
|
||||
case 13: output << "k,"; break;
|
||||
case 14: output << "l,"; break;
|
||||
case 15: output << "mem,"; break;
|
||||
}
|
||||
|
||||
switch(dst) {
|
||||
case 0: output << "non"; break;
|
||||
case 1: output << "a"; break;
|
||||
case 2: output << "b"; break;
|
||||
case 3: output << "tr"; break;
|
||||
case 4: output << "dp"; break;
|
||||
case 5: output << "rp"; break;
|
||||
case 6: output << "dr"; break;
|
||||
case 7: output << "sr"; break;
|
||||
case 8: output << "sol"; break;
|
||||
case 9: output << "som"; break;
|
||||
case 10: output << "k"; break;
|
||||
case 11: output << "klr"; break;
|
||||
case 12: output << "klm"; break;
|
||||
case 13: output << "l"; break;
|
||||
case 14: output << "trb"; break;
|
||||
case 15: output << "mem"; break;
|
||||
}
|
||||
switch(dst) {
|
||||
case 0: output << "non"; break;
|
||||
case 1: output << "a"; break;
|
||||
case 2: output << "b"; break;
|
||||
case 3: output << "tr"; break;
|
||||
case 4: output << "dp"; break;
|
||||
case 5: output << "rp"; break;
|
||||
case 6: output << "dr"; break;
|
||||
case 7: output << "sr"; break;
|
||||
case 8: output << "sol"; break;
|
||||
case 9: output << "som"; break;
|
||||
case 10: output << "k"; break;
|
||||
case 11: output << "klr"; break;
|
||||
case 12: output << "klm"; break;
|
||||
case 13: output << "l"; break;
|
||||
case 14: output << "trb"; break;
|
||||
case 15: output << "mem"; break;
|
||||
}
|
||||
|
||||
if(dpl) {
|
||||
@ -132,9 +130,12 @@ string NECDSP::disassemble(uint14 ip) {
|
||||
if(type == 2) { //JP
|
||||
uint9 brch = opcode >> 13;
|
||||
uint11 na = opcode >> 2;
|
||||
uint8 bank = opcode >> 0;
|
||||
|
||||
uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
|
||||
|
||||
switch(brch) {
|
||||
case 0x000: output << "jmpso "; break;
|
||||
case 0x000: output << "jmpso "; jp = 0; break;
|
||||
case 0x080: output << "jnca "; break;
|
||||
case 0x082: output << "jca "; break;
|
||||
case 0x084: output << "jncb "; break;
|
||||
@ -169,14 +170,14 @@ string NECDSP::disassemble(uint14 ip) {
|
||||
case 0x0ba: output << "jsoak "; break;
|
||||
case 0x0bc: output << "jnrqm "; break;
|
||||
case 0x0be: output << "jrqm "; break;
|
||||
case 0x100: output << "ljmp "; break;
|
||||
case 0x101: output << "hjmp "; break;
|
||||
case 0x140: output << "lcall "; break;
|
||||
case 0x141: output << "hcall "; break;
|
||||
case 0x100: output << "ljmp "; jp &= ~0x2000; break;
|
||||
case 0x101: output << "hjmp "; jp |= 0x2000; break;
|
||||
case 0x140: output << "lcall "; jp &= ~0x2000; break;
|
||||
case 0x141: output << "hcall "; jp |= 0x2000; break;
|
||||
default: output << "?????? "; break;
|
||||
}
|
||||
|
||||
output << "$" << hex<4>(na);
|
||||
output << "$" << hex<4>(jp);
|
||||
}
|
||||
|
||||
if(type == 3) { //LD
|
||||
|
@ -1,28 +1,16 @@
|
||||
#ifdef NECDSP_CPP
|
||||
|
||||
uint8 NECDSP::read(unsigned addr) {
|
||||
uint8 NECDSP::sr_read(unsigned) {
|
||||
cpu.synchronize_coprocessor();
|
||||
if((addr & srmask) == srtest) return sr_read();
|
||||
if((addr & drmask) == drtest) return dr_read();
|
||||
if((addr & dpmask) == dptest) return dp_read(addr);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void NECDSP::write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
if((addr & srmask) == srtest) return sr_write(data);
|
||||
if((addr & drmask) == drtest) return dr_write(data);
|
||||
if((addr & dpmask) == dptest) return dp_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 NECDSP::sr_read() {
|
||||
return regs.sr >> 8;
|
||||
}
|
||||
|
||||
void NECDSP::sr_write(uint8 data) {
|
||||
void NECDSP::sr_write(unsigned, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
}
|
||||
|
||||
uint8 NECDSP::dr_read() {
|
||||
uint8 NECDSP::dr_read(unsigned) {
|
||||
cpu.synchronize_coprocessor();
|
||||
if(regs.sr.drc == 0) {
|
||||
//16-bit
|
||||
if(regs.sr.drs == 0) {
|
||||
@ -40,7 +28,8 @@ uint8 NECDSP::dr_read() {
|
||||
}
|
||||
}
|
||||
|
||||
void NECDSP::dr_write(uint8 data) {
|
||||
void NECDSP::dr_write(unsigned, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
if(regs.sr.drc == 0) {
|
||||
//16-bit
|
||||
if(regs.sr.drs == 0) {
|
||||
@ -59,6 +48,7 @@ void NECDSP::dr_write(uint8 data) {
|
||||
}
|
||||
|
||||
uint8 NECDSP::dp_read(unsigned addr) {
|
||||
cpu.synchronize_coprocessor();
|
||||
bool hi = addr & 1;
|
||||
addr = (addr >> 1) & 2047;
|
||||
|
||||
@ -70,6 +60,7 @@ uint8 NECDSP::dp_read(unsigned addr) {
|
||||
}
|
||||
|
||||
void NECDSP::dp_write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
bool hi = addr & 1;
|
||||
addr = (addr >> 1) & 2047;
|
||||
|
||||
|
@ -16,26 +16,23 @@ void NECDSP::enter() {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
exec();
|
||||
uint24 opcode = programROM[regs.pc++];
|
||||
switch(opcode >> 22) {
|
||||
case 0: exec_op(opcode); break;
|
||||
case 1: exec_rt(opcode); break;
|
||||
case 2: exec_jp(opcode); break;
|
||||
case 3: exec_ld(opcode); break;
|
||||
}
|
||||
|
||||
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
|
||||
regs.m = result >> 15; //store sign + top 15-bits
|
||||
regs.n = result << 1; //store low 15-bits + zero
|
||||
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
}
|
||||
}
|
||||
|
||||
void NECDSP::exec() {
|
||||
uint24 opcode = programROM[regs.pc++];
|
||||
switch(opcode >> 22) {
|
||||
case 0: exec_op(opcode); break;
|
||||
case 1: exec_rt(opcode); break;
|
||||
case 2: exec_jp(opcode); break;
|
||||
case 3: exec_ld(opcode); break;
|
||||
}
|
||||
|
||||
int32 result = (int32)regs.k * regs.l; //sign + 30-bit result
|
||||
regs.m = result >> 15; //store sign + top 15-bits
|
||||
regs.n = result << 1; //store low 15-bits + zero
|
||||
}
|
||||
|
||||
void NECDSP::exec_op(uint24 opcode) {
|
||||
uint2 pselect = opcode >> 20; //P select
|
||||
uint4 alu = opcode >> 16; //ALU operation mode
|
||||
@ -46,23 +43,24 @@ void NECDSP::exec_op(uint24 opcode) {
|
||||
uint4 src = opcode >> 4; //move source
|
||||
uint4 dst = opcode >> 0; //move destination
|
||||
|
||||
uint16 idb;
|
||||
switch(src) {
|
||||
case 0: regs.idb = regs.trb; break;
|
||||
case 1: regs.idb = regs.a; break;
|
||||
case 2: regs.idb = regs.b; break;
|
||||
case 3: regs.idb = regs.tr; break;
|
||||
case 4: regs.idb = regs.dp; break;
|
||||
case 5: regs.idb = regs.rp; break;
|
||||
case 6: regs.idb = dataROM[regs.rp]; break;
|
||||
case 7: regs.idb = 0x8000 - regs.flaga.s1; break;
|
||||
case 8: regs.idb = regs.dr; regs.sr.rqm = 1; break;
|
||||
case 9: regs.idb = regs.dr; break;
|
||||
case 10: regs.idb = regs.sr; break;
|
||||
case 11: regs.idb = regs.si; break; //MSB
|
||||
case 12: regs.idb = regs.si; break; //LSB
|
||||
case 13: regs.idb = regs.k; break;
|
||||
case 14: regs.idb = regs.l; break;
|
||||
case 15: regs.idb = dataRAM[regs.dp]; break;
|
||||
case 0: idb = regs.trb; break;
|
||||
case 1: idb = regs.a; break;
|
||||
case 2: idb = regs.b; break;
|
||||
case 3: idb = regs.tr; break;
|
||||
case 4: idb = regs.dp; break;
|
||||
case 5: idb = regs.rp; break;
|
||||
case 6: idb = dataROM[regs.rp]; break;
|
||||
case 7: idb = 0x8000 - regs.flaga.s1; break;
|
||||
case 8: idb = regs.dr; regs.sr.rqm = 1; break;
|
||||
case 9: idb = regs.dr; break;
|
||||
case 10: idb = regs.sr; break;
|
||||
case 11: idb = regs.si; break; //MSB
|
||||
case 12: idb = regs.si; break; //LSB
|
||||
case 13: idb = regs.k; break;
|
||||
case 14: idb = regs.l; break;
|
||||
case 15: idb = dataRAM[regs.dp]; break;
|
||||
}
|
||||
|
||||
if(alu) {
|
||||
@ -72,7 +70,7 @@ void NECDSP::exec_op(uint24 opcode) {
|
||||
|
||||
switch(pselect) {
|
||||
case 0: p = dataRAM[regs.dp]; break;
|
||||
case 1: p = regs.idb; break;
|
||||
case 1: p = idb; break;
|
||||
case 2: p = regs.m; break;
|
||||
case 3: p = regs.n; break;
|
||||
}
|
||||
@ -146,7 +144,7 @@ void NECDSP::exec_op(uint24 opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
exec_ld((regs.idb << 6) + dst);
|
||||
exec_ld((idb << 6) + dst);
|
||||
|
||||
switch(dpl) {
|
||||
case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC
|
||||
@ -169,55 +167,54 @@ void NECDSP::exec_jp(uint24 opcode) {
|
||||
uint11 na = opcode >> 2; //next address
|
||||
uint2 bank = opcode >> 0; //bank address
|
||||
|
||||
uint16 jps = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
|
||||
uint16 jpl = (bank << 11) | (na << 0);
|
||||
uint14 jp = (regs.pc & 0x2000) | (bank << 11) | (na << 0);
|
||||
|
||||
switch(brch) {
|
||||
case 0x000: regs.pc = regs.so; return; //JMPSO
|
||||
|
||||
case 0x080: if(regs.flaga.c == 0) regs.pc = jps; return; //JNCA
|
||||
case 0x082: if(regs.flaga.c == 1) regs.pc = jps; return; //JCA
|
||||
case 0x084: if(regs.flagb.c == 0) regs.pc = jps; return; //JNCB
|
||||
case 0x086: if(regs.flagb.c == 1) regs.pc = jps; return; //JCB
|
||||
case 0x080: if(regs.flaga.c == 0) regs.pc = jp; return; //JNCA
|
||||
case 0x082: if(regs.flaga.c == 1) regs.pc = jp; return; //JCA
|
||||
case 0x084: if(regs.flagb.c == 0) regs.pc = jp; return; //JNCB
|
||||
case 0x086: if(regs.flagb.c == 1) regs.pc = jp; return; //JCB
|
||||
|
||||
case 0x088: if(regs.flaga.z == 0) regs.pc = jps; return; //JNZA
|
||||
case 0x08a: if(regs.flaga.z == 1) regs.pc = jps; return; //JZA
|
||||
case 0x08c: if(regs.flagb.z == 0) regs.pc = jps; return; //JNZB
|
||||
case 0x08e: if(regs.flagb.z == 1) regs.pc = jps; return; //JZB
|
||||
case 0x088: if(regs.flaga.z == 0) regs.pc = jp; return; //JNZA
|
||||
case 0x08a: if(regs.flaga.z == 1) regs.pc = jp; return; //JZA
|
||||
case 0x08c: if(regs.flagb.z == 0) regs.pc = jp; return; //JNZB
|
||||
case 0x08e: if(regs.flagb.z == 1) regs.pc = jp; return; //JZB
|
||||
|
||||
case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jps; return; //JNOVA0
|
||||
case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jps; return; //JOVA0
|
||||
case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jps; return; //JNOVB0
|
||||
case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jps; return; //JOVB0
|
||||
case 0x090: if(regs.flaga.ov0 == 0) regs.pc = jp; return; //JNOVA0
|
||||
case 0x092: if(regs.flaga.ov0 == 1) regs.pc = jp; return; //JOVA0
|
||||
case 0x094: if(regs.flagb.ov0 == 0) regs.pc = jp; return; //JNOVB0
|
||||
case 0x096: if(regs.flagb.ov0 == 1) regs.pc = jp; return; //JOVB0
|
||||
|
||||
case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jps; return; //JNOVA1
|
||||
case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jps; return; //JOVA1
|
||||
case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jps; return; //JNOVB1
|
||||
case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jps; return; //JOVB1
|
||||
case 0x098: if(regs.flaga.ov1 == 0) regs.pc = jp; return; //JNOVA1
|
||||
case 0x09a: if(regs.flaga.ov1 == 1) regs.pc = jp; return; //JOVA1
|
||||
case 0x09c: if(regs.flagb.ov1 == 0) regs.pc = jp; return; //JNOVB1
|
||||
case 0x09e: if(regs.flagb.ov1 == 1) regs.pc = jp; return; //JOVB1
|
||||
|
||||
case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jps; return; //JNSA0
|
||||
case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jps; return; //JSA0
|
||||
case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jps; return; //JNSB0
|
||||
case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jps; return; //JSB0
|
||||
case 0x0a0: if(regs.flaga.s0 == 0) regs.pc = jp; return; //JNSA0
|
||||
case 0x0a2: if(regs.flaga.s0 == 1) regs.pc = jp; return; //JSA0
|
||||
case 0x0a4: if(regs.flagb.s0 == 0) regs.pc = jp; return; //JNSB0
|
||||
case 0x0a6: if(regs.flagb.s0 == 1) regs.pc = jp; return; //JSB0
|
||||
|
||||
case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jps; return; //JNSA1
|
||||
case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jps; return; //JSA1
|
||||
case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jps; return; //JNSB1
|
||||
case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jps; return; //JSB1
|
||||
case 0x0a8: if(regs.flaga.s1 == 0) regs.pc = jp; return; //JNSA1
|
||||
case 0x0aa: if(regs.flaga.s1 == 1) regs.pc = jp; return; //JSA1
|
||||
case 0x0ac: if(regs.flagb.s1 == 0) regs.pc = jp; return; //JNSB1
|
||||
case 0x0ae: if(regs.flagb.s1 == 1) regs.pc = jp; return; //JSB1
|
||||
|
||||
case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jps; return; //JDPL0
|
||||
case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jps; return; //JDPLN0
|
||||
case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jps; return; //JDPLF
|
||||
case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jps; return; //JDPLNF
|
||||
case 0x0b0: if((regs.dp & 0x0f) == 0x00) regs.pc = jp; return; //JDPL0
|
||||
case 0x0b1: if((regs.dp & 0x0f) != 0x00) regs.pc = jp; return; //JDPLN0
|
||||
case 0x0b2: if((regs.dp & 0x0f) == 0x0f) regs.pc = jp; return; //JDPLF
|
||||
case 0x0b3: if((regs.dp & 0x0f) != 0x0f) regs.pc = jp; return; //JDPLNF
|
||||
|
||||
case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jps; return; //JNRQM
|
||||
case 0x0be: if(regs.sr.rqm == 1) regs.pc = jps; return; //JRQM
|
||||
case 0x0bc: if(regs.sr.rqm == 0) regs.pc = jp; return; //JNRQM
|
||||
case 0x0be: if(regs.sr.rqm == 1) regs.pc = jp; return; //JRQM
|
||||
|
||||
case 0x100: regs.pc = 0x0000 | jpl; return; //LJMP
|
||||
case 0x101: regs.pc = 0x2000 | jpl; return; //HJMP
|
||||
case 0x100: regs.pc = jp & ~0x2000; return; //LJMP
|
||||
case 0x101: regs.pc = jp | 0x2000; return; //HJMP
|
||||
|
||||
case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = 0x0000 | jpl; return; //LCALL
|
||||
case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = 0x2000 | jpl; return; //HCALL
|
||||
case 0x140: regs.stack[regs.sp++] = regs.pc; regs.pc = jp & ~0x2000; return; //LCALL
|
||||
case 0x141: regs.stack[regs.sp++] = regs.pc; regs.pc = jp | 0x2000; return; //HCALL
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,8 +222,6 @@ void NECDSP::exec_ld(uint24 opcode) {
|
||||
uint16 id = opcode >> 6; //immediate data
|
||||
uint4 dst = opcode >> 0; //destination
|
||||
|
||||
regs.idb = id;
|
||||
|
||||
switch(dst) {
|
||||
case 0: break;
|
||||
case 1: regs.a = id; break;
|
||||
@ -251,6 +246,9 @@ void NECDSP::init() {
|
||||
}
|
||||
|
||||
void NECDSP::enable() {
|
||||
if(revision == Revision::uPD96050) {
|
||||
cartridge.nvram.append({ "nec", (uint8_t*)dataRAM, 4096 });
|
||||
}
|
||||
}
|
||||
|
||||
void NECDSP::power() {
|
||||
@ -258,7 +256,6 @@ void NECDSP::power() {
|
||||
regs.pc.bits(11);
|
||||
regs.rp.bits(10);
|
||||
regs.dp.bits( 8);
|
||||
dpmask = 0x000000, dptest = 0xffffff; //uPD7725 not mapped to SNES bus
|
||||
}
|
||||
|
||||
if(revision.i == Revision::uPD96050) {
|
||||
@ -292,7 +289,6 @@ void NECDSP::reset() {
|
||||
regs.dr = 0x0000;
|
||||
regs.si = 0x0000;
|
||||
regs.so = 0x0000;
|
||||
regs.idb = 0x0000;
|
||||
}
|
||||
|
||||
NECDSP::NECDSP() {
|
||||
|
@ -1,11 +1,8 @@
|
||||
class NECDSP : public Coprocessor, public Memory {
|
||||
class NECDSP : public Coprocessor {
|
||||
public:
|
||||
//enum class Revision : unsigned { uPD7725, uPD96050 } revision;
|
||||
struct Revision { enum e { uPD7725, uPD96050 } i; } revision;
|
||||
unsigned frequency;
|
||||
unsigned drmask, drtest;
|
||||
unsigned srmask, srtest;
|
||||
unsigned dpmask, dptest;
|
||||
|
||||
#include "registers.hpp"
|
||||
|
||||
@ -20,7 +17,6 @@ public:
|
||||
static void Enter();
|
||||
void enter();
|
||||
|
||||
void exec();
|
||||
void exec_op(uint24 opcode);
|
||||
void exec_rt(uint24 opcode);
|
||||
void exec_jp(uint24 opcode);
|
||||
@ -28,14 +24,11 @@ public:
|
||||
|
||||
string disassemble(uint14 ip);
|
||||
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
uint8 sr_read(unsigned);
|
||||
void sr_write(unsigned, uint8 data);
|
||||
|
||||
uint8 sr_read();
|
||||
void sr_write(uint8 data);
|
||||
|
||||
uint8 dr_read();
|
||||
void dr_write(uint8 data);
|
||||
uint8 dr_read(unsigned);
|
||||
void dr_write(unsigned, uint8 data);
|
||||
|
||||
uint8 dp_read(unsigned addr);
|
||||
void dp_write(unsigned addr, uint8 data);
|
||||
|
@ -48,5 +48,4 @@ struct Regs {
|
||||
uint16 dr; //data register
|
||||
uint16 si;
|
||||
uint16 so;
|
||||
uint16 idb;
|
||||
} regs;
|
||||
|
@ -48,7 +48,6 @@ void NECDSP::serialize(serializer &s) {
|
||||
s.integer(regs.dr);
|
||||
s.integer(regs.si);
|
||||
s.integer(regs.so);
|
||||
s.integer(regs.idb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -69,11 +69,11 @@ void OBC1::write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
uint8 OBC1::ram_read(unsigned addr) {
|
||||
return memory::cartram.read(addr & 0x1fff);
|
||||
return cartridge.ram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
void OBC1::ram_write(unsigned addr, uint8 data) {
|
||||
memory::cartram.write(addr & 0x1fff, data);
|
||||
cartridge.ram.write(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
OBC1::OBC1() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
class OBC1 : public Memory {
|
||||
class OBC1 {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
|
@ -1,218 +1,34 @@
|
||||
#ifdef SA1_CPP
|
||||
|
||||
VBRBus vbrbus;
|
||||
SA1Bus sa1bus;
|
||||
//ROM / RAM access from the S-CPU
|
||||
|
||||
namespace memory {
|
||||
StaticRAM iram(2048);
|
||||
//accessed by:
|
||||
VSPROM vsprom; //S-CPU + SA-1
|
||||
CPUIRAM cpuiram; //S-CPU
|
||||
SA1IRAM sa1iram; //SA-1
|
||||
SA1BWRAM sa1bwram; //SA-1
|
||||
CC1BWRAM cc1bwram; //S-CPU
|
||||
BitmapRAM bitmapram; //SA-1
|
||||
unsigned SA1::CPUIRAM::size() const {
|
||||
return sa1.iram.size();
|
||||
}
|
||||
|
||||
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.
|
||||
//this is used both to avoid VBR-reads from accessing MMIO registers, and
|
||||
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
||||
//these ports.
|
||||
//(* eg, memory::cartram is used directly, as memory::sa1bwram syncs to the S-CPU)
|
||||
void VBRBus::init() {
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cartram);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::vsprom);
|
||||
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::cartram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, memory::iram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cartram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x8000, 0xffff, memory::vsprom);
|
||||
map(MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, memory::vsprom);
|
||||
}
|
||||
|
||||
void SA1Bus::init() {
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, memory::sa1iram);
|
||||
map(MapMode::Direct, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, memory::sa1iram);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::vsprom);
|
||||
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::sa1bwram);
|
||||
map(MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bitmapram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, memory::sa1iram);
|
||||
map(MapMode::Direct, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, memory::sa1iram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1bwram);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x8000, 0xffff, memory::vsprom);
|
||||
map(MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, memory::vsprom);
|
||||
}
|
||||
|
||||
//======
|
||||
//VSPROM
|
||||
//======
|
||||
|
||||
//this class maps $00:[ff00-ffff] for the purpose of supporting:
|
||||
//$2209.d6 IVSW (S-CPU IRQ vector selection) (0 = cart, 1 = SA-1)
|
||||
//$2209.d4 NVSW (S-CPU NMI vector selection) (0 = cart, 1 = SA-1)
|
||||
//when set, vector addresses are over-ridden with SA-1 register settings:
|
||||
//SIV = S-CPU IRQ vector address override
|
||||
//SNV = S-CPU NMI vector address override
|
||||
//
|
||||
//$00:[ffea-ffeb|ffee-ffef] are special cased on read;
|
||||
//all other addresses return original mapped data.
|
||||
|
||||
unsigned VSPROM::size() const {
|
||||
return memory::cartrom.size();
|
||||
}
|
||||
|
||||
uint8 VSPROM::read(unsigned addr) {
|
||||
//use $7fex instead of $ffex due to linear mapping of 32k granularity ROM data
|
||||
if((addr & 0xffffe0) == 0x007fe0) {
|
||||
if(addr == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
|
||||
if(addr == 0x7feb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
|
||||
if(addr == 0x7fee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
|
||||
if(addr == 0x7fef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
|
||||
}
|
||||
return memory::cartrom.read(addr);
|
||||
}
|
||||
|
||||
void VSPROM::write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
//=======
|
||||
//SA1IRAM
|
||||
//=======
|
||||
|
||||
unsigned SA1IRAM::size() const {
|
||||
return memory::iram.size();
|
||||
}
|
||||
|
||||
uint8 SA1IRAM::read(unsigned addr) {
|
||||
sa1.synchronize_cpu();
|
||||
return memory::iram.read(addr);
|
||||
}
|
||||
|
||||
void SA1IRAM::write(unsigned addr, uint8 data) {
|
||||
sa1.synchronize_cpu();
|
||||
memory::iram.write(addr, data);
|
||||
}
|
||||
|
||||
//=======
|
||||
//CPUIRAM
|
||||
//=======
|
||||
|
||||
unsigned CPUIRAM::size() const {
|
||||
return memory::iram.size();
|
||||
}
|
||||
|
||||
uint8 CPUIRAM::read(unsigned addr) {
|
||||
uint8 SA1::CPUIRAM::read(unsigned addr) {
|
||||
cpu.synchronize_coprocessor();
|
||||
return memory::iram.read(addr);
|
||||
return sa1.iram.read(addr);
|
||||
}
|
||||
|
||||
void CPUIRAM::write(unsigned addr, uint8 data) {
|
||||
void SA1::CPUIRAM::write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
memory::iram.write(addr, data);
|
||||
sa1.iram.write(addr, data);
|
||||
}
|
||||
|
||||
//========
|
||||
//SA1BWRAM
|
||||
//========
|
||||
|
||||
unsigned SA1BWRAM::size() const {
|
||||
return memory::cartram.size();
|
||||
unsigned SA1::CPUBWRAM::size() const {
|
||||
return cartridge.ram.size();
|
||||
}
|
||||
|
||||
uint8 SA1BWRAM::read(unsigned addr) {
|
||||
sa1.synchronize_cpu();
|
||||
return memory::cartram.read(addr);
|
||||
}
|
||||
|
||||
void SA1BWRAM::write(unsigned addr, uint8 data) {
|
||||
sa1.synchronize_cpu();
|
||||
memory::cartram.write(addr, data);
|
||||
}
|
||||
|
||||
//========
|
||||
//CC1BWRAM
|
||||
//========
|
||||
|
||||
unsigned CC1BWRAM::size() const {
|
||||
return memory::cartram.size();
|
||||
}
|
||||
|
||||
uint8 CC1BWRAM::read(unsigned addr) {
|
||||
uint8 SA1::CPUBWRAM::read(unsigned addr) {
|
||||
cpu.synchronize_coprocessor();
|
||||
if(dma) return sa1.dma_cc1_read(addr);
|
||||
return memory::cartram.read(addr);
|
||||
return cartridge.ram.read(addr);
|
||||
}
|
||||
|
||||
void CC1BWRAM::write(unsigned addr, uint8 data) {
|
||||
void SA1::CPUBWRAM::write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
memory::cartram.write(addr, data);
|
||||
}
|
||||
|
||||
//=========
|
||||
//BitmapRAM
|
||||
//=========
|
||||
|
||||
unsigned BitmapRAM::size() const {
|
||||
return 0x100000;
|
||||
}
|
||||
|
||||
uint8 BitmapRAM::read(unsigned addr) {
|
||||
sa1.synchronize_cpu();
|
||||
|
||||
if(sa1.mmio.bbf == 0) {
|
||||
//4bpp
|
||||
unsigned shift = addr & 1;
|
||||
addr = (addr >> 1) & (memory::cartram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: return (memory::cartram.read(addr) >> 0) & 15;
|
||||
case 1: return (memory::cartram.read(addr) >> 4) & 15;
|
||||
}
|
||||
} else {
|
||||
//2bpp
|
||||
unsigned shift = addr & 3;
|
||||
addr = (addr >> 2) & (memory::cartram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: return (memory::cartram.read(addr) >> 0) & 3;
|
||||
case 1: return (memory::cartram.read(addr) >> 2) & 3;
|
||||
case 2: return (memory::cartram.read(addr) >> 4) & 3;
|
||||
case 3: return (memory::cartram.read(addr) >> 6) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitmapRAM::write(unsigned addr, uint8 data) {
|
||||
sa1.synchronize_cpu();
|
||||
|
||||
if(sa1.mmio.bbf == 0) {
|
||||
//4bpp
|
||||
unsigned shift = addr & 1;
|
||||
addr = (addr >> 1) & (memory::cartram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break;
|
||||
case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break;
|
||||
}
|
||||
} else {
|
||||
//2bpp
|
||||
unsigned shift = addr & 3;
|
||||
addr = (addr >> 2) & (memory::cartram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break;
|
||||
case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break;
|
||||
case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break;
|
||||
case 3: data = (memory::cartram.read(addr) & 0x3f) | ((data & 3) << 6); break;
|
||||
}
|
||||
}
|
||||
|
||||
memory::cartram.write(addr, data);
|
||||
cartridge.ram.write(addr, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,55 +1,14 @@
|
||||
struct VBRBus : Bus {
|
||||
void init();
|
||||
};
|
||||
|
||||
struct SA1Bus : Bus {
|
||||
void init();
|
||||
};
|
||||
|
||||
struct VSPROM : Memory {
|
||||
unsigned size() const;
|
||||
alwaysinline uint8 read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8);
|
||||
};
|
||||
StaticRAM iram;
|
||||
|
||||
struct CPUIRAM : Memory {
|
||||
unsigned size() const;
|
||||
alwaysinline uint8 read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8);
|
||||
};
|
||||
} cpuiram;
|
||||
|
||||
struct SA1IRAM : Memory {
|
||||
unsigned size() const;
|
||||
alwaysinline uint8 read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
struct SA1BWRAM : Memory {
|
||||
unsigned size() const;
|
||||
alwaysinline uint8 read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
struct CC1BWRAM : Memory {
|
||||
struct CPUBWRAM : Memory {
|
||||
unsigned size() const;
|
||||
alwaysinline uint8 read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8);
|
||||
bool dma;
|
||||
};
|
||||
|
||||
struct BitmapRAM : Memory {
|
||||
unsigned size() const;
|
||||
alwaysinline uint8 read(unsigned);
|
||||
alwaysinline void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
extern StaticRAM iram;
|
||||
|
||||
extern VSPROM vsprom;
|
||||
extern CPUIRAM cpuiram;
|
||||
extern SA1IRAM sa1iram;
|
||||
extern SA1BWRAM sa1bwram;
|
||||
extern CC1BWRAM cc1bwram;
|
||||
extern BitmapRAM bitmapram;
|
||||
};
|
||||
} cpubwram;
|
||||
|
@ -17,30 +17,30 @@ void SA1::dma_normal() {
|
||||
switch(mmio.sd) {
|
||||
case DMA::SourceROM: {
|
||||
if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) {
|
||||
data = sa1bus.read(dsa);
|
||||
data = bus_read(dsa);
|
||||
}
|
||||
} break;
|
||||
|
||||
case DMA::SourceBWRAM: {
|
||||
if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) {
|
||||
data = sa1bus.read(dsa);
|
||||
data = bus_read(dsa);
|
||||
}
|
||||
} break;
|
||||
|
||||
case DMA::SourceIRAM: {
|
||||
data = memory::iram.read(dsa & 0x07ff);
|
||||
data = iram.read(dsa & 0x07ff);
|
||||
} break;
|
||||
}
|
||||
|
||||
switch((int)mmio.dd) {
|
||||
case DMA::DestBWRAM: {
|
||||
if((dda & 0x40e000) == 0x006000 || (dda & 0xf00000) == 0x400000) {
|
||||
sa1bus.write(dda, data);
|
||||
bus_write(dda, data);
|
||||
}
|
||||
} break;
|
||||
|
||||
case DMA::DestIRAM: {
|
||||
memory::iram.write(dda & 0x07ff, data);
|
||||
iram.write(dda & 0x07ff, data);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@ -59,7 +59,7 @@ void SA1::dma_normal() {
|
||||
//===========================
|
||||
|
||||
void SA1::dma_cc1() {
|
||||
memory::cc1bwram.dma = true;
|
||||
cpubwram.dma = true;
|
||||
mmio.chdma_irqfl = true;
|
||||
if(mmio.chdma_irqen) {
|
||||
mmio.chdma_irqcl = 0;
|
||||
@ -75,7 +75,7 @@ uint8 SA1::dma_cc1_read(unsigned addr) {
|
||||
//buffer next character to I-RAM
|
||||
unsigned bpp = 2 << (2 - mmio.dmacb);
|
||||
unsigned bpl = (8 << mmio.dmasize) >> mmio.dmacb;
|
||||
unsigned bwmask = memory::cartram.size() - 1;
|
||||
unsigned bwmask = cartridge.ram.size() - 1;
|
||||
unsigned tile = ((addr - mmio.dsa) & bwmask) >> (6 - mmio.dmacb);
|
||||
unsigned ty = (tile >> mmio.dmasize);
|
||||
unsigned tx = tile & ((1 << mmio.dmasize) - 1);
|
||||
@ -84,7 +84,7 @@ uint8 SA1::dma_cc1_read(unsigned addr) {
|
||||
for(unsigned y = 0; y < 8; y++) {
|
||||
uint64 data = 0;
|
||||
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||
data |= (uint64)memory::cartram.read((bwaddr + byte) & bwmask) << (byte << 3);
|
||||
data |= (uint64)cartridge.ram.read((bwaddr + byte) & bwmask) << (byte << 3);
|
||||
}
|
||||
bwaddr += bpl;
|
||||
|
||||
@ -104,12 +104,12 @@ uint8 SA1::dma_cc1_read(unsigned addr) {
|
||||
|
||||
for(unsigned byte = 0; byte < bpp; byte++) {
|
||||
unsigned p = mmio.dda + (y << 1) + ((byte & 6) << 3) + (byte & 1);
|
||||
memory::iram.write(p & 0x07ff, out[byte]);
|
||||
iram.write(p & 0x07ff, out[byte]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return memory::iram.read((mmio.dda + (addr & charmask)) & 0x07ff);
|
||||
return iram.read((mmio.dda + (addr & charmask)) & 0x07ff);
|
||||
}
|
||||
|
||||
//===========================
|
||||
@ -130,7 +130,7 @@ void SA1::dma_cc2() {
|
||||
for(unsigned bit = 0; bit < 8; bit++) {
|
||||
output |= ((brf[bit] >> byte) & 1) << (7 - bit);
|
||||
}
|
||||
memory::iram.write(addr + ((byte & 6) << 3) + (byte & 1), output);
|
||||
iram.write(addr + ((byte & 6) << 3) + (byte & 1), output);
|
||||
}
|
||||
|
||||
dma.line = (dma.line + 1) & 15;
|
||||
|
@ -1,5 +1,103 @@
|
||||
#ifdef SA1_CPP
|
||||
|
||||
uint8 SA1::bus_read(unsigned addr) {
|
||||
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff
|
||||
return mmio_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||
return mmc_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
||||
return mmc_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
return mmc_sa1_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||
synchronize_cpu();
|
||||
return iram.read(addr & 2047);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||
synchronize_cpu();
|
||||
return iram.read(addr & 2047);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||
synchronize_cpu();
|
||||
return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
||||
synchronize_cpu();
|
||||
return bitmap_read(addr & 0x0fffff);
|
||||
}
|
||||
}
|
||||
|
||||
void SA1::bus_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff
|
||||
return mmio_write(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
return mmc_sa1_write(addr, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||
synchronize_cpu();
|
||||
return iram.write(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||
synchronize_cpu();
|
||||
return iram.write(addr & 2047, data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||
synchronize_cpu();
|
||||
return cartridge.ram.write(addr & (cartridge.ram.size() - 1), data);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
|
||||
synchronize_cpu();
|
||||
return bitmap_write(addr & 0x0fffff, data);
|
||||
}
|
||||
}
|
||||
|
||||
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.
|
||||
//this is used both to keep VBR-reads from accessing MMIO registers, and
|
||||
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
|
||||
//these ports.
|
||||
uint8 SA1::vbr_read(unsigned addr) {
|
||||
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
|
||||
return mmc_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
|
||||
return mmc_read(addr);
|
||||
}
|
||||
|
||||
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
|
||||
return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
|
||||
return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
|
||||
return iram.read(addr & 2047);
|
||||
}
|
||||
|
||||
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
|
||||
return iram.read(addr & 0x2047);
|
||||
}
|
||||
}
|
||||
|
||||
//ROM, I-RAM and MMIO registers are accessed at ~10.74MHz (2 clock ticks)
|
||||
//BW-RAM is accessed at ~5.37MHz (4 clock ticks)
|
||||
//tick() == 2 clock ticks
|
||||
@ -12,13 +110,155 @@ void SA1::op_io() {
|
||||
uint8 SA1::op_read(unsigned addr) {
|
||||
tick();
|
||||
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
||||
return sa1bus.read(addr);
|
||||
return bus_read(addr);
|
||||
}
|
||||
|
||||
void SA1::op_write(unsigned addr, uint8 data) {
|
||||
tick();
|
||||
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
|
||||
sa1bus.write(addr, data);
|
||||
bus_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 SA1::mmc_read(unsigned addr) {
|
||||
if((addr & 0xffffe0) == 0x00ffe0) {
|
||||
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
|
||||
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
|
||||
if(addr == 0xffee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
|
||||
if(addr == 0xffef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
|
||||
}
|
||||
|
||||
static auto read = [](unsigned addr) {
|
||||
return cartridge.rom.read(bus.mirror(addr, cartridge.rom.size()));
|
||||
};
|
||||
|
||||
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
|
||||
if(mmio.cbmode == 0) return read(0x000000 | addr);
|
||||
return read((mmio.cb << 20) | addr);
|
||||
}
|
||||
|
||||
if((addr & 0xe08000) == 0x208000) { //$20-3f:8000-ffff
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
|
||||
if(mmio.dbmode == 0) return read(0x100000 | addr);
|
||||
return read((mmio.db << 20) | addr);
|
||||
}
|
||||
|
||||
if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
|
||||
if(mmio.ebmode == 0) return read(0x200000 | addr);
|
||||
return read((mmio.eb << 20) | addr);
|
||||
}
|
||||
|
||||
if((addr & 0xe08000) == 0xa08000) { //$a0-bf:8000-ffff
|
||||
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
|
||||
if(mmio.fbmode == 0) return read(0x300000 | addr);
|
||||
return read((mmio.fb << 20) | addr);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xc00000) { //$c0-cf:0000-ffff
|
||||
return read((mmio.cb << 20) | (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xd00000) { //$d0-df:0000-ffff
|
||||
return read((mmio.db << 20) | (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xe00000) { //$e0-ef:0000-ffff
|
||||
return read((mmio.eb << 20) | (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xf00000) { //$f0-ff:0000-ffff
|
||||
return read((mmio.fb << 20) | (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void SA1::mmc_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
uint8 SA1::mmc_cpu_read(unsigned addr) {
|
||||
cpu.synchronize_coprocessor();
|
||||
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
|
||||
return cpubwram.read(addr);
|
||||
}
|
||||
|
||||
void SA1::mmc_cpu_write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
|
||||
cpubwram.write(addr, data);
|
||||
}
|
||||
|
||||
uint8 SA1::mmc_sa1_read(unsigned addr) {
|
||||
synchronize_cpu();
|
||||
if(mmio.sw46 == 0) {
|
||||
//$40-43:0000-ffff x 32 projection
|
||||
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), cartridge.ram.size());
|
||||
return cartridge.ram.read(addr);
|
||||
} else {
|
||||
//$60-6f:0000-ffff x 128 projection
|
||||
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
|
||||
return bitmap_read(addr);
|
||||
}
|
||||
}
|
||||
|
||||
void SA1::mmc_sa1_write(unsigned addr, uint8 data) {
|
||||
synchronize_cpu();
|
||||
if(mmio.sw46 == 0) {
|
||||
//$40-43:0000-ffff x 32 projection
|
||||
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), cartridge.ram.size());
|
||||
cartridge.ram.write(addr, data);
|
||||
} else {
|
||||
//$60-6f:0000-ffff x 128 projection
|
||||
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
|
||||
bitmap_write(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SA1::bitmap_read(unsigned addr) {
|
||||
if(mmio.bbf == 0) {
|
||||
//4bpp
|
||||
unsigned shift = addr & 1;
|
||||
addr = (addr >> 1) & (cartridge.ram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: return (cartridge.ram.read(addr) >> 0) & 15;
|
||||
case 1: return (cartridge.ram.read(addr) >> 4) & 15;
|
||||
}
|
||||
} else {
|
||||
//2bpp
|
||||
unsigned shift = addr & 3;
|
||||
addr = (addr >> 2) & (cartridge.ram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: return (cartridge.ram.read(addr) >> 0) & 3;
|
||||
case 1: return (cartridge.ram.read(addr) >> 2) & 3;
|
||||
case 2: return (cartridge.ram.read(addr) >> 4) & 3;
|
||||
case 3: return (cartridge.ram.read(addr) >> 6) & 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SA1::bitmap_write(unsigned addr, uint8 data) {
|
||||
if(mmio.bbf == 0) {
|
||||
//4bpp
|
||||
unsigned shift = addr & 1;
|
||||
addr = (addr >> 1) & (cartridge.ram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: data = (cartridge.ram.read(addr) & 0xf0) | ((data & 15) << 0); break;
|
||||
case 1: data = (cartridge.ram.read(addr) & 0x0f) | ((data & 15) << 4); break;
|
||||
}
|
||||
} else {
|
||||
//2bpp
|
||||
unsigned shift = addr & 3;
|
||||
addr = (addr >> 2) & (cartridge.ram.size() - 1);
|
||||
switch(shift) { default:
|
||||
case 0: data = (cartridge.ram.read(addr) & 0xfc) | ((data & 3) << 0); break;
|
||||
case 1: data = (cartridge.ram.read(addr) & 0xf3) | ((data & 3) << 2); break;
|
||||
case 2: data = (cartridge.ram.read(addr) & 0xcf) | ((data & 3) << 4); break;
|
||||
case 3: data = (cartridge.ram.read(addr) & 0x3f) | ((data & 3) << 6); break;
|
||||
}
|
||||
}
|
||||
|
||||
cartridge.ram.write(addr, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,19 @@
|
||||
uint8 bus_read(unsigned addr);
|
||||
void bus_write(unsigned addr, uint8 data);
|
||||
uint8 vbr_read(unsigned addr);
|
||||
|
||||
alwaysinline void op_io();
|
||||
alwaysinline uint8 op_read(unsigned addr);
|
||||
alwaysinline void op_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8_t vbr_read(unsigned addr);
|
||||
uint8 mmc_read(unsigned addr);
|
||||
void mmc_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmc_cpu_read(unsigned addr);
|
||||
void mmc_cpu_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mmc_sa1_read(unsigned addr);
|
||||
void mmc_sa1_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 bitmap_read(unsigned addr);
|
||||
void bitmap_write(unsigned addr, uint8 data);
|
||||
|
@ -1,13 +1,5 @@
|
||||
#ifdef SA1_CPP
|
||||
|
||||
//BS-X flash carts, when present, are mapped to 0x400000+
|
||||
Memory& SA1::mmio_access(unsigned &addr) {
|
||||
if(!memory::bsxflash.data()) return memory::vsprom;
|
||||
if(addr < 0x400000) return memory::vsprom;
|
||||
addr &= 0x3fffff;
|
||||
return bsxflash;
|
||||
}
|
||||
|
||||
//(CCNT) SA-1 control
|
||||
void SA1::mmio_w2200(uint8 data) {
|
||||
if(mmio.sa1_resb && !(data & 0x80)) {
|
||||
@ -151,104 +143,35 @@ void SA1::mmio_w2215(uint8 data) { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8
|
||||
void SA1::mmio_w2220(uint8 data) {
|
||||
mmio.cbmode = (data & 0x80);
|
||||
mmio.cb = (data & 0x07);
|
||||
|
||||
unsigned addr = mmio.cb << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.cbmode == 0) {
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
|
||||
} else {
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(DXB) Super MMC bank D
|
||||
void SA1::mmio_w2221(uint8 data) {
|
||||
mmio.dbmode = (data & 0x80);
|
||||
mmio.db = (data & 0x07);
|
||||
|
||||
unsigned addr = mmio.db << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.dbmode == 0) {
|
||||
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
|
||||
} else {
|
||||
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(EXB) Super MMC bank E
|
||||
void SA1::mmio_w2222(uint8 data) {
|
||||
mmio.ebmode = (data & 0x80);
|
||||
mmio.eb = (data & 0x07);
|
||||
|
||||
unsigned addr = mmio.eb << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.ebmode == 0) {
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
|
||||
} else {
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(FXB) Super MMC bank F
|
||||
void SA1::mmio_w2223(uint8 data) {
|
||||
mmio.fbmode = (data & 0x80);
|
||||
mmio.fb = (data & 0x07);
|
||||
|
||||
unsigned addr = mmio.fb << 20;
|
||||
Memory &access = mmio_access(addr);
|
||||
|
||||
if(mmio.fbmode == 0) {
|
||||
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
|
||||
} else {
|
||||
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
|
||||
}
|
||||
|
||||
//(BMAPS) S-CPU BW-RAM address mapping
|
||||
void SA1::mmio_w2224(uint8 data) {
|
||||
mmio.sbm = (data & 0x1f);
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
|
||||
}
|
||||
|
||||
//(BMAP) SA-1 BW-RAM address mapping
|
||||
void SA1::mmio_w2225(uint8 data) {
|
||||
mmio.sw46 = (data & 0x80);
|
||||
mmio.cbm = (data & 0x7f);
|
||||
|
||||
if(mmio.sw46 == 0) {
|
||||
//$[40-43]:[0000-ffff] x 32 projection
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
|
||||
} else {
|
||||
//$[60-6f]:[0000-ffff] x 128 projection
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
//(SWBE) S-CPU BW-RAM write enable
|
||||
@ -294,7 +217,7 @@ void SA1::mmio_w2231(uint8 data) {
|
||||
mmio.dmasize = (data >> 2) & 7;
|
||||
mmio.dmacb = (data & 0x03);
|
||||
|
||||
if(mmio.chdend) memory::cc1bwram.dma = false;
|
||||
if(mmio.chdend) cpubwram.dma = false;
|
||||
if(mmio.dmasize > 5) mmio.dmasize = 5;
|
||||
if(mmio.dmacb > 2) mmio.dmacb = 2;
|
||||
}
|
||||
@ -491,18 +414,18 @@ uint8 SA1::mmio_r230b() { return mmio.overflow << 7; }
|
||||
|
||||
//(VDPL) variable-length data read port low
|
||||
uint8 SA1::mmio_r230c() {
|
||||
uint32 data = (vbrbus.read(mmio.va + 0) << 0)
|
||||
| (vbrbus.read(mmio.va + 1) << 8)
|
||||
| (vbrbus.read(mmio.va + 2) << 16);
|
||||
uint32 data = (vbr_read(mmio.va + 0) << 0)
|
||||
| (vbr_read(mmio.va + 1) << 8)
|
||||
| (vbr_read(mmio.va + 2) << 16);
|
||||
data >>= mmio.vbit;
|
||||
return data >> 0;
|
||||
}
|
||||
|
||||
//(VDPH) variable-length data read port high
|
||||
uint8 SA1::mmio_r230d() {
|
||||
uint32 data = (vbrbus.read(mmio.va + 0) << 0)
|
||||
| (vbrbus.read(mmio.va + 1) << 8)
|
||||
| (vbrbus.read(mmio.va + 2) << 16);
|
||||
uint32 data = (vbr_read(mmio.va + 0) << 0)
|
||||
| (vbr_read(mmio.va + 1) << 8)
|
||||
| (vbr_read(mmio.va + 2) << 16);
|
||||
data >>= mmio.vbit;
|
||||
|
||||
if(mmio.hl == 1) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
Memory& mmio_access(unsigned &addr);
|
||||
|
||||
struct MMIO {
|
||||
//$2200 CCNT
|
||||
@ -64,19 +63,19 @@ struct MMIO {
|
||||
|
||||
//$2220 CXB
|
||||
bool cbmode;
|
||||
uint8 cb;
|
||||
unsigned cb;
|
||||
|
||||
//$2221 DXB
|
||||
bool dbmode;
|
||||
uint8 db;
|
||||
unsigned db;
|
||||
|
||||
//$2222 EXB
|
||||
bool ebmode;
|
||||
uint8 eb;
|
||||
unsigned eb;
|
||||
|
||||
//$2223 FXB
|
||||
bool fbmode;
|
||||
uint8 fb;
|
||||
unsigned fb;
|
||||
|
||||
//$2224 BMAPS
|
||||
uint8 sbm;
|
||||
|
@ -124,17 +124,15 @@ void SA1::enable() {
|
||||
void SA1::power() {
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
vbrbus.init();
|
||||
sa1bus.init();
|
||||
reset();
|
||||
}
|
||||
|
||||
void SA1::reset() {
|
||||
create(SA1::Enter, system.cpu_frequency());
|
||||
|
||||
memory::cc1bwram.dma = false;
|
||||
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
|
||||
memory::iram.write(addr, 0x00);
|
||||
cpubwram.dma = false;
|
||||
for(unsigned addr = 0; addr < iram.size(); addr++) {
|
||||
iram.write(addr, 0x00);
|
||||
}
|
||||
|
||||
regs.pc.d = 0x000000;
|
||||
@ -220,15 +218,15 @@ void SA1::reset() {
|
||||
mmio.vcnt = 0x0000;
|
||||
|
||||
//$2220-2223 CXB, DXB, EXB, FXB
|
||||
mmio.cbmode = 0;
|
||||
mmio.dbmode = 0;
|
||||
mmio.ebmode = 0;
|
||||
mmio.fbmode = 0;
|
||||
mmio.cbmode = 1;
|
||||
mmio.dbmode = 1;
|
||||
mmio.ebmode = 1;
|
||||
mmio.fbmode = 1;
|
||||
|
||||
mmio.cb = 0x00;
|
||||
mmio.db = 0x01;
|
||||
mmio.eb = 0x02;
|
||||
mmio.fb = 0x03;
|
||||
mmio.eb = 0x00;
|
||||
mmio.fb = 0x01;
|
||||
|
||||
//$2224 BMAPS
|
||||
mmio.sbm = 0x00;
|
||||
@ -323,7 +321,7 @@ void SA1::reset() {
|
||||
mmio.overflow = false;
|
||||
}
|
||||
|
||||
SA1::SA1() {
|
||||
SA1::SA1() : iram(2048) {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "bus/bus.hpp"
|
||||
|
||||
class SA1 : public Coprocessor, public CPUcore, public MMIO {
|
||||
class SA1 : public Coprocessor, public CPUcore {
|
||||
public:
|
||||
#include "bus/bus.hpp"
|
||||
#include "dma/dma.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
@ -36,4 +35,3 @@ public:
|
||||
};
|
||||
|
||||
extern SA1 sa1;
|
||||
extern SA1Bus sa1bus;
|
||||
|
@ -15,9 +15,9 @@ void SA1::serialize(serializer &s) {
|
||||
s.integer(status.hcounter);
|
||||
|
||||
//bus/bus.hpp
|
||||
s.array(memory::iram.data(), memory::iram.size());
|
||||
s.array(iram.data(), iram.size());
|
||||
|
||||
s.integer(memory::cc1bwram.dma);
|
||||
s.integer(cpubwram.dma);
|
||||
|
||||
//dma/dma.hpp
|
||||
s.integer(dma.line);
|
||||
|
@ -8,15 +8,14 @@ SDD1 sdd1;
|
||||
#include "serialization.cpp"
|
||||
#include "sdd1emu.cpp"
|
||||
|
||||
void SDD1::init() {}
|
||||
void SDD1::init() {
|
||||
}
|
||||
|
||||
void SDD1::enable() {
|
||||
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
||||
//buffer address and transfer size information for use in SDD1::read()
|
||||
for(unsigned i = 0x4300; i <= 0x437f; i++) {
|
||||
cpu_mmio[i & 0x7f] = memory::mmio.handle(i);
|
||||
memory::mmio.map(i, *this);
|
||||
}
|
||||
//buffer address and transfer size information for use in SDD1::mcu_read()
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
|
||||
}
|
||||
|
||||
void SDD1::power() {
|
||||
@ -44,7 +43,7 @@ uint8 SDD1::mmio_read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
if((addr & 0x4380) == 0x4300) {
|
||||
return cpu_mmio[addr & 0x7f]->mmio_read(addr);
|
||||
return cpu.mmio_read(addr);
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
@ -70,7 +69,7 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
||||
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
|
||||
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
|
||||
}
|
||||
return cpu_mmio[addr & 0x7f]->mmio_write(addr, data);
|
||||
return cpu.mmio_write(addr, data);
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
@ -84,7 +83,7 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
//SDD1::read() is mapped to $[c0-ff]:[0000-ffff]
|
||||
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
|
||||
//the design is meant to be as close to the hardware design as possible, thus this code
|
||||
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
|
||||
//
|
||||
@ -102,7 +101,7 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
|
||||
//
|
||||
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
|
||||
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
|
||||
uint8 SDD1::read(unsigned addr) {
|
||||
uint8 SDD1::mcu_read(unsigned addr) {
|
||||
if(sdd1_enable & xfer_enable) {
|
||||
//at least one channel has S-DD1 decompression enabled ...
|
||||
for(unsigned i = 0; i < 8; i++) {
|
||||
@ -139,10 +138,10 @@ uint8 SDD1::read(unsigned addr) {
|
||||
} //S-DD1 decompressor enabled
|
||||
|
||||
//S-DD1 decompression mode inactive; return ROM data
|
||||
return memory::cartrom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
|
||||
return cartridge.rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
void SDD1::write(unsigned addr, uint8 data) {
|
||||
void SDD1::mcu_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
SDD1::SDD1() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "sdd1emu.hpp"
|
||||
|
||||
class SDD1 : public MMIO, public Memory {
|
||||
class SDD1 {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
@ -10,16 +10,14 @@ public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
uint8 mcu_read(unsigned addr);
|
||||
void mcu_write(unsigned addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
SDD1();
|
||||
~SDD1();
|
||||
|
||||
private:
|
||||
MMIO *cpu_mmio[0x80]; //bus spying hooks to glean information for struct dma[]
|
||||
|
||||
uint8 sdd1_enable; //channel bit-mask
|
||||
uint8 xfer_enable; //channel bit-mask
|
||||
unsigned mmc[4]; //memory map controller ROM indices
|
||||
|
@ -31,7 +31,7 @@ understood.
|
||||
************************************************************************/
|
||||
|
||||
typedef uint8 bool8;
|
||||
#define SDD1_read(__addr) (sdd1.read(__addr))
|
||||
#define SDD1_read(__addr) (sdd1.mcu_read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
@ -61,16 +61,16 @@ void Serial::write(uint8 data) {
|
||||
uint8 Serial::mmio_read(unsigned addr) {
|
||||
cpu.synchronize_coprocessor();
|
||||
switch(addr & 1) { default:
|
||||
case 0: return r4016->mmio_read(addr);
|
||||
case 1: return r4017->mmio_read(addr);
|
||||
case 0: return cpu.mmio_read(addr);
|
||||
case 1: return cpu.mmio_read(addr);
|
||||
}
|
||||
}
|
||||
|
||||
void Serial::mmio_write(unsigned addr, uint8 data) {
|
||||
cpu.synchronize_coprocessor();
|
||||
switch(addr & 1) { default:
|
||||
case 0: r4016->mmio_write(addr, data); break;
|
||||
case 1: r4017->mmio_write(addr, data); break;
|
||||
case 0: cpu.mmio_write(addr, data); break;
|
||||
case 1: cpu.mmio_write(addr, data); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,11 +78,6 @@ void Serial::init() {
|
||||
}
|
||||
|
||||
void Serial::enable() {
|
||||
r4016 = memory::mmio.handle(0x4016);
|
||||
r4017 = memory::mmio.handle(0x4017);
|
||||
memory::mmio.map(0x4016, *this);
|
||||
memory::mmio.map(0x4017, *this);
|
||||
|
||||
if(opened()) close();
|
||||
string name = notdir(cartridge.basename());
|
||||
string path = dir(cartridge.basename());
|
||||
@ -91,6 +86,9 @@ void Serial::enable() {
|
||||
flowcontrol = sym("snesserial_flowcontrol");
|
||||
main = sym("snesserial_main");
|
||||
}
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
|
||||
}
|
||||
|
||||
void Serial::power() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
class Serial : public Coprocessor, public MMIO, public library, public property<Serial> {
|
||||
class Serial : public Coprocessor, public library, public property<Serial> {
|
||||
public:
|
||||
static void Enter();
|
||||
void enter();
|
||||
@ -19,7 +19,6 @@ public:
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
MMIO *r4016, *r4017;
|
||||
function<unsigned ()> baudrate;
|
||||
function<bool ()> flowcontrol;
|
||||
function<void (void (*)(unsigned), uint8_t (*)(), void (*)(uint8_t))> main;
|
||||
|
@ -24,9 +24,9 @@ void SPC7110Decomp::write(uint8 data) {
|
||||
}
|
||||
|
||||
uint8 SPC7110Decomp::dataread() {
|
||||
unsigned size = memory::cartrom.size() - spc7110.data_rom_offset;
|
||||
unsigned size = cartridge.rom.size() - spc7110.data_rom_offset;
|
||||
while(decomp_offset >= size) decomp_offset -= size;
|
||||
return memory::cartrom.read(spc7110.data_rom_offset + decomp_offset++);
|
||||
return cartridge.rom.read(spc7110.data_rom_offset + decomp_offset++);
|
||||
}
|
||||
|
||||
void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
|
||||
|
@ -73,6 +73,7 @@ void SPC7110::serialize(serializer &s) {
|
||||
s.integer(r4841);
|
||||
s.integer(r4842);
|
||||
|
||||
s.array(rtc);
|
||||
s.integer(rtc_state);
|
||||
s.integer(rtc_mode);
|
||||
s.integer(rtc_index);
|
||||
|
@ -6,17 +6,19 @@ using std::numeric_limits;
|
||||
namespace SNES {
|
||||
|
||||
SPC7110 spc7110;
|
||||
SPC7110MCU spc7110mcu;
|
||||
SPC7110DCU spc7110dcu;
|
||||
SPC7110RAM spc7110ram;
|
||||
|
||||
#include "serialization.cpp"
|
||||
#include "decomp.cpp"
|
||||
|
||||
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
void SPC7110::init() {}
|
||||
void SPC7110::enable() {}
|
||||
void SPC7110::init() {
|
||||
}
|
||||
|
||||
void SPC7110::enable() {
|
||||
for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff;
|
||||
if(cartridge.has_spc7110rtc()) cartridge.nvram.append({ "rtc", rtc, 20 });
|
||||
}
|
||||
|
||||
void SPC7110::power() {
|
||||
reset();
|
||||
@ -86,7 +88,7 @@ void SPC7110::reset() {
|
||||
}
|
||||
|
||||
unsigned SPC7110::datarom_addr(unsigned addr) {
|
||||
unsigned size = memory::cartrom.size() - data_rom_offset;
|
||||
unsigned size = cartridge.rom.size() - data_rom_offset;
|
||||
while(addr >= size) addr -= size;
|
||||
return data_rom_offset + addr;
|
||||
}
|
||||
@ -98,17 +100,13 @@ void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8;
|
||||
void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; }
|
||||
|
||||
void SPC7110::update_time(int offset) {
|
||||
time_t rtc_time
|
||||
= (memory::cartrtc.read(16) << 0)
|
||||
| (memory::cartrtc.read(17) << 8)
|
||||
| (memory::cartrtc.read(18) << 16)
|
||||
| (memory::cartrtc.read(19) << 24);
|
||||
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
|
||||
time_t current_time = time(0) - offset;
|
||||
|
||||
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
|
||||
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
|
||||
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
|
||||
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
|
||||
//rtc[] timestamp to remain valid for up to ~34 years from the last update, even if
|
||||
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
|
||||
//or whether time_t is signed or unsigned.
|
||||
time_t diff
|
||||
@ -118,17 +116,17 @@ void SPC7110::update_time(int offset) {
|
||||
if(diff > numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
|
||||
|
||||
bool update = true;
|
||||
if(memory::cartrtc.read(13) & 1) update = false; //do not update if CR0 timer disable flag is set
|
||||
if(memory::cartrtc.read(15) & 3) update = false; //do not update if CR2 timer disable flags are set
|
||||
if(rtc[13] & 1) update = false; //do not update if CR0 timer disable flag is set
|
||||
if(rtc[15] & 3) update = false; //do not update if CR2 timer disable flags are set
|
||||
|
||||
if(diff > 0 && update == true) {
|
||||
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||
unsigned month = memory::cartrtc.read( 8) + memory::cartrtc.read( 9) * 10;
|
||||
unsigned year = memory::cartrtc.read(10) + memory::cartrtc.read(11) * 10;
|
||||
unsigned weekday = memory::cartrtc.read(12);
|
||||
unsigned second = rtc[ 0] + rtc[ 1] * 10;
|
||||
unsigned minute = rtc[ 2] + rtc[ 3] * 10;
|
||||
unsigned hour = rtc[ 4] + rtc[ 5] * 10;
|
||||
unsigned day = rtc[ 6] + rtc[ 7] * 10;
|
||||
unsigned month = rtc[ 8] + rtc[ 9] * 10;
|
||||
unsigned year = rtc[10] + rtc[11] * 10;
|
||||
unsigned weekday = rtc[12];
|
||||
|
||||
day--;
|
||||
month--;
|
||||
@ -171,25 +169,25 @@ void SPC7110::update_time(int offset) {
|
||||
month++;
|
||||
year %= 100;
|
||||
|
||||
memory::cartrtc.write( 0, second % 10);
|
||||
memory::cartrtc.write( 1, second / 10);
|
||||
memory::cartrtc.write( 2, minute % 10);
|
||||
memory::cartrtc.write( 3, minute / 10);
|
||||
memory::cartrtc.write( 4, hour % 10);
|
||||
memory::cartrtc.write( 5, hour / 10);
|
||||
memory::cartrtc.write( 6, day % 10);
|
||||
memory::cartrtc.write( 7, day / 10);
|
||||
memory::cartrtc.write( 8, month % 10);
|
||||
memory::cartrtc.write( 9, month / 10);
|
||||
memory::cartrtc.write(10, year % 10);
|
||||
memory::cartrtc.write(11, (year / 10) % 10);
|
||||
memory::cartrtc.write(12, weekday % 7);
|
||||
rtc[ 0] = second % 10;
|
||||
rtc[ 1] = second / 10;
|
||||
rtc[ 2] = minute % 10;
|
||||
rtc[ 3] = minute / 10;
|
||||
rtc[ 4] = hour % 10;
|
||||
rtc[ 5] = hour / 10;
|
||||
rtc[ 6] = day % 10;
|
||||
rtc[ 7] = day / 10;
|
||||
rtc[ 8] = month % 10;
|
||||
rtc[ 9] = month / 10;
|
||||
rtc[10] = year % 10;
|
||||
rtc[11] = (year / 10) % 10;
|
||||
rtc[12] = weekday % 7;
|
||||
}
|
||||
|
||||
memory::cartrtc.write(16, current_time >> 0);
|
||||
memory::cartrtc.write(17, current_time >> 8);
|
||||
memory::cartrtc.write(18, current_time >> 16);
|
||||
memory::cartrtc.write(19, current_time >> 24);
|
||||
rtc[16] = current_time >> 0;
|
||||
rtc[17] = current_time >> 8;
|
||||
rtc[18] = current_time >> 16;
|
||||
rtc[19] = current_time >> 24;
|
||||
}
|
||||
|
||||
uint8 SPC7110::mmio_read(unsigned addr) {
|
||||
@ -241,7 +239,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
|
||||
set_data_adjust(adjust + 1);
|
||||
}
|
||||
|
||||
uint8 data = memory::cartrom.read(datarom_addr(adjustaddr));
|
||||
uint8 data = cartridge.rom.read(datarom_addr(adjustaddr));
|
||||
if(!(r4818 & 2)) {
|
||||
unsigned increment = (r4818 & 1) ? data_increment() : 1;
|
||||
if(r4818 & 4) increment = (int16)increment; //16-bit sign extend
|
||||
@ -270,7 +268,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
|
||||
unsigned adjust = data_adjust();
|
||||
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||
|
||||
uint8 data = memory::cartrom.read(datarom_addr(addr + adjust));
|
||||
uint8 data = cartridge.rom.read(datarom_addr(addr + adjust));
|
||||
if((r4818 & 0x60) == 0x60) {
|
||||
if((r4818 & 16) == 0) {
|
||||
set_data_pointer(addr + adjust);
|
||||
@ -326,7 +324,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
|
||||
if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00;
|
||||
|
||||
r4842 = 0x80;
|
||||
uint8 data = memory::cartrtc.read(rtc_index);
|
||||
uint8 data = rtc[rtc_index];
|
||||
rtc_index = (rtc_index + 1) & 15;
|
||||
return data;
|
||||
}
|
||||
@ -360,10 +358,10 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||
unsigned index = (r4804 << 2);
|
||||
unsigned length = (r4809 + (r480a << 8));
|
||||
unsigned addr = datarom_addr(table + index);
|
||||
unsigned mode = (memory::cartrom.read(addr + 0));
|
||||
unsigned offset = (memory::cartrom.read(addr + 1) << 16)
|
||||
+ (memory::cartrom.read(addr + 2) << 8)
|
||||
+ (memory::cartrom.read(addr + 3) << 0);
|
||||
unsigned mode = (cartridge.rom.read(addr + 0));
|
||||
unsigned offset = (cartridge.rom.read(addr + 1) << 16)
|
||||
+ (cartridge.rom.read(addr + 2) << 8)
|
||||
+ (cartridge.rom.read(addr + 3) << 0);
|
||||
|
||||
decomp.init(mode, offset, (r4805 + (r4806 << 8)) << mode);
|
||||
r480c = 0x80;
|
||||
@ -599,10 +597,10 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||
if(data & 8) {
|
||||
update_time();
|
||||
|
||||
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||
unsigned second = rtc[ 0] + rtc[ 1] * 10;
|
||||
//clear seconds
|
||||
memory::cartrtc.write(0, 0);
|
||||
memory::cartrtc.write(1, 0);
|
||||
rtc[0] = 0;
|
||||
rtc[1] = 0;
|
||||
|
||||
if(second >= 30) update_time(+60);
|
||||
}
|
||||
@ -611,21 +609,21 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||
//control register 2
|
||||
if(rtc_index == 15) {
|
||||
//disable timer and clear second counter
|
||||
if((data & 1) && !(memory::cartrtc.read(15) & 1)) {
|
||||
if((data & 1) && !(rtc[15] & 1)) {
|
||||
update_time();
|
||||
|
||||
//clear seconds
|
||||
memory::cartrtc.write(0, 0);
|
||||
memory::cartrtc.write(1, 0);
|
||||
rtc[0] = 0;
|
||||
rtc[1] = 0;
|
||||
}
|
||||
|
||||
//disable timer
|
||||
if((data & 2) && !(memory::cartrtc.read(15) & 2)) {
|
||||
if((data & 2) && !(rtc[15] & 2)) {
|
||||
update_time();
|
||||
}
|
||||
}
|
||||
|
||||
memory::cartrtc.write(rtc_index, data & 15);
|
||||
rtc[rtc_index] = data & 15;
|
||||
rtc_index = (rtc_index + 1) & 15;
|
||||
} break;
|
||||
} //switch(rtc_state)
|
||||
@ -636,49 +634,41 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
|
||||
SPC7110::SPC7110() {
|
||||
}
|
||||
|
||||
//==========
|
||||
//SPC7110MCU
|
||||
//==========
|
||||
//============
|
||||
//SPC7110::MCU
|
||||
//============
|
||||
|
||||
unsigned SPC7110MCU::size() const {
|
||||
return 0x300000;
|
||||
}
|
||||
|
||||
uint8 SPC7110MCU::read(unsigned addr) {
|
||||
if(addr <= 0xdfffff) return memory::cartrom.read(spc7110.dx_offset + (addr & 0x0fffff));
|
||||
if(addr <= 0xefffff) return memory::cartrom.read(spc7110.ex_offset + (addr & 0x0fffff));
|
||||
if(addr <= 0xffffff) return memory::cartrom.read(spc7110.fx_offset + (addr & 0x0fffff));
|
||||
uint8 SPC7110::mcu_read(unsigned addr) {
|
||||
if(addr <= 0xdfffff) return cartridge.rom.read(dx_offset + (addr & 0x0fffff));
|
||||
if(addr <= 0xefffff) return cartridge.rom.read(ex_offset + (addr & 0x0fffff));
|
||||
if(addr <= 0xffffff) return cartridge.rom.read(fx_offset + (addr & 0x0fffff));
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void SPC7110MCU::write(unsigned addr, uint8 data) {
|
||||
void SPC7110::mcu_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
//==========
|
||||
//SPC7110DCU
|
||||
//==========
|
||||
//============
|
||||
//SPC7110::DCU
|
||||
//============
|
||||
|
||||
uint8 SPC7110DCU::read(unsigned) {
|
||||
return spc7110.mmio_read(0x4800);
|
||||
uint8 SPC7110::dcu_read(unsigned) {
|
||||
return mmio_read(0x4800);
|
||||
}
|
||||
|
||||
void SPC7110DCU::write(unsigned, uint8) {
|
||||
void SPC7110::dcu_write(unsigned, uint8) {
|
||||
}
|
||||
|
||||
//==========
|
||||
//SPC7110RAM
|
||||
//==========
|
||||
//============
|
||||
//SPC7110::RAM
|
||||
//============
|
||||
|
||||
unsigned SPC7110RAM::size() const {
|
||||
return 0x2000;
|
||||
uint8 SPC7110::ram_read(unsigned addr) {
|
||||
return cartridge.ram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
uint8 SPC7110RAM::read(unsigned addr) {
|
||||
return memory::cartram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
void SPC7110RAM::write(unsigned addr, uint8 data) {
|
||||
if(spc7110.r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
|
||||
void SPC7110::ram_write(unsigned addr, uint8 data) {
|
||||
if(r4830 & 0x80) cartridge.ram.write(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,8 +17,9 @@
|
||||
|
||||
#include "decomp.hpp"
|
||||
|
||||
class SPC7110 : public MMIO {
|
||||
class SPC7110 {
|
||||
public:
|
||||
uint8 rtc[20];
|
||||
unsigned data_rom_offset;
|
||||
|
||||
void init();
|
||||
@ -40,6 +41,15 @@ public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 mcu_read(unsigned addr);
|
||||
void mcu_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 dcu_read(unsigned);
|
||||
void dcu_write(unsigned, uint8);
|
||||
|
||||
uint8 ram_read(unsigned addr);
|
||||
void ram_write(unsigned addr, uint8 data);
|
||||
|
||||
//spc7110decomp
|
||||
void decomp_init();
|
||||
uint8 decomp_read();
|
||||
@ -130,32 +140,6 @@ private:
|
||||
unsigned rtc_index;
|
||||
|
||||
static const unsigned months[12];
|
||||
friend class SPC7110MCU;
|
||||
friend class SPC7110DCU;
|
||||
friend class SPC7110RAM;
|
||||
};
|
||||
|
||||
class SPC7110MCU : public Memory {
|
||||
public:
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
};
|
||||
|
||||
class SPC7110DCU : public Memory {
|
||||
public:
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
};
|
||||
|
||||
class SPC7110RAM : public Memory {
|
||||
public:
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
};
|
||||
|
||||
extern SPC7110 spc7110;
|
||||
extern SPC7110MCU spc7110mcu;
|
||||
extern SPC7110DCU spc7110dcu;
|
||||
extern SPC7110RAM spc7110ram;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifdef SRTC_CPP
|
||||
|
||||
void SRTC::serialize(serializer &s) {
|
||||
s.array(rtc);
|
||||
s.integer(rtc_mode);
|
||||
s.integer(rtc_index);
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ void SRTC::init() {
|
||||
}
|
||||
|
||||
void SRTC::enable() {
|
||||
for(unsigned n = 0; n < 20; n++) rtc[n] = 0xff;
|
||||
cartridge.nvram.append({ "rtc", rtc, 20 });
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
@ -29,17 +31,13 @@ void SRTC::reset() {
|
||||
}
|
||||
|
||||
void SRTC::update_time() {
|
||||
time_t rtc_time
|
||||
= (memory::cartrtc.read(16) << 0)
|
||||
| (memory::cartrtc.read(17) << 8)
|
||||
| (memory::cartrtc.read(18) << 16)
|
||||
| (memory::cartrtc.read(19) << 24);
|
||||
time_t rtc_time = (rtc[16] << 0) | (rtc[17] << 8) | (rtc[18] << 16) | (rtc[19] << 24);
|
||||
time_t current_time = time(0);
|
||||
|
||||
//sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic.
|
||||
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
|
||||
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
|
||||
//accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow
|
||||
//memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if
|
||||
//rtc[] timestamp to remain valid for up to ~34 years from the last update, even if
|
||||
//time_t overflows. calculation should be valid regardless of number representation, time_t size,
|
||||
//or whether time_t is signed or unsigned.
|
||||
time_t diff
|
||||
@ -49,13 +47,13 @@ void SRTC::update_time() {
|
||||
if(diff > numeric_limits<time_t>::max() / 2) diff = 0; //compensate for underflow
|
||||
|
||||
if(diff > 0) {
|
||||
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||
unsigned month = memory::cartrtc.read( 8);
|
||||
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||
unsigned weekday = memory::cartrtc.read(12);
|
||||
unsigned second = rtc[ 0] + rtc[ 1] * 10;
|
||||
unsigned minute = rtc[ 2] + rtc[ 3] * 10;
|
||||
unsigned hour = rtc[ 4] + rtc[ 5] * 10;
|
||||
unsigned day = rtc[ 6] + rtc[ 7] * 10;
|
||||
unsigned month = rtc[ 8];
|
||||
unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100;
|
||||
unsigned weekday = rtc[12];
|
||||
|
||||
day--;
|
||||
month--;
|
||||
@ -98,25 +96,25 @@ void SRTC::update_time() {
|
||||
month++;
|
||||
year -= 1000;
|
||||
|
||||
memory::cartrtc.write( 0, second % 10);
|
||||
memory::cartrtc.write( 1, second / 10);
|
||||
memory::cartrtc.write( 2, minute % 10);
|
||||
memory::cartrtc.write( 3, minute / 10);
|
||||
memory::cartrtc.write( 4, hour % 10);
|
||||
memory::cartrtc.write( 5, hour / 10);
|
||||
memory::cartrtc.write( 6, day % 10);
|
||||
memory::cartrtc.write( 7, day / 10);
|
||||
memory::cartrtc.write( 8, month);
|
||||
memory::cartrtc.write( 9, year % 10);
|
||||
memory::cartrtc.write(10, (year / 10) % 10);
|
||||
memory::cartrtc.write(11, year / 100);
|
||||
memory::cartrtc.write(12, weekday % 7);
|
||||
rtc[ 0] = second % 10;
|
||||
rtc[ 1] = second / 10;
|
||||
rtc[ 2] = minute % 10;
|
||||
rtc[ 3] = minute / 10;
|
||||
rtc[ 4] = hour % 10;
|
||||
rtc[ 5] = hour / 10;
|
||||
rtc[ 6] = day % 10;
|
||||
rtc[ 7] = day / 10;
|
||||
rtc[ 8] = month;
|
||||
rtc[ 9] = year % 10;
|
||||
rtc[10] = (year / 10) % 10;
|
||||
rtc[11] = year / 100;
|
||||
rtc[12] = weekday % 7;
|
||||
}
|
||||
|
||||
memory::cartrtc.write(16, current_time >> 0);
|
||||
memory::cartrtc.write(17, current_time >> 8);
|
||||
memory::cartrtc.write(18, current_time >> 16);
|
||||
memory::cartrtc.write(19, current_time >> 24);
|
||||
rtc[16] = current_time >> 0;
|
||||
rtc[17] = current_time >> 8;
|
||||
rtc[18] = current_time >> 16;
|
||||
rtc[19] = current_time >> 24;
|
||||
}
|
||||
|
||||
//returns day of week for specified date
|
||||
@ -158,7 +156,7 @@ unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
|
||||
return (sum + 1) % 7; //1900-01-01 was a Monday
|
||||
}
|
||||
|
||||
uint8 SRTC::mmio_read(unsigned addr) {
|
||||
uint8 SRTC::read(unsigned addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
if(addr == 0x2800) {
|
||||
@ -172,14 +170,14 @@ uint8 SRTC::mmio_read(unsigned addr) {
|
||||
rtc_index = -1;
|
||||
return 0x0f;
|
||||
} else {
|
||||
return memory::cartrtc.read(rtc_index++);
|
||||
return rtc[rtc_index++];
|
||||
}
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void SRTC::mmio_write(unsigned addr, uint8 data) {
|
||||
void SRTC::write(unsigned addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
|
||||
if(addr == 0x2801) {
|
||||
@ -200,16 +198,16 @@ void SRTC::mmio_write(unsigned addr, uint8 data) {
|
||||
|
||||
if(rtc_mode == RtcWrite) {
|
||||
if(rtc_index >= 0 && rtc_index < 12) {
|
||||
memory::cartrtc.write(rtc_index++, data);
|
||||
rtc[rtc_index++] = data;
|
||||
|
||||
if(rtc_index == 12) {
|
||||
//day of week is automatically calculated and written
|
||||
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||
unsigned month = memory::cartrtc.read( 8);
|
||||
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||
unsigned day = rtc[ 6] + rtc[ 7] * 10;
|
||||
unsigned month = rtc[ 8];
|
||||
unsigned year = rtc[ 9] + rtc[10] * 10 + rtc[11] * 100;
|
||||
year += 1000;
|
||||
|
||||
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
|
||||
rtc[rtc_index++] = weekday(year, month, day);
|
||||
}
|
||||
}
|
||||
} else if(rtc_mode == RtcCommand) {
|
||||
@ -219,7 +217,7 @@ void SRTC::mmio_write(unsigned addr, uint8 data) {
|
||||
} else if(data == 4) {
|
||||
rtc_mode = RtcReady;
|
||||
rtc_index = -1;
|
||||
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
|
||||
for(unsigned i = 0; i < 13; i++) rtc[i] = 0;
|
||||
} else {
|
||||
//unknown behavior
|
||||
rtc_mode = RtcReady;
|
||||
|
@ -1,12 +1,14 @@
|
||||
class SRTC : public MMIO {
|
||||
class SRTC {
|
||||
public:
|
||||
uint8 rtc[20];
|
||||
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
SRTC();
|
||||
|
@ -1,4 +1,4 @@
|
||||
class ST0018 : public MMIO {
|
||||
class ST0018 {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
|
@ -1,72 +1,12 @@
|
||||
#ifdef SUPERFX_CPP
|
||||
|
||||
SuperFXBus superfxbus;
|
||||
|
||||
namespace memory {
|
||||
SuperFXGSUROM gsurom;
|
||||
SuperFXGSURAM gsuram;
|
||||
SuperFXCPUROM fxrom;
|
||||
SuperFXCPURAM fxram;
|
||||
}
|
||||
|
||||
void SuperFXBus::init() {
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
|
||||
map(MapMode::Linear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
|
||||
map(MapMode::Linear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
|
||||
}
|
||||
|
||||
//ROM / RAM access from the SuperFX CPU
|
||||
|
||||
unsigned SuperFXGSUROM::size() const {
|
||||
return memory::cartrom.size();
|
||||
}
|
||||
|
||||
uint8 SuperFXGSUROM::read(unsigned addr) {
|
||||
while(!superfx.regs.scmr.ron && scheduler.sync.i != Scheduler::SynchronizeMode::All) {
|
||||
superfx.add_clocks(6);
|
||||
superfx.synchronize_cpu();
|
||||
}
|
||||
return memory::cartrom.read(addr);
|
||||
}
|
||||
|
||||
void SuperFXGSUROM::write(unsigned addr, uint8 data) {
|
||||
while(!superfx.regs.scmr.ron && scheduler.sync.i != Scheduler::SynchronizeMode::All) {
|
||||
superfx.add_clocks(6);
|
||||
superfx.synchronize_cpu();
|
||||
}
|
||||
memory::cartrom.write(addr, data);
|
||||
}
|
||||
|
||||
unsigned SuperFXGSURAM::size() const {
|
||||
return memory::cartram.size();
|
||||
}
|
||||
|
||||
uint8 SuperFXGSURAM::read(unsigned addr) {
|
||||
while(!superfx.regs.scmr.ran && scheduler.sync.i != Scheduler::SynchronizeMode::All) {
|
||||
superfx.add_clocks(6);
|
||||
superfx.synchronize_cpu();
|
||||
}
|
||||
return memory::cartram.read(addr);
|
||||
}
|
||||
|
||||
void SuperFXGSURAM::write(unsigned addr, uint8 data) {
|
||||
while(!superfx.regs.scmr.ran && scheduler.sync.i != Scheduler::SynchronizeMode::All) {
|
||||
superfx.add_clocks(6);
|
||||
superfx.synchronize_cpu();
|
||||
}
|
||||
memory::cartram.write(addr, data);
|
||||
}
|
||||
|
||||
//ROM / RAM access from the S-CPU
|
||||
|
||||
unsigned SuperFXCPUROM::size() const {
|
||||
return memory::cartrom.size();
|
||||
unsigned SuperFX::ROM::size() const {
|
||||
return cartridge.rom.size();
|
||||
}
|
||||
|
||||
uint8 SuperFXCPUROM::read(unsigned addr) {
|
||||
uint8 SuperFX::ROM::read(unsigned addr) {
|
||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ron) {
|
||||
static const uint8_t data[16] = {
|
||||
0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
|
||||
@ -74,24 +14,24 @@ uint8 SuperFXCPUROM::read(unsigned addr) {
|
||||
};
|
||||
return data[addr & 15];
|
||||
}
|
||||
return memory::cartrom.read(addr);
|
||||
return cartridge.rom.read(addr);
|
||||
}
|
||||
|
||||
void SuperFXCPUROM::write(unsigned addr, uint8 data) {
|
||||
memory::cartrom.write(addr, data);
|
||||
void SuperFX::ROM::write(unsigned addr, uint8 data) {
|
||||
cartridge.rom.write(addr, data);
|
||||
}
|
||||
|
||||
unsigned SuperFXCPURAM::size() const {
|
||||
return memory::cartram.size();
|
||||
unsigned SuperFX::RAM::size() const {
|
||||
return cartridge.ram.size();
|
||||
}
|
||||
|
||||
uint8 SuperFXCPURAM::read(unsigned addr) {
|
||||
uint8 SuperFX::RAM::read(unsigned addr) {
|
||||
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr;
|
||||
return memory::cartram.read(addr);
|
||||
return cartridge.ram.read(addr);
|
||||
}
|
||||
|
||||
void SuperFXCPURAM::write(unsigned addr, uint8 data) {
|
||||
memory::cartram.write(addr, data);
|
||||
void SuperFX::RAM::write(unsigned addr, uint8 data) {
|
||||
cartridge.ram.write(addr, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,34 +1,11 @@
|
||||
struct SuperFXBus : Bus {
|
||||
void init();
|
||||
};
|
||||
|
||||
struct SuperFXGSUROM : Memory {
|
||||
struct ROM : Memory {
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned);
|
||||
void write(unsigned, uint8);
|
||||
};
|
||||
} rom;
|
||||
|
||||
struct SuperFXGSURAM : Memory {
|
||||
struct RAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned);
|
||||
void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
struct SuperFXCPUROM : Memory {
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned);
|
||||
void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
struct SuperFXCPURAM : Memory {
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned);
|
||||
void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
extern SuperFXGSUROM gsurom;
|
||||
extern SuperFXGSURAM gsuram;
|
||||
extern SuperFXCPUROM fxrom;
|
||||
extern SuperFXCPURAM fxram;
|
||||
}
|
||||
} ram;
|
||||
|
@ -66,7 +66,7 @@ uint8 SuperFX::rpix(uint8 x, uint8 y) {
|
||||
for(unsigned n = 0; n < bpp; n++) {
|
||||
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
|
||||
add_clocks(memory_access_speed);
|
||||
data |= ((superfxbus.read(addr + byte) >> x) & 1) << n;
|
||||
data |= ((bus_read(addr + byte) >> x) & 1) << n;
|
||||
}
|
||||
|
||||
return data;
|
||||
@ -95,10 +95,10 @@ void SuperFX::pixelcache_flush(pixelcache_t &cache) {
|
||||
if(cache.bitpend != 0xff) {
|
||||
add_clocks(memory_access_speed);
|
||||
data &= cache.bitpend;
|
||||
data |= superfxbus.read(addr + byte) & ~cache.bitpend;
|
||||
data |= bus_read(addr + byte) & ~cache.bitpend;
|
||||
}
|
||||
add_clocks(memory_access_speed);
|
||||
superfxbus.write(addr + byte, data);
|
||||
bus_write(addr + byte, data);
|
||||
}
|
||||
|
||||
cache.bitpend = 0x00;
|
||||
|
@ -36,8 +36,8 @@ void SuperFX::disassemble_opcode(char *output) {
|
||||
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 superfxbus.read((regs.pbr << 16) + regs.r[15] + 0)
|
||||
#define op2 superfxbus.read((regs.pbr << 16) + regs.r[15] + 1)
|
||||
#define op1 bus_read((regs.pbr << 16) + regs.r[15] + 0)
|
||||
#define op2 bus_read((regs.pbr << 16) + regs.r[15] + 1)
|
||||
|
||||
void SuperFX::disassemble_alt0(char *output) {
|
||||
char t[256] = "";
|
||||
|
@ -1,5 +1,41 @@
|
||||
#ifdef SUPERFX_CPP
|
||||
|
||||
uint8 SuperFX::bus_read(unsigned addr) {
|
||||
if((addr & 0xc00000) == 0x000000) { //$00-3f:0000-7fff, $00-3f:8000-ffff
|
||||
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
add_clocks(6);
|
||||
synchronize_cpu();
|
||||
}
|
||||
return cartridge.rom.read((((addr & 0x3f0000) >> 1) | (addr & 0x7fff)) & rom_mask);
|
||||
}
|
||||
|
||||
if((addr & 0xe00000) == 0x400000) { //$40-5f:0000-ffff
|
||||
while(!regs.scmr.ron && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
add_clocks(6);
|
||||
synchronize_cpu();
|
||||
}
|
||||
return cartridge.rom.read(addr & rom_mask);
|
||||
}
|
||||
|
||||
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
||||
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
add_clocks(6);
|
||||
synchronize_cpu();
|
||||
}
|
||||
return cartridge.ram.read(addr & ram_mask);
|
||||
}
|
||||
}
|
||||
|
||||
void SuperFX::bus_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xe00000) == 0x600000) { //$60-7f:0000-ffff
|
||||
while(!regs.scmr.ran && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
add_clocks(6);
|
||||
synchronize_cpu();
|
||||
}
|
||||
return cartridge.ram.write(addr & ram_mask, data);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SuperFX::op_read(uint16 addr) {
|
||||
uint16 offset = addr - regs.cbr;
|
||||
if(offset < 512) {
|
||||
@ -8,7 +44,7 @@ uint8 SuperFX::op_read(uint16 addr) {
|
||||
unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
add_clocks(memory_access_speed);
|
||||
cache.buffer[dp++] = superfxbus.read(sp++);
|
||||
cache.buffer[dp++] = bus_read(sp++);
|
||||
}
|
||||
cache.valid[offset >> 4] = true;
|
||||
} else {
|
||||
@ -21,12 +57,12 @@ uint8 SuperFX::op_read(uint16 addr) {
|
||||
//$[00-5f]:[0000-ffff] ROM
|
||||
rombuffer_sync();
|
||||
add_clocks(memory_access_speed);
|
||||
return superfxbus.read((regs.pbr << 16) + addr);
|
||||
return bus_read((regs.pbr << 16) + addr);
|
||||
} else {
|
||||
//$[60-7f]:[0000-ffff] RAM
|
||||
rambuffer_sync();
|
||||
add_clocks(memory_access_speed);
|
||||
return superfxbus.read((regs.pbr << 16) + addr);
|
||||
return bus_read((regs.pbr << 16) + addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,6 +96,9 @@ void SuperFX::cache_mmio_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
|
||||
void SuperFX::memory_reset() {
|
||||
rom_mask = cartridge.rom.size() - 1;
|
||||
ram_mask = cartridge.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++) {
|
||||
|
@ -1,3 +1,8 @@
|
||||
unsigned rom_mask; //rom_size - 1
|
||||
unsigned ram_mask; //ram_size - 1
|
||||
uint8 bus_read(unsigned addr);
|
||||
void bus_write(unsigned addr, uint8 data);
|
||||
|
||||
uint8 op_read(uint16 addr);
|
||||
alwaysinline uint8 peekpipe();
|
||||
alwaysinline uint8 pipe();
|
||||
|
@ -53,7 +53,6 @@ void SuperFX::power() {
|
||||
|
||||
void SuperFX::reset() {
|
||||
create(SuperFX::Enter, system.cpu_frequency());
|
||||
superfxbus.init();
|
||||
instruction_counter = 0;
|
||||
|
||||
for(unsigned n = 0; n < 16; n++) regs.r[n] = 0x0000;
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "bus/bus.hpp"
|
||||
|
||||
class SuperFX : public Coprocessor, public MMIO {
|
||||
class SuperFX : public Coprocessor {
|
||||
public:
|
||||
#include "bus/bus.hpp"
|
||||
#include "core/core.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
@ -22,4 +21,3 @@ private:
|
||||
};
|
||||
|
||||
extern SuperFX superfx;
|
||||
extern SuperFXBus superfxbus;
|
||||
|
@ -5,14 +5,14 @@ void SuperFX::add_clocks(unsigned clocks) {
|
||||
regs.romcl -= min(clocks, regs.romcl);
|
||||
if(regs.romcl == 0) {
|
||||
regs.sfr.r = 0;
|
||||
regs.romdr = superfxbus.read((regs.rombr << 16) + regs.r[14]);
|
||||
regs.romdr = bus_read((regs.rombr << 16) + regs.r[14]);
|
||||
}
|
||||
}
|
||||
|
||||
if(regs.ramcl) {
|
||||
regs.ramcl -= min(clocks, regs.ramcl);
|
||||
if(regs.ramcl == 0) {
|
||||
superfxbus.write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr);
|
||||
bus_write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ void SuperFX::rambuffer_sync() {
|
||||
|
||||
uint8 SuperFX::rambuffer_read(uint16 addr) {
|
||||
rambuffer_sync();
|
||||
return superfxbus.read(0x700000 + (regs.rambr << 16) + addr);
|
||||
return bus_read(0x700000 + (regs.rambr << 16) + addr);
|
||||
}
|
||||
|
||||
void SuperFX::rambuffer_write(uint16 addr, uint8 data) {
|
||||
|
@ -98,8 +98,33 @@ void CPU::op_irq() {
|
||||
regs.pc.w = rd.w;
|
||||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
|
||||
read = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
cpu_version = config.cpu.version;
|
||||
foreach(n, wram) n = config.cpu.wram_init_value;
|
||||
|
||||
regs.a = regs.x = regs.y = 0x0000;
|
||||
regs.s = 0x01ff;
|
||||
|
@ -1,5 +1,7 @@
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO {
|
||||
class CPU : public Processor, public CPUcore, public PPUcounter {
|
||||
public:
|
||||
uint8 wram[128 * 1024];
|
||||
|
||||
enum{ Threaded = true };
|
||||
array<Processor*> coprocessors;
|
||||
alwaysinline void step(unsigned clocks);
|
||||
@ -15,6 +17,7 @@ public:
|
||||
alwaysinline bool interrupt_pending() { return status.interrupt_pending; }
|
||||
|
||||
void enter();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
|
@ -1,8 +1,11 @@
|
||||
void mmio_power();
|
||||
void mmio_reset();
|
||||
public:
|
||||
uint8 mmio_read(unsigned addr);
|
||||
void mmio_write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
void mmio_power();
|
||||
void mmio_reset();
|
||||
|
||||
uint8 mmio_r2180();
|
||||
uint8 mmio_r4016();
|
||||
uint8 mmio_r4017();
|
||||
|
@ -4,6 +4,9 @@ void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
CPUcore::core_serialize(s);
|
||||
PPUcounter::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
|
||||
s.integer(cpu_version);
|
||||
|
||||
s.integer(status.interrupt_pending);
|
||||
|
@ -38,24 +38,24 @@ uint8 Debugger::read(Debugger::MemorySource::e source, unsigned addr) {
|
||||
|
||||
case MemorySource::APUBus: {
|
||||
if((addr & 0xffc0) == 0xffc0) return smp.iplrom[addr & 0x3f];
|
||||
return memory::apuram.read(addr & 0xffff);
|
||||
return smp.apuram[addr & 0xffff];
|
||||
} break;
|
||||
|
||||
case MemorySource::APURAM: {
|
||||
return memory::apuram.read(addr & 0xffff);
|
||||
return smp.apuram[addr & 0xffff];
|
||||
} break;
|
||||
|
||||
case MemorySource::VRAM: {
|
||||
return memory::vram.read(addr & 0xffff);
|
||||
return ppu.vram[addr & 0xffff];
|
||||
} break;
|
||||
|
||||
case MemorySource::OAM: {
|
||||
if(addr & 0x0200) return memory::oam.read(0x0200 + (addr & 0x1f));
|
||||
return memory::oam.read(addr & 0x01ff);
|
||||
if(addr & 0x0200) return ppu.oam[0x0200 + (addr & 0x1f)];
|
||||
return ppu.oam[addr & 0x01ff];
|
||||
} break;
|
||||
|
||||
case MemorySource::CGRAM: {
|
||||
return memory::cgram.read(addr & 0x01ff);
|
||||
return ppu.cgram[addr & 0x01ff];
|
||||
} break;
|
||||
}
|
||||
|
||||
@ -67,9 +67,9 @@ void Debugger::write(Debugger::MemorySource::e source, unsigned addr, uint8 data
|
||||
case MemorySource::CPUBus: {
|
||||
//do not write to memory-mapped registers that could affect program behavior
|
||||
if(((addr - 0x2000) & 0x40c000) == 0x000000) break; //$00-3f:2000-5fff MMIO
|
||||
memory::cartrom.write_protect(false);
|
||||
cartridge.rom.write_protect(false);
|
||||
bus.write(addr & 0xffffff, data);
|
||||
memory::cartrom.write_protect(true);
|
||||
cartridge.rom.write_protect(true);
|
||||
} break;
|
||||
|
||||
case MemorySource::APUBus: {
|
||||
@ -77,20 +77,20 @@ void Debugger::write(Debugger::MemorySource::e source, unsigned addr, uint8 data
|
||||
}
|
||||
|
||||
case MemorySource::APURAM: {
|
||||
memory::apuram.write(addr & 0xffff, data);
|
||||
smp.apuram[addr & 0xffff] = data;
|
||||
} break;
|
||||
|
||||
case MemorySource::VRAM: {
|
||||
memory::vram.write(addr & 0xffff, data);
|
||||
ppu.vram[addr & 0xffff] = data;
|
||||
} break;
|
||||
|
||||
case MemorySource::OAM: {
|
||||
if(addr & 0x0200) memory::oam.write(0x0200 + (addr & 0x1f), data);
|
||||
else memory::oam.write(addr & 0x01ff, data);
|
||||
if(addr & 0x0200) ppu.oam[0x0200 + (addr & 0x1f)] = data;
|
||||
else ppu.oam[addr & 0x01ff] = data;
|
||||
} break;
|
||||
|
||||
case MemorySource::CGRAM: {
|
||||
memory::cgram.write(addr & 0x01ff, data);
|
||||
ppu.cgram[addr & 0x01ff] = data;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
void DSP::brr_decode(voice_t &v) {
|
||||
//state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle
|
||||
int nybbles = (state.t_brr_byte << 8) + memory::apuram[(uint16)(v.brr_addr + v.brr_offset + 1)];
|
||||
int nybbles = (state.t_brr_byte << 8) + smp.apuram[(uint16)(v.brr_addr + v.brr_offset + 1)];
|
||||
|
||||
const int filter = (state.t_brr_header >> 2) & 3;
|
||||
const int scale = (state.t_brr_header >> 4);
|
||||
|
@ -13,8 +13,8 @@ int DSP::echo_output(bool channel) {
|
||||
|
||||
void DSP::echo_read(bool channel) {
|
||||
unsigned addr = state.t_echo_ptr + channel * 2;
|
||||
uint8 lo = memory::apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = memory::apuram[(uint16)(addr + 1)];
|
||||
uint8 lo = smp.apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = smp.apuram[(uint16)(addr + 1)];
|
||||
int s = (int16)((hi << 8) + lo);
|
||||
state.echo_hist[channel].write(state.echo_hist_pos, s >> 1);
|
||||
}
|
||||
@ -23,8 +23,8 @@ void DSP::echo_write(bool channel) {
|
||||
if(!(state.t_echo_disabled & 0x20)) {
|
||||
unsigned addr = state.t_echo_ptr + channel * 2;
|
||||
int s = state.t_echo_out[channel];
|
||||
memory::apuram[(uint16)(addr + 0)] = s;
|
||||
memory::apuram[(uint16)(addr + 1)] = s >> 8;
|
||||
smp.apuram[(uint16)(addr + 0)] = s;
|
||||
smp.apuram[(uint16)(addr + 1)] = s >> 8;
|
||||
}
|
||||
|
||||
state.t_echo_out[channel] = 0;
|
||||
|
@ -24,8 +24,8 @@ void DSP::voice_2(voice_t &v) {
|
||||
//read sample pointer (ignored if not needed)
|
||||
uint16 addr = state.t_dir_addr;
|
||||
if(!v.kon_delay) addr += 2;
|
||||
uint8 lo = memory::apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = memory::apuram[(uint16)(addr + 1)];
|
||||
uint8 lo = smp.apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = smp.apuram[(uint16)(addr + 1)];
|
||||
state.t_brr_next_addr = ((hi << 8) + lo);
|
||||
|
||||
state.t_adsr0 = VREG(adsr0);
|
||||
@ -45,8 +45,8 @@ void DSP::voice_3a(voice_t &v) {
|
||||
}
|
||||
|
||||
void DSP::voice_3b(voice_t &v) {
|
||||
state.t_brr_byte = memory::apuram[(uint16)(v.brr_addr + v.brr_offset)];
|
||||
state.t_brr_header = memory::apuram[(uint16)(v.brr_addr)];
|
||||
state.t_brr_byte = smp.apuram[(uint16)(v.brr_addr + v.brr_offset)];
|
||||
state.t_brr_header = smp.apuram[(uint16)(v.brr_addr)];
|
||||
}
|
||||
|
||||
void DSP::voice_3c(voice_t &v) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include "libsnes.hpp"
|
||||
#include <snes.hpp>
|
||||
#include <snes/snes.hpp>
|
||||
|
||||
#include <nall/snes/cartridge.hpp>
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
using namespace nall;
|
||||
#include <iostream>
|
||||
|
||||
struct Interface : public SNES::Interface {
|
||||
snes_video_refresh_t pvideo_refresh;
|
||||
@ -24,7 +24,7 @@ struct Interface : public SNES::Interface {
|
||||
}
|
||||
|
||||
int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
||||
if(pinput_state) return pinput_state(port, (unsigned)device.i, index, id);
|
||||
if(pinput_state) return pinput_state(port, (unsigned)device, index, id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ unsigned snes_library_revision_major(void) {
|
||||
}
|
||||
|
||||
unsigned snes_library_revision_minor(void) {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
void snes_set_video_refresh(snes_video_refresh_t video_refresh) {
|
||||
@ -59,7 +59,7 @@ void snes_set_input_state(snes_input_state_t input_state) {
|
||||
}
|
||||
|
||||
void snes_set_controller_port_device(bool port, unsigned device) {
|
||||
SNES::input.port_set_device(port, (SNES::Input::Device::e)device);
|
||||
SNES::input.port_set_device(port, (SNES::Input::Device)device);
|
||||
}
|
||||
|
||||
void snes_set_cartridge_basename(const char *basename) {
|
||||
@ -120,9 +120,9 @@ bool snes_load_cartridge_normal(
|
||||
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, lstring(xmlrom));
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xmlrom });
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -132,11 +132,11 @@ bool snes_load_cartridge_bsx_slotted(
|
||||
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
if(bsx_data) SNES::memory::bsxflash.copy(bsx_data, bsx_size);
|
||||
if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size);
|
||||
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SNESCartridge(bsx_data, bsx_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, lstring(xmlrom, xmlbsx));
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, { xmlrom, xmlbsx });
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -146,11 +146,11 @@ bool snes_load_cartridge_bsx(
|
||||
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
if(bsx_data) SNES::memory::bsxflash.copy(bsx_data, bsx_size);
|
||||
if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size);
|
||||
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SNESCartridge(bsx_data, bsx_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, lstring(xmlrom, xmlbsx));
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, { xmlrom, xmlbsx });
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -161,13 +161,13 @@ bool snes_load_cartridge_sufami_turbo(
|
||||
const char *stb_xml, const uint8_t *stb_data, unsigned stb_size
|
||||
) {
|
||||
snes_cheat_reset();
|
||||
if(rom_data) SNES::memory::cartrom.copy(rom_data, rom_size);
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
if(sta_data) SNES::memory::stArom.copy(sta_data, sta_size);
|
||||
if(sta_data) SNES::sufamiturbo.slotA.rom.copy(sta_data, sta_size);
|
||||
string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SNESCartridge(sta_data, sta_size).xmlMemoryMap;
|
||||
if(stb_data) SNES::memory::stBrom.copy(stb_data, stb_size);
|
||||
if(stb_data) SNES::sufamiturbo.slotB.rom.copy(stb_data, stb_size);
|
||||
string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SNESCartridge(stb_data, stb_size).xmlMemoryMap;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, lstring(xmlrom, xmlsta, xmlstb));
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, { xmlrom, xmlsta, xmlstb });
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -176,21 +176,14 @@ bool snes_load_cartridge_super_game_boy(
|
||||
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
|
||||
const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size
|
||||
) {
|
||||
|
||||
string xmlrom, xmldmg;
|
||||
snes_cheat_reset();
|
||||
|
||||
if (rom_data) {
|
||||
xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
SNES::memory::cartrom.copy(rom_data, rom_size);
|
||||
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
|
||||
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SNESCartridge(rom_data, rom_size).xmlMemoryMap;
|
||||
if(dmg_data) {
|
||||
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(dmg_data, dmg_size).xml;
|
||||
GameBoy::cartridge.load(dmg_xml, dmg_data, dmg_size);
|
||||
}
|
||||
|
||||
if (dmg_data) {
|
||||
xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(dmg_data, dmg_size).xml;
|
||||
GameBoy::cartridge.load(xmldmg, dmg_data, dmg_size);
|
||||
}
|
||||
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, lstring(xmlrom, ""));
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, { xmlrom, "" });
|
||||
SNES::system.power();
|
||||
return true;
|
||||
}
|
||||
@ -200,7 +193,7 @@ void snes_unload_cartridge(void) {
|
||||
}
|
||||
|
||||
bool snes_get_region(void) {
|
||||
return SNES::system.region.i == SNES::System::Region::NTSC ? 0 : 1;
|
||||
return SNES::system.region() == SNES::System::Region::NTSC ? 0 : 1;
|
||||
}
|
||||
|
||||
uint8_t* snes_get_memory_data(unsigned id) {
|
||||
@ -208,27 +201,40 @@ uint8_t* snes_get_memory_data(unsigned id) {
|
||||
|
||||
switch(id) {
|
||||
case SNES_MEMORY_CARTRIDGE_RAM:
|
||||
return SNES::memory::cartram.data();
|
||||
return SNES::cartridge.ram.data();
|
||||
case SNES_MEMORY_CARTRIDGE_RTC:
|
||||
return SNES::memory::cartrtc.data();
|
||||
if(SNES::cartridge.has_srtc()) return SNES::srtc.rtc;
|
||||
if(SNES::cartridge.has_spc7110rtc()) return SNES::spc7110.rtc;
|
||||
return 0;
|
||||
case SNES_MEMORY_BSX_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
return SNES::memory::bsxram.data();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
return SNES::bsxcartridge.sram.data();
|
||||
case SNES_MEMORY_BSX_PRAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
return SNES::memory::bsxpram.data();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
return SNES::bsxcartridge.psram.data();
|
||||
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return SNES::memory::stAram.data();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return SNES::sufamiturbo.slotA.ram.data();
|
||||
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return SNES::memory::stBram.data();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
return SNES::sufamiturbo.slotB.ram.data();
|
||||
case SNES_MEMORY_GAME_BOY_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
return GameBoy::cartridge.ramdata;
|
||||
case SNES_MEMORY_GAME_BOY_RTC:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
return 0; // FIXME: Where is this stored?
|
||||
//case SNES_MEMORY_GAME_BOY_RTC:
|
||||
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
// return GameBoy::cartridge.rtcdata;
|
||||
|
||||
case SNES_MEMORY_WRAM:
|
||||
return SNES::cpu.wram;
|
||||
case SNES_MEMORY_APURAM:
|
||||
return SNES::smp.apuram;
|
||||
case SNES_MEMORY_VRAM:
|
||||
return SNES::ppu.vram;
|
||||
case SNES_MEMORY_OAM:
|
||||
return SNES::ppu.oam;
|
||||
case SNES_MEMORY_CGRAM:
|
||||
return SNES::ppu.cgram;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -240,34 +246,51 @@ unsigned snes_get_memory_size(unsigned id) {
|
||||
|
||||
switch(id) {
|
||||
case SNES_MEMORY_CARTRIDGE_RAM:
|
||||
size = SNES::memory::cartram.size();
|
||||
size = SNES::cartridge.ram.size();
|
||||
break;
|
||||
case SNES_MEMORY_CARTRIDGE_RTC:
|
||||
size = SNES::memory::cartrtc.size();
|
||||
if(SNES::cartridge.has_srtc() || SNES::cartridge.has_spc7110rtc()) size = 20;
|
||||
break;
|
||||
case SNES_MEMORY_BSX_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
size = SNES::memory::bsxram.size();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
size = SNES::bsxcartridge.sram.size();
|
||||
break;
|
||||
case SNES_MEMORY_BSX_PRAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::Bsx) break;
|
||||
size = SNES::memory::bsxpram.size();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
|
||||
size = SNES::bsxcartridge.psram.size();
|
||||
break;
|
||||
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
size = SNES::memory::stAram.size();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
size = SNES::sufamiturbo.slotA.ram.size();
|
||||
break;
|
||||
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
size = SNES::memory::stBram.size();
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
|
||||
size = SNES::sufamiturbo.slotB.ram.size();
|
||||
break;
|
||||
case SNES_MEMORY_GAME_BOY_RAM:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
size = GameBoy::cartridge.ramsize;
|
||||
break;
|
||||
case SNES_MEMORY_GAME_BOY_RTC:
|
||||
if(SNES::cartridge.mode.i != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
size = 0; // FIXME: Where is this stored?
|
||||
//case SNES_MEMORY_GAME_BOY_RTC:
|
||||
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
|
||||
// size = GameBoy::cartridge.rtcsize;
|
||||
// break;
|
||||
|
||||
case SNES_MEMORY_WRAM:
|
||||
size = 128 * 1024;
|
||||
break;
|
||||
case SNES_MEMORY_APURAM:
|
||||
size = 64 * 1024;
|
||||
break;
|
||||
case SNES_MEMORY_VRAM:
|
||||
size = 64 * 1024;
|
||||
break;
|
||||
case SNES_MEMORY_OAM:
|
||||
size = 544;
|
||||
break;
|
||||
case SNES_MEMORY_CGRAM:
|
||||
size = 512;
|
||||
break;
|
||||
}
|
||||
|
||||
if(size == -1U) size = 0;
|
||||
|
@ -60,6 +60,13 @@ extern "C" {
|
||||
#define SNES_MEMORY_GAME_BOY_RAM 6
|
||||
#define SNES_MEMORY_GAME_BOY_RTC 7
|
||||
|
||||
#define SNES_MEMORY_WRAM 100
|
||||
#define SNES_MEMORY_APURAM 101
|
||||
#define SNES_MEMORY_VRAM 102
|
||||
#define SNES_MEMORY_OAM 103
|
||||
#define SNES_MEMORY_CGRAM 104
|
||||
|
||||
|
||||
// Note: Only one instance of the libsnes library is supported in one process.
|
||||
// Compiling with C, you might have to #include <stdbool.h> since bool is not a recognized keyword in C(99) without this header.
|
||||
|
||||
|
@ -22,14 +22,14 @@ void MappedRAM::reset() {
|
||||
delete[] data_;
|
||||
data_ = 0;
|
||||
}
|
||||
size_ = -1U;
|
||||
size_ = 0;
|
||||
write_protect_ = false;
|
||||
}
|
||||
|
||||
void MappedRAM::map(uint8 *source, unsigned length) {
|
||||
reset();
|
||||
data_ = source;
|
||||
size_ = data_ && length > 0 ? length : -1U;
|
||||
size_ = data_ ? length : 0;
|
||||
}
|
||||
|
||||
void MappedRAM::copy(const uint8 *data, unsigned size) {
|
||||
@ -47,22 +47,14 @@ unsigned MappedRAM::size() const { return size_; }
|
||||
uint8 MappedRAM::read(unsigned addr) { return data_[addr]; }
|
||||
void MappedRAM::write(unsigned addr, uint8 n) { if(!write_protect_) data_[addr] = n; }
|
||||
const uint8& MappedRAM::operator[](unsigned addr) const { return data_[addr]; }
|
||||
MappedRAM::MappedRAM() : data_(0), size_(-1U), write_protect_(false) {}
|
||||
MappedRAM::MappedRAM() : data_(0), size_(0), write_protect_(false) {}
|
||||
|
||||
//Bus
|
||||
|
||||
uint8 Bus::read(uint24 addr) {
|
||||
#if defined(CHEAT_SYSTEM)
|
||||
if(cheat.active() && cheat.exists(addr)) {
|
||||
uint8 r;
|
||||
if(cheat.read(addr, r)) return r;
|
||||
}
|
||||
#endif
|
||||
Page &p = page[addr >> 8];
|
||||
return p.access->read(p.offset + addr);
|
||||
uint8 Bus::read(unsigned addr) {
|
||||
return reader[lookup[addr]](target[addr]);
|
||||
}
|
||||
|
||||
void Bus::write(uint24 addr, uint8 data) {
|
||||
Page &p = page[addr >> 8];
|
||||
p.access->write(p.offset + addr, data);
|
||||
void Bus::write(unsigned addr, uint8 data) {
|
||||
return writer[lookup[addr]](target[addr], data);
|
||||
}
|
||||
|
@ -5,47 +5,6 @@ namespace SNES {
|
||||
|
||||
Bus bus;
|
||||
|
||||
#include "serialization.cpp"
|
||||
|
||||
namespace memory {
|
||||
MMIOAccess mmio;
|
||||
StaticRAM wram(128 * 1024);
|
||||
StaticRAM apuram(64 * 1024);
|
||||
StaticRAM vram(64 * 1024);
|
||||
StaticRAM oam(544);
|
||||
StaticRAM cgram(512);
|
||||
|
||||
UnmappedMemory memory_unmapped;
|
||||
UnmappedMMIO mmio_unmapped;
|
||||
};
|
||||
|
||||
unsigned UnmappedMemory::size() const { return 16 * 1024 * 1024; }
|
||||
uint8 UnmappedMemory::read(unsigned) { return cpu.regs.mdr; }
|
||||
void UnmappedMemory::write(unsigned, uint8) {}
|
||||
|
||||
uint8 UnmappedMMIO::mmio_read(unsigned) { return cpu.regs.mdr; }
|
||||
void UnmappedMMIO::mmio_write(unsigned, uint8) {}
|
||||
|
||||
MMIO* MMIOAccess::handle(unsigned addr) {
|
||||
return mmio[addr & 0x7fff];
|
||||
}
|
||||
|
||||
void MMIOAccess::map(unsigned addr, MMIO &access) {
|
||||
mmio[addr & 0x7fff] = &access;
|
||||
}
|
||||
|
||||
uint8 MMIOAccess::read(unsigned addr) {
|
||||
return mmio[addr & 0x7fff]->mmio_read(addr);
|
||||
}
|
||||
|
||||
void MMIOAccess::write(unsigned addr, uint8 data) {
|
||||
mmio[addr & 0x7fff]->mmio_write(addr, data);
|
||||
}
|
||||
|
||||
MMIOAccess::MMIOAccess() {
|
||||
for(unsigned i = 0; i < 0x8000; i++) mmio[i] = &memory::mmio_unmapped;
|
||||
}
|
||||
|
||||
unsigned Bus::mirror(unsigned addr, unsigned size) {
|
||||
unsigned base = 0;
|
||||
if(size) {
|
||||
@ -64,103 +23,61 @@ unsigned Bus::mirror(unsigned addr, unsigned size) {
|
||||
return base;
|
||||
}
|
||||
|
||||
void Bus::map(unsigned addr, Memory &access, unsigned offset) {
|
||||
Page &p = page[addr >> 8];
|
||||
p.access = &access;
|
||||
p.offset = offset - addr;
|
||||
}
|
||||
|
||||
void Bus::map(
|
||||
MapMode::e mode,
|
||||
uint8 bank_lo, uint8 bank_hi,
|
||||
uint16 addr_lo, uint16 addr_hi,
|
||||
Memory &access, unsigned offset, unsigned size
|
||||
MapMode mode,
|
||||
unsigned bank_lo, unsigned bank_hi,
|
||||
unsigned addr_lo, unsigned addr_hi,
|
||||
const function<uint8 (unsigned)> &rd,
|
||||
const function<void (unsigned, uint8)> &wr,
|
||||
unsigned base, unsigned length
|
||||
) {
|
||||
assert(bank_lo <= bank_hi);
|
||||
assert(addr_lo <= addr_hi);
|
||||
if(access.size() == -1U) return;
|
||||
assert(bank_lo <= bank_hi && bank_lo <= 0xff);
|
||||
assert(addr_lo <= addr_hi && addr_lo <= 0xffff);
|
||||
unsigned id = idcount++;
|
||||
assert(id < 255);
|
||||
reader[id] = rd;
|
||||
writer[id] = wr;
|
||||
|
||||
uint8 page_lo = addr_lo >> 8;
|
||||
uint8 page_hi = addr_hi >> 8;
|
||||
unsigned index = 0;
|
||||
if(length == 0) length = (bank_hi - bank_lo + 1) * (addr_hi - addr_lo + 1);
|
||||
|
||||
switch(mode) {
|
||||
case MapMode::Direct: {
|
||||
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
||||
for(unsigned page = page_lo; page <= page_hi; page++) {
|
||||
map((bank << 16) + (page << 8), access, (bank << 16) + (page << 8));
|
||||
}
|
||||
unsigned offset = 0;
|
||||
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
||||
for(unsigned addr = addr_lo; addr <= addr_hi; addr++) {
|
||||
unsigned destaddr = (bank << 16) | addr;
|
||||
if(mode == MapMode::Linear) {
|
||||
destaddr = base + mirror(offset, length);
|
||||
offset = (offset + 1) % length;
|
||||
} else if(mode == MapMode::Shadow) {
|
||||
destaddr = base + mirror(destaddr, length);
|
||||
}
|
||||
} break;
|
||||
|
||||
case MapMode::Linear: {
|
||||
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
||||
for(unsigned page = page_lo; page <= page_hi; page++) {
|
||||
map((bank << 16) + (page << 8), access, mirror(offset + index, access.size()));
|
||||
index += 256;
|
||||
if(size) index %= size;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case MapMode::Shadow: {
|
||||
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
||||
index += page_lo * 256;
|
||||
if(size) index %= size;
|
||||
|
||||
for(unsigned page = page_lo; page <= page_hi; page++) {
|
||||
map((bank << 16) + (page << 8), access, mirror(offset + index, access.size()));
|
||||
index += 256;
|
||||
if(size) index %= size;
|
||||
}
|
||||
|
||||
index += (255 - page_hi) * 256;
|
||||
if(size) index %= size;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Bus::load_cart() {
|
||||
if(cartridge.loaded() == true) return false;
|
||||
|
||||
map_reset();
|
||||
map_xml();
|
||||
map_system();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Bus::unload_cart() {
|
||||
}
|
||||
|
||||
void Bus::map_reset() {
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
|
||||
map(MapMode::Direct, 0x00, 0x3f, 0x2000, 0x5fff, memory::mmio);
|
||||
map(MapMode::Direct, 0x80, 0xbf, 0x2000, 0x5fff, memory::mmio);
|
||||
for(unsigned i = 0x2000; i <= 0x5fff; i++) memory::mmio.map(i, memory::mmio_unmapped);
|
||||
}
|
||||
|
||||
void Bus::map_xml() {
|
||||
foreach(m, cartridge.mapping) {
|
||||
if(m.memory) {
|
||||
map(m.mode.i, m.banklo, m.bankhi, m.addrlo, m.addrhi, *m.memory, m.offset, m.size);
|
||||
} else if(m.mmio) {
|
||||
for(unsigned i = m.addrlo; i <= m.addrhi; i++) memory::mmio.map(i, *m.mmio);
|
||||
lookup[(bank << 16) | addr] = id;
|
||||
target[(bank << 16) | addr] = destaddr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bus::map_system() {
|
||||
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
|
||||
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
|
||||
map(MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, memory::wram);
|
||||
void Bus::map_reset() {
|
||||
function<uint8 (unsigned)> reader = [](unsigned) { return cpu.regs.mdr; };
|
||||
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
|
||||
|
||||
idcount = 0;
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, reader, writer);
|
||||
}
|
||||
|
||||
void Bus::power() {
|
||||
foreach(n, memory::wram) n = config.cpu.wram_init_value;
|
||||
void Bus::map_xml() {
|
||||
foreach(m, cartridge.mapping) {
|
||||
map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, m.read, m.write, m.offset, m.size);
|
||||
}
|
||||
}
|
||||
|
||||
void Bus::reset() {
|
||||
Bus::Bus() {
|
||||
lookup = new uint8 [16 * 1024 * 1024];
|
||||
target = new uint32[16 * 1024 * 1024];
|
||||
}
|
||||
|
||||
Bus::~Bus() {
|
||||
delete[] lookup;
|
||||
delete[] target;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,22 +4,6 @@ struct Memory {
|
||||
virtual void write(unsigned addr, uint8 data) = 0;
|
||||
};
|
||||
|
||||
struct MMIO {
|
||||
virtual uint8 mmio_read(unsigned addr) = 0;
|
||||
virtual void mmio_write(unsigned addr, uint8 data) = 0;
|
||||
};
|
||||
|
||||
struct UnmappedMemory : Memory {
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned);
|
||||
void write(unsigned, uint8);
|
||||
};
|
||||
|
||||
struct UnmappedMMIO : MMIO {
|
||||
uint8 mmio_read(unsigned);
|
||||
void mmio_write(unsigned, uint8);
|
||||
};
|
||||
|
||||
struct StaticRAM : Memory {
|
||||
inline uint8* data();
|
||||
inline unsigned size() const;
|
||||
@ -57,58 +41,34 @@ private:
|
||||
bool write_protect_;
|
||||
};
|
||||
|
||||
struct MMIOAccess : Memory {
|
||||
MMIO* handle(unsigned addr);
|
||||
void map(unsigned addr, MMIO &access);
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
MMIOAccess();
|
||||
|
||||
private:
|
||||
MMIO *mmio[0x8000];
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
unsigned mirror(unsigned addr, unsigned size);
|
||||
void map(unsigned addr, Memory &access, unsigned offset);
|
||||
struct MapMode{ enum e{ Direct, Linear, Shadow } i; };
|
||||
void map(MapMode::e mode,
|
||||
uint8 bank_lo, uint8 bank_hi,
|
||||
uint16 addr_lo, uint16 addr_hi,
|
||||
Memory &access, unsigned offset = 0, unsigned size = 0);
|
||||
|
||||
alwaysinline uint8 read(uint24 addr);
|
||||
alwaysinline void write(uint24 addr, uint8 data);
|
||||
alwaysinline uint8 read(unsigned addr);
|
||||
alwaysinline void write(unsigned addr, uint8 data);
|
||||
|
||||
bool load_cart();
|
||||
void unload_cart();
|
||||
uint8 *lookup;
|
||||
uint32 *target;
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
unsigned idcount;
|
||||
function<uint8 (unsigned)> reader[256];
|
||||
function<void (unsigned, uint8)> writer[256];
|
||||
|
||||
struct Page {
|
||||
Memory *access;
|
||||
unsigned offset;
|
||||
} page[65536];
|
||||
enum class MapMode : unsigned { Direct, Linear, Shadow };
|
||||
void map(
|
||||
MapMode mode,
|
||||
unsigned bank_lo, unsigned bank_hi,
|
||||
unsigned addr_lo, unsigned addr_hi,
|
||||
const function<uint8 (unsigned)> &read,
|
||||
const function<void (unsigned, uint8)> &write,
|
||||
unsigned base = 0, unsigned length = 0
|
||||
);
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
void map_reset();
|
||||
void map_xml();
|
||||
void map_system();
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
extern MMIOAccess mmio; //S-CPU, S-PPU
|
||||
extern StaticRAM wram; //S-CPU
|
||||
extern StaticRAM apuram; //S-SMP, S-DSP
|
||||
extern StaticRAM vram; //S-PPU
|
||||
extern StaticRAM oam; //S-PPU
|
||||
extern StaticRAM cgram; //S-PPU
|
||||
|
||||
extern UnmappedMemory memory_unmapped;
|
||||
extern UnmappedMMIO mmio_unmapped;
|
||||
Bus();
|
||||
~Bus();
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
|
@ -1,11 +0,0 @@
|
||||
#ifdef MEMORY_CPP
|
||||
|
||||
void Bus::serialize(serializer &s) {
|
||||
s.array(memory::wram.data(), memory::wram.size());
|
||||
s.array(memory::apuram.data(), memory::apuram.size());
|
||||
s.array(memory::vram.data(), memory::vram.size());
|
||||
s.array(memory::oam.data(), memory::oam.size());
|
||||
s.array(memory::cgram.data(), memory::cgram.size());
|
||||
}
|
||||
|
||||
#endif
|
@ -96,7 +96,7 @@ void PPU::Background::get_tile() {
|
||||
if(ty & 0x20) offset += screen_y;
|
||||
|
||||
uint16 addr = regs.screen_addr + (offset << 1);
|
||||
tile = (memory::vram[addr + 0] << 0) + (memory::vram[addr + 1] << 8);
|
||||
tile = (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8);
|
||||
bool mirror_y = tile & 0x8000;
|
||||
bool mirror_x = tile & 0x4000;
|
||||
priority = (tile & 0x2000 ? regs.priority1 : regs.priority0);
|
||||
@ -111,18 +111,18 @@ void PPU::Background::get_tile() {
|
||||
offset = (character << (4 + color_depth)) + ((voffset & 7) << 1);
|
||||
|
||||
if(regs.mode >= Mode::BPP2) {
|
||||
data[0] = memory::vram[offset + 0];
|
||||
data[1] = memory::vram[offset + 1];
|
||||
data[0] = ppu.vram[offset + 0];
|
||||
data[1] = ppu.vram[offset + 1];
|
||||
}
|
||||
if(regs.mode >= Mode::BPP4) {
|
||||
data[2] = memory::vram[offset + 16];
|
||||
data[3] = memory::vram[offset + 17];
|
||||
data[2] = ppu.vram[offset + 16];
|
||||
data[3] = ppu.vram[offset + 17];
|
||||
}
|
||||
if(regs.mode >= Mode::BPP8) {
|
||||
data[4] = memory::vram[offset + 32];
|
||||
data[5] = memory::vram[offset + 33];
|
||||
data[6] = memory::vram[offset + 48];
|
||||
data[7] = memory::vram[offset + 49];
|
||||
data[4] = ppu.vram[offset + 32];
|
||||
data[5] = ppu.vram[offset + 33];
|
||||
data[6] = ppu.vram[offset + 48];
|
||||
data[7] = ppu.vram[offset + 49];
|
||||
}
|
||||
|
||||
if(mirror_x) for(unsigned n = 0; n < 8; n++) {
|
||||
@ -273,7 +273,7 @@ unsigned PPU::Background::get_tile(unsigned x, unsigned y) {
|
||||
if(y & 0x20) offset += screen_y;
|
||||
|
||||
uint16 addr = regs.screen_addr + (offset << 1);
|
||||
return (memory::vram[addr + 0] << 0) + (memory::vram[addr + 1] << 8);
|
||||
return (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8);
|
||||
}
|
||||
|
||||
PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) {
|
||||
|
@ -46,8 +46,8 @@ void PPU::Background::run_mode7() {
|
||||
case 1: {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
|
||||
@ -58,8 +58,8 @@ void PPU::Background::run_mode7() {
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -71,9 +71,9 @@ void PPU::Background::run_mode7() {
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
}
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user