This commit is contained in:
Themaister 2011-01-24 18:49:42 +01:00
parent 3b29d40426
commit ce9e66b27a
118 changed files with 1473 additions and 2046 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +0,0 @@
bool Cheat::active() const { return cheat_enabled; }
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&regs, 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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
class Cx4 : public Memory {
class Cx4 {
public:
void init();
void enable();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
class MSU1 : public Coprocessor, public MMIO {
class MSU1 : public Coprocessor {
public:
static void Enter();
void enter();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,5 +48,4 @@ struct Regs {
uint16 dr; //data register
uint16 si;
uint16 so;
uint16 idb;
} regs;

View File

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

View File

@ -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() {}

View File

@ -1,4 +1,4 @@
class OBC1 : public Memory {
class OBC1 {
public:
void init();
void enable();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ understood.
************************************************************************/
typedef uint8 bool8;
#define SDD1_read(__addr) (sdd1.read(__addr))
#define SDD1_read(__addr) (sdd1.mcu_read(__addr))
////////////////////////////////////////////////////

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#ifdef SRTC_CPP
void SRTC::serialize(serializer &s) {
s.array(rtc);
s.integer(rtc_mode);
s.integer(rtc_index);
}

View File

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

View File

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

View File

@ -1,4 +1,4 @@
class ST0018 : public MMIO {
class ST0018 {
public:
void init();
void enable();

View File

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

View File

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

View File

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

View File

@ -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] = "";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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