Update to v074r11 release.

byuu says:

Changelog:
- debugger compiles on all three profiles
- libsnes compiles on all three platforms (no API changes to libsnes)
- memory.cpp : namespace memory removed (wram -> cpu, apuram -> smp,
  vram, oam, cgram -> ppu)
- sa1.cpp : namespace memory removed (SA-1 specific functions merged
  inline to SA1::bus_read,write)
- GameBoy: added serial link support with interrupts and proper 8192hz
  timing, but obviously it acts as if no other GB is connected to it
- GameBoy: added STAT OAM interrupt, and better STAT d1,d0 mode values
- UI: since Qt is dead, I've renamed the config files back to bsnes.cfg
  and bsnes-geometry.cfg
- SA1: IRAM was not syncing to CPU on SA-1 side
- PPU/Accuracy and PPU/Performance needed Sprite oam renamed to Sprite
  sprite; so that I could add uint8 oam[544]
  - makes more sense anyway, OAM = object attribute memory, obj or
    sprite are better names for Sprite rendering class
- more cleanup
This commit is contained in:
Tim Allen 2011-01-24 20:03:17 +11:00
parent 054bdd4094
commit 53fe43afd8
76 changed files with 565 additions and 601 deletions

View File

@ -120,12 +120,19 @@ void CPU::power() {
status.timer1 = 0;
status.timer2 = 0;
status.timer3 = 0;
status.timer4 = 0;
status.p15 = 0;
status.p14 = 0;
status.joyp = 0;
status.mlt_req = 0;
status.serial_data = 0;
status.serial_bits = 0;
status.serial_transfer = 0;
status.serial_clock = 0;
status.div = 0;
status.tima = 0;

View File

@ -23,6 +23,7 @@ struct CPU : Processor, MMIO {
unsigned timer1;
unsigned timer2;
unsigned timer3;
unsigned timer4;
//$ff00 JOYP
bool p15;
@ -30,6 +31,14 @@ struct CPU : Processor, MMIO {
uint8 joyp;
uint8 mlt_req;
//$ff01 SB
uint8 serial_data;
unsigned serial_bits;
//$ff02 SC
bool serial_transfer;
bool serial_clock;
//$ff04 DIV
uint8 div;

View File

@ -31,6 +31,15 @@ uint8 CPU::mmio_read(uint16 addr) {
| (status.joyp << 0);
}
if(addr == 0xff01) { //SB
return 0xff;
}
if(addr == 0xff02) { //SC
return (status.serial_transfer << 7)
| (status.serial_clock << 0);
}
if(addr == 0xff04) { //DIV
return status.div;
}
@ -81,10 +90,14 @@ void CPU::mmio_write(uint16 addr, uint8 data) {
}
if(addr == 0xff01) { //SB
status.serial_data = data;
return;
}
if(addr == 0xff02) { //SC
status.serial_transfer = data & 0x80;
status.serial_clock = data & 0x01;
if(status.serial_transfer) status.serial_bits = 8;
return;
}

View File

@ -27,12 +27,19 @@ void CPU::serialize(serializer &s) {
s.integer(status.timer1);
s.integer(status.timer2);
s.integer(status.timer3);
s.integer(status.timer4);
s.integer(status.p15);
s.integer(status.p14);
s.integer(status.joyp);
s.integer(status.mlt_req);
s.integer(status.serial_data);
s.integer(status.serial_bits);
s.integer(status.serial_transfer);
s.integer(status.serial_clock);
s.integer(status.div);
s.integer(status.tima);
s.integer(status.tma);

View File

@ -64,10 +64,22 @@ void CPU::timer_stage2() { // 16384hz
status.div++;
status.timer2 -= 4;
if(++status.timer3 >= 4) timer_stage3();
if(++status.timer3 >= 2) timer_stage3();
}
void CPU::timer_stage3() { // 4096hz
void CPU::timer_stage3() { // 8192hz
if(status.serial_transfer && status.serial_clock) {
if(--status.serial_bits == 0) {
status.serial_transfer = 0;
interrupt_raise(Interrupt::Serial);
}
}
status.timer3 -= 2;
if(++status.timer4 >= 2) timer_stage4();
}
void CPU::timer_stage4() { // 4096hz
if(status.timer_enable && status.timer_clock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
@ -75,7 +87,7 @@ void CPU::timer_stage3() { // 4096hz
}
}
status.timer3 -= 4;
status.timer4 -= 2;
}
#endif

View File

@ -3,6 +3,7 @@ void timer_stage0();
void timer_stage1();
void timer_stage2();
void timer_stage3();
void timer_stage4();
//opcode.cpp
void op_io();

View File

@ -5,7 +5,7 @@
namespace GameBoy {
namespace Info {
static const char Name[] = "bgameboy";
static const char Version[] = "000.12";
static const char Version[] = "000.13";
static unsigned SerializerVersion = 1;
}
}

View File

@ -19,7 +19,11 @@ void LCD::main() {
add_clocks(4);
if(status.lx == 320) {
if(status.lx == 0) {
if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
if(status.lx == 252) {
if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat);
}
}

View File

@ -17,9 +17,10 @@ uint8 LCD::mmio_read(uint16 addr) {
if(addr == 0xff41) { //STAT
unsigned mode;
if(status.ly >= 144) mode = 1; //Vblank
else if(status.lx >= 320) mode = 0; //Hblank
else mode = 3; //LCD transfer
if(status.ly >= 144) mode = 1; //Vblank
else if(status.lx < 80) mode = 2; //OAM
else if(status.lx < 252) mode = 3; //LCD
else mode = 0; //Hblank
return (status.interrupt_lyc << 6)
| (status.interrupt_oam << 5)

View File

@ -91,32 +91,27 @@ void CPU::op_irq(uint16 vector) {
}
void CPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
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, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &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, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
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, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
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::Linear, 0x00, 0x3f, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram }
);
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() {

View File

@ -1,5 +1,7 @@
class CPU : public Processor, public CPUcore, public PPUcounter {
public:
uint8 wram[128 * 1024];
enum : bool { Threaded = true };
array<Processor*> coprocessors;
alwaysinline void step(unsigned clocks);

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

@ -123,17 +123,20 @@ void PPU::frame() {
}
void PPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
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() == System::Region::NTSC ? 0 : 1); //0 = NTSC, 1 = PAL

View File

@ -1,5 +1,9 @@
class PPU : public Processor, public PPUcounter {
public:
uint8 vram[128 * 1024];
uint8 oam[544];
uint8 cgram[512];
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();

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

@ -67,7 +67,7 @@ void PPU::render_scanline() {
bg2.render();
bg3.render();
bg4.render();
oam.render();
sprite.render();
screen.render();
}
@ -75,11 +75,11 @@ 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;
@ -87,14 +87,17 @@ void PPU::frame() {
}
void PPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
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();
}
@ -117,10 +120,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;
}
}
@ -135,7 +138,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

@ -1,5 +1,9 @@
class PPU : public Processor, public PPUcounter {
public:
uint8 vram[64 * 1024];
uint8 oam[544];
uint8 cgram[512];
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
@ -39,7 +43,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

@ -125,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);
@ -142,7 +142,7 @@ 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);
@ -201,7 +201,7 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
} 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);
@ -219,7 +219,7 @@ 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);

View File

@ -1,144 +1,34 @@
#ifdef SA1_CPP
namespace memory {
StaticRAM iram(2048);
//accessed by:
CPUIRAM cpuiram; //S-CPU
SA1IRAM sa1iram; //SA-1
SA1BWRAM sa1bwram; //SA-1
CC1BWRAM cc1bwram; //S-CPU
BitmapRAM bitmapram; //SA-1
//ROM / RAM access from the S-CPU
unsigned SA1::CPUIRAM::size() const {
return sa1.iram.size();
}
//=======
//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 {
unsigned SA1::CPUBWRAM::size() const {
return cartridge.ram.size();
}
uint8 SA1BWRAM::read(unsigned addr) {
sa1.synchronize_cpu();
return cartridge.ram.read(addr);
}
void SA1BWRAM::write(unsigned addr, uint8 data) {
sa1.synchronize_cpu();
cartridge.ram.write(addr, data);
}
//========
//CC1BWRAM
//========
unsigned CC1BWRAM::size() const {
return cartridge.ram.size();
}
uint8 CC1BWRAM::read(unsigned addr) {
uint8 SA1::CPUBWRAM::read(unsigned addr) {
cpu.synchronize_coprocessor();
if(dma) return sa1.dma_cc1_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();
cartridge.ram.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) & (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 BitmapRAM::write(unsigned addr, uint8 data) {
sa1.synchronize_cpu();
if(sa1.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,40 +1,14 @@
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 CPUIRAM cpuiram;
extern SA1IRAM sa1iram;
extern SA1BWRAM sa1bwram;
extern CC1BWRAM cc1bwram;
extern BitmapRAM bitmapram;
};
} cpubwram;

View File

@ -28,7 +28,7 @@ void SA1::dma_normal() {
} break;
case DMA::SourceIRAM: {
data = memory::iram.read(dsa & 0x07ff);
data = iram.read(dsa & 0x07ff);
} break;
}
@ -40,7 +40,7 @@ void SA1::dma_normal() {
} 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;
@ -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

@ -18,19 +18,23 @@ uint8 SA1::bus_read(unsigned addr) {
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
return memory::iram.read(addr & 2047);
synchronize_cpu();
return iram.read(addr & 2047);
}
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
return memory::iram.read(addr & 2047);
synchronize_cpu();
return iram.read(addr & 2047);
}
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
return memory::sa1bwram.read(addr & (memory::sa1bwram.size() - 1));
synchronize_cpu();
return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
}
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
return memory::bitmapram.read(addr & (memory::bitmapram.size() - 1));
synchronize_cpu();
return bitmap_read(addr & 0x0fffff);
}
}
@ -44,19 +48,23 @@ void SA1::bus_write(unsigned addr, uint8 data) {
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
return memory::iram.write(addr & 2047, data);
synchronize_cpu();
return iram.write(addr & 2047, data);
}
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
return memory::iram.write(addr & 2047, data);
synchronize_cpu();
return iram.write(addr & 2047, data);
}
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
return memory::sa1bwram.write(addr & (memory::sa1bwram.size() - 1), data);
synchronize_cpu();
return cartridge.ram.write(addr & (cartridge.ram.size() - 1), data);
}
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
return memory::bitmapram.write(addr & (memory::bitmapram.size() - 1), data);
synchronize_cpu();
return bitmap_write(addr & 0x0fffff, data);
}
}
@ -64,7 +72,6 @@ void SA1::bus_write(unsigned addr, uint8 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.
//(* eg, cartridge.ram is used directly, as memory::sa1bwram syncs to the S-CPU)
uint8 SA1::vbr_read(unsigned addr) {
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
return mmc_read(addr);
@ -83,11 +90,11 @@ uint8 SA1::vbr_read(unsigned addr) {
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
return memory::iram.read(addr & 2047);
return iram.read(addr & 2047);
}
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
return memory::iram.read(addr & 0x2047);
return iram.read(addr & 0x2047);
}
}
@ -172,26 +179,26 @@ 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), memory::cc1bwram.size());
return memory::cc1bwram.read(addr);
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), memory::cc1bwram.size());
memory::cc1bwram.write(addr, data);
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), memory::sa1bwram.size());
return memory::sa1bwram.read(addr);
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), memory::bitmapram.size());
return memory::bitmapram.read(addr);
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
return bitmap_read(addr);
}
}
@ -199,13 +206,59 @@ 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), memory::sa1bwram.size());
memory::sa1bwram.write(addr, data);
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), memory::bitmapram.size());
memory::bitmapram.write(addr, data);
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

@ -14,3 +14,6 @@ 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

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

View File

@ -130,9 +130,9 @@ void SA1::power() {
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;
@ -321,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:
#include "bus/bus.hpp"
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"

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

@ -19,6 +19,7 @@
class SPC7110 {
public:
uint8 rtc[20];
unsigned data_rom_offset;
void init();
@ -134,7 +135,6 @@ private:
enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write };
enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c };
uint8 rtc[20];
unsigned rtc_state;
unsigned rtc_mode;
unsigned rtc_index;

View File

@ -1,5 +1,7 @@
class SRTC {
public:
uint8 rtc[20];
void init();
void enable();
void power();
@ -14,7 +16,6 @@ public:
private:
static const unsigned months[12];
enum RtcMode { RtcReady, RtcCommand, RtcRead, RtcWrite };
uint8 rtc[20];
unsigned rtc_mode;
signed rtc_index;

View File

@ -1,17 +1,12 @@
#ifdef SUPERFX_CPP
namespace memory {
SuperFXCPUROM fxrom;
SuperFXCPURAM fxram;
}
//ROM / RAM access from the S-CPU
unsigned SuperFXCPUROM::size() const {
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,
@ -22,20 +17,20 @@ uint8 SuperFXCPUROM::read(unsigned addr) {
return cartridge.rom.read(addr);
}
void SuperFXCPUROM::write(unsigned addr, uint8 data) {
void SuperFX::ROM::write(unsigned addr, uint8 data) {
cartridge.rom.write(addr, data);
}
unsigned SuperFXCPURAM::size() const {
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 cartridge.ram.read(addr);
}
void SuperFXCPURAM::write(unsigned addr, uint8 data) {
void SuperFX::RAM::write(unsigned addr, uint8 data) {
cartridge.ram.write(addr, data);
}

View File

@ -1,16 +1,11 @@
struct SuperFXCPUROM : Memory {
struct ROM : Memory {
unsigned size() const;
uint8 read(unsigned);
void write(unsigned, uint8);
};
} rom;
struct SuperFXCPURAM : Memory {
struct RAM : Memory {
unsigned size() const;
uint8 read(unsigned);
void write(unsigned, uint8);
};
namespace memory {
extern SuperFXCPUROM fxrom;
extern SuperFXCPURAM fxram;
}
} ram;

View File

@ -1,7 +1,6 @@
#include "bus/bus.hpp"
class SuperFX : public Coprocessor {
public:
#include "bus/bus.hpp"
#include "core/core.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"

View File

@ -99,37 +99,32 @@ void CPU::op_irq() {
}
void CPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
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, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &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, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
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, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
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::Linear, 0x00, 0x3f, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
bus.map(
Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram }
);
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, memory::wram) n = config.cpu.wram_init_value;
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:
uint8 wram[128 * 1024];
enum : bool { Threaded = true };
array<Processor*> coprocessors;
alwaysinline void step(unsigned clocks);

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 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;
}
@ -73,20 +73,20 @@ void Debugger::write(Debugger::MemorySource source, unsigned addr, uint8 data) {
} break;
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

@ -120,7 +120,7 @@ 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, { xmlrom });
SNES::system.power();
@ -132,9 +132,9 @@ 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, { xmlrom, xmlbsx });
SNES::system.power();
@ -146,9 +146,9 @@ 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, { xmlrom, xmlbsx });
SNES::system.power();
@ -161,11 +161,11 @@ 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, { xmlrom, xmlsta, xmlstb });
SNES::system.power();
@ -177,7 +177,7 @@ bool snes_load_cartridge_super_game_boy(
const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_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(dmg_data) {
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(dmg_data, dmg_size).xml;
@ -201,21 +201,23 @@ 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() != SNES::Cartridge::Mode::Bsx) break;
return SNES::memory::bsxram.data();
return SNES::bsxcartridge.sram.data();
case SNES_MEMORY_BSX_PRAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
return SNES::memory::bsxpram.data();
return SNES::bsxcartridge.psram.data();
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
return SNES::memory::stAram.data();
return SNES::sufamiturbo.slotA.ram.data();
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
return SNES::memory::stBram.data();
return SNES::sufamiturbo.slotB.ram.data();
case SNES_MEMORY_GAME_BOY_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
return GameBoy::cartridge.ramdata;
@ -224,15 +226,15 @@ uint8_t* snes_get_memory_data(unsigned id) {
// return GameBoy::cartridge.rtcdata;
case SNES_MEMORY_WRAM:
return SNES::memory::wram.data();
return SNES::cpu.wram;
case SNES_MEMORY_APURAM:
return SNES::memory::apuram.data();
return SNES::smp.apuram;
case SNES_MEMORY_VRAM:
return SNES::memory::vram.data();
return SNES::ppu.vram;
case SNES_MEMORY_OAM:
return SNES::memory::oam.data();
return SNES::ppu.oam;
case SNES_MEMORY_CGRAM:
return SNES::memory::cgram.data();
return SNES::ppu.cgram;
}
return 0;
@ -244,26 +246,26 @@ 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() != SNES::Cartridge::Mode::Bsx) break;
size = SNES::memory::bsxram.size();
size = SNES::bsxcartridge.sram.size();
break;
case SNES_MEMORY_BSX_PRAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
size = SNES::memory::bsxpram.size();
size = SNES::bsxcartridge.psram.size();
break;
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
size = SNES::memory::stAram.size();
size = SNES::sufamiturbo.slotA.ram.size();
break;
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
size = SNES::memory::stBram.size();
size = SNES::sufamiturbo.slotB.ram.size();
break;
case SNES_MEMORY_GAME_BOY_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
@ -275,19 +277,19 @@ unsigned snes_get_memory_size(unsigned id) {
// break;
case SNES_MEMORY_WRAM:
size = SNES::memory::wram.size();
size = 128 * 1024;
break;
case SNES_MEMORY_APURAM:
size = SNES::memory::apuram.size();
size = 64 * 1024;
break;
case SNES_MEMORY_VRAM:
size = SNES::memory::vram.size();
size = 64 * 1024;
break;
case SNES_MEMORY_OAM:
size = SNES::memory::oam.size();
size = 544;
break;
case SNES_MEMORY_CGRAM:
size = SNES::memory::cgram.size();
size = 512;
break;
}

View File

@ -5,16 +5,6 @@ namespace SNES {
Bus bus;
#include "serialization.cpp"
namespace memory {
StaticRAM wram(128 * 1024);
StaticRAM apuram(64 * 1024);
StaticRAM vram(64 * 1024);
StaticRAM oam(544);
StaticRAM cgram(512);
};
unsigned Bus::mirror(unsigned addr, unsigned size) {
unsigned base = 0;
if(size) {

View File

@ -67,17 +67,8 @@ struct Bus {
void map_reset();
void map_xml();
void serialize(serializer&);
Bus();
~Bus();
};
namespace memory {
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 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;
}
}

View File

@ -32,14 +32,14 @@ uint16 PPU::get_vram_address() {
uint8 PPU::vram_read(unsigned addr) {
if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) {
return memory::vram[addr];
return vram[addr];
}
return 0x00;
}
void PPU::vram_write(unsigned addr, uint8 data) {
if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) {
memory::vram[addr] = data;
vram[addr] = data;
}
}
@ -50,7 +50,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: {
@ -62,12 +62,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;
@ -78,7 +78,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: {
@ -88,7 +88,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: {
@ -98,7 +98,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: {
@ -108,7 +108,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: {
@ -117,7 +117,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: {
@ -127,7 +127,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;
@ -135,7 +135,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;
}
@ -143,29 +143,29 @@ void PPU::mmio_update_video_mode() {
//INIDISP
void PPU::mmio_w2100(uint8 data) {
if(regs.display_disable && vcounter() == (!regs.overscan ? 225 : 240)) oam.address_reset();
if(regs.display_disable && vcounter() == (!regs.overscan ? 225 : 240)) sprite.address_reset();
regs.display_disable = data & 0x80;
regs.display_brightness = data & 0x0f;
}
//OBSEL
void PPU::mmio_w2101(uint8 data) {
oam.regs.base_size = (data >> 5) & 7;
oam.regs.nameselect = (data >> 3) & 3;
oam.regs.tiledata_addr = (data & 3) << 14;
sprite.regs.base_size = (data >> 5) & 7;
sprite.regs.nameselect = (data >> 3) & 3;
sprite.regs.tiledata_addr = (data & 3) << 14;
}
//OAMADDL
void PPU::mmio_w2102(uint8 data) {
regs.oam_baseaddr = (regs.oam_baseaddr & 0x0200) | (data << 1);
oam.address_reset();
sprite.address_reset();
}
//OAMADDH
void PPU::mmio_w2103(uint8 data) {
regs.oam_priority = data & 0x80;
regs.oam_baseaddr = ((data & 0x01) << 9) | (regs.oam_baseaddr & 0x01fe);
oam.address_reset();
sprite.address_reset();
}
//OAMDATA
@ -177,12 +177,12 @@ void PPU::mmio_w2104(uint8 data) {
if(latch == 0) regs.oam_latchdata = data;
if(addr & 0x0200) {
oam.update(addr, data);
sprite.update(addr, data);
} else if(latch == 1) {
oam.update((addr & ~1) + 0, regs.oam_latchdata);
oam.update((addr & ~1) + 1, data);
sprite.update((addr & ~1) + 0, regs.oam_latchdata);
sprite.update((addr & ~1) + 1, data);
}
oam.set_first_sprite();
sprite.set_first_sprite();
}
//BGMODE
@ -399,8 +399,8 @@ void PPU::mmio_w2122(uint8 data) {
if(latch == 0) {
regs.cgram_latchdata = data;
} else {
memory::cgram[(addr & ~1) + 0] = regs.cgram_latchdata;
memory::cgram[(addr & ~1) + 1] = data & 0x7f;
cgram[(addr & ~1) + 0] = regs.cgram_latchdata;
cgram[(addr & ~1) + 1] = data & 0x7f;
}
}
@ -476,7 +476,7 @@ void PPU::mmio_w212b(uint8 data) {
//TM
void PPU::mmio_w212c(uint8 data) {
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;
@ -485,7 +485,7 @@ void PPU::mmio_w212c(uint8 data) {
//TS
void PPU::mmio_w212d(uint8 data) {
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;
@ -542,7 +542,7 @@ void PPU::mmio_w2133(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();
}
@ -580,8 +580,8 @@ uint8 PPU::mmio_r2138() {
if(regs.display_disable == false && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.oam_iaddr;
if(addr & 0x0200) addr &= 0x021f;
regs.ppu1_mdr = memory::oam[addr];
oam.set_first_sprite();
regs.ppu1_mdr = oam[addr];
sprite.set_first_sprite();
return regs.ppu1_mdr;
}
@ -621,10 +621,10 @@ uint8 PPU::mmio_r213b() {
) addr = regs.cgram_iaddr;
if(latch == 0) {
regs.ppu2_mdr = memory::cgram[addr];
regs.ppu2_mdr = cgram[addr];
} else {
regs.ppu2_mdr &= 0x80;
regs.ppu2_mdr |= memory::cgram[addr];
regs.ppu2_mdr |= cgram[addr];
}
return regs.ppu2_mdr;
}
@ -656,8 +656,8 @@ uint8 PPU::mmio_r213d() {
//STAT77
uint8 PPU::mmio_r213e() {
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 |= ppu1_version & 0x0f;
return regs.ppu1_mdr;
}

View File

@ -53,7 +53,7 @@ void PPU::enter() {
bg3.run(0);
bg4.run(0);
if(pixel >= 0) {
oam.run();
sprite.run();
window.run();
screen.run();
}
@ -61,7 +61,7 @@ void PPU::enter() {
}
add_clocks(22);
oam.tilefetch();
sprite.tilefetch();
} else {
add_clocks(1052 + 22 + 136);
}
@ -80,17 +80,20 @@ void PPU::add_clocks(unsigned clocks) {
}
void PPU::enable() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
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;
memset(memory::vram.data(), 0x00, memory::vram.size());
memset(memory::oam.data(), 0x00, memory::oam.size());
memset(memory::cgram.data(), 0x00, memory::cgram.size());
foreach(n, vram) n = 0x00;
foreach(n, oam) n = 0x00;
foreach(n, cgram) n = 0x00;
reset();
}
@ -105,7 +108,7 @@ void PPU::reset() {
bg2.reset();
bg3.reset();
bg4.reset();
oam.reset();
sprite.reset();
window.reset();
screen.reset();
@ -125,14 +128,14 @@ void PPU::scanline() {
bg2.scanline();
bg3.scanline();
bg4.scanline();
oam.scanline();
sprite.scanline();
window.scanline();
screen.scanline();
}
void PPU::frame() {
system.frame();
oam.frame();
sprite.frame();
display.interlace = regs.interlace;
display.overscan = regs.overscan;
@ -143,7 +146,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),
window(*this),
screen(*this) {
surface = new uint16[512 * 512];

View File

@ -1,5 +1,9 @@
class PPU : public Processor, public PPUcounter {
public:
uint8 vram[64 * 1024];
uint8 oam[544];
uint8 cgram[512];
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
@ -40,7 +44,7 @@ private:
Background bg2;
Background bg3;
Background bg4;
Sprite oam;
Sprite sprite;
Window window;
Screen screen;

View File

@ -55,9 +55,9 @@ uint16 PPU::Screen::get_pixel(bool swap) {
color_main = get_color(self.bg4.output.main.palette);
source_main = BG4;
}
if(self.oam.output.main.priority > priority_main) {
priority_main = self.oam.output.main.priority;
color_main = get_color(self.oam.output.main.palette);
if(self.sprite.output.main.priority > priority_main) {
priority_main = self.sprite.output.main.priority;
color_main = get_color(self.sprite.output.main.palette);
source_main = OAM;
}
if(priority_main == 0) {
@ -97,9 +97,9 @@ uint16 PPU::Screen::get_pixel(bool swap) {
color_sub = get_color(self.bg4.output.sub.palette);
source_sub = BG4;
}
if(self.oam.output.sub.priority > priority_sub) {
priority_sub = self.oam.output.sub.priority;
color_sub = get_color(self.oam.output.sub.palette);
if(self.sprite.output.sub.priority > priority_sub) {
priority_sub = self.sprite.output.sub.priority;
color_sub = get_color(self.sprite.output.sub.palette);
source_sub = OAM;
}
if(priority_sub == 0) {
@ -130,7 +130,7 @@ uint16 PPU::Screen::get_pixel(bool swap) {
color_main = 0x0000;
}
bool color_exempt = (source_main == OAM && self.oam.output.main.palette < 192);
bool color_exempt = (source_main == OAM && self.sprite.output.main.palette < 192);
if(!color_exempt && color_enable[source_main] && self.window.output.sub.color_enable) {
bool halve = false;
if(regs.color_halve && self.window.output.main.color_enable) {
@ -173,7 +173,7 @@ uint16 PPU::Screen::addsub(unsigned x, unsigned y, bool halve) {
uint16 PPU::Screen::get_color(unsigned palette) {
palette <<= 1;
self.regs.cgram_iaddr = palette;
return memory::cgram[palette + 0] + (memory::cgram[palette + 1] << 8);
return ppu.cgram[palette + 0] + (ppu.cgram[palette + 1] << 8);
}
uint16 PPU::Screen::get_direct_color(unsigned palette, unsigned tile) {

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);
@ -81,7 +85,7 @@ void PPU::serialize(serializer &s) {
bg2.serialize(s);
bg3.serialize(s);
bg4.serialize(s);
oam.serialize(s);
sprite.serialize(s);
window.serialize(s);
screen.serialize(s);
}

View File

@ -1,7 +1,7 @@
#ifdef PPU_CPP
void PPU::Sprite::update(unsigned addr, uint8 data) {
memory::oam[addr] = data;
ppu.oam[addr] = data;
if(addr < 0x0200) {
unsigned n = addr >> 2;
@ -35,21 +35,21 @@ void PPU::Sprite::update(unsigned addr, uint8 data) {
unsigned PPU::Sprite::SpriteItem::width() const {
if(size == 0) {
static unsigned width[] = { 8, 8, 8, 16, 16, 32, 16, 16 };
return width[ppu.oam.regs.base_size];
return width[ppu.sprite.regs.base_size];
} else {
static unsigned width[] = { 16, 32, 64, 32, 64, 64, 32, 32 };
return width[ppu.oam.regs.base_size];
return width[ppu.sprite.regs.base_size];
}
}
unsigned PPU::Sprite::SpriteItem::height() const {
if(size == 0) {
if(ppu.oam.regs.interlace && ppu.oam.regs.base_size >= 6) return 16;
if(ppu.sprite.regs.interlace && ppu.sprite.regs.base_size >= 6) return 16;
static unsigned height[] = { 8, 8, 8, 16, 16, 32, 32, 32 };
return height[ppu.oam.regs.base_size];
return height[ppu.sprite.regs.base_size];
} else {
static unsigned height[] = { 16, 32, 64, 32, 64, 64, 64, 32 };
return height[ppu.oam.regs.base_size];
return height[ppu.sprite.regs.base_size];
}
}

View File

@ -144,12 +144,12 @@ void PPU::Sprite::tilefetch() {
unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);
uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);
oam_tile[n].d0 = memory::vram[addr + 0];
oam_tile[n].d1 = memory::vram[addr + 1];
oam_tile[n].d0 = ppu.vram[addr + 0];
oam_tile[n].d1 = ppu.vram[addr + 1];
self.add_clocks(2);
oam_tile[n].d2 = memory::vram[addr + 16];
oam_tile[n].d3 = memory::vram[addr + 17];
oam_tile[n].d2 = ppu.vram[addr + 16];
oam_tile[n].d3 = ppu.vram[addr + 17];
self.add_clocks(2);
}
}

View File

@ -52,8 +52,8 @@ void PPU::Window::run() {
regs.oam_two_enable, regs.oam_two_invert,
regs.oam_mask, regs.oam_main_enable, regs.oam_sub_enable
);
if(main) self.oam.output.main.priority = 0;
if(sub) self.oam.output.sub.priority = 0;
if(main) self.sprite.output.main.priority = 0;
if(sub) self.sprite.output.sub.priority = 0;
test(
main, sub,

View File

@ -2,7 +2,7 @@
uint8 SMPcore::disassemble_read(uint16 addr) {
if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f];
return memory::apuram[addr];
return smp.apuram[addr];
}
uint16 SMPcore::relb(int8 offset, int op_len) {

View File

@ -3,20 +3,20 @@
alwaysinline uint8 SMP::ram_read(uint16 addr) {
if(addr >= 0xffc0 && status.iplrom_enabled) return iplrom[addr & 0x3f];
if(status.ram_disabled) return 0x5a; //0xff on mini-SNES
return memory::apuram[addr];
return apuram[addr];
}
alwaysinline void SMP::ram_write(uint16 addr, uint8 data) {
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
if(status.ram_writable && !status.ram_disabled) memory::apuram[addr] = data;
if(status.ram_writable && !status.ram_disabled) apuram[addr] = data;
}
uint8 SMP::port_read(uint2 port) const {
return memory::apuram[0xf4 + port];
return apuram[0xf4 + port];
}
void SMP::port_write(uint2 port, uint8 data) {
memory::apuram[0xf4 + port] = data;
apuram[0xf4 + port] = data;
}
alwaysinline uint8 SMP::op_busread(uint16 addr) {

View File

@ -4,6 +4,8 @@ void SMP::serialize(serializer &s) {
Processor::serialize(s);
SMPcore::core_serialize(s);
s.array(apuram);
s.integer(status.clock_counter);
s.integer(status.dsp_counter);
s.integer(status.timer_step);

View File

@ -71,9 +71,7 @@ void SMP::reset() {
regs.sp = 0xef;
regs.p = 0x02;
for(unsigned i = 0; i < memory::apuram.size(); i++) {
memory::apuram.write(i, 0x00);
}
foreach(n, apuram) n = 0x00;
status.clock_counter = 0;
status.dsp_counter = 0;

View File

@ -1,5 +1,8 @@
class SMP : public Processor, public SMPcore {
public:
static const uint8 iplrom[64];
uint8 apuram[64 * 1024];
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
@ -16,8 +19,6 @@ public:
SMP();
~SMP();
static const uint8 iplrom[64];
private:
#include "memory/memory.hpp"
#include "timing/timing.hpp"

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "074.10";
static const char Version[] = "074.11";
static const unsigned SerializerVersion = 17;
}
}

View File

@ -49,7 +49,6 @@ void System::serialize(serializer &s) {
}
void System::serialize_all(serializer &s) {
bus.serialize(s);
cartridge.serialize(s);
system.serialize(s);
cpu.serialize(s);

View File

@ -1,12 +1,12 @@
Configuration config;
void Configuration::load() {
configuration::load(string(path.user, "bsnes-phoenix.cfg"));
configuration::load(string(path.user, "bsnes.cfg"));
}
void Configuration::save() {
mkdir(path.user, 0755);
configuration::save(string(path.user, "bsnes-phoenix.cfg"));
configuration::save(string(path.user, "bsnes.cfg"));
}
void Configuration::create() {

View File

@ -146,7 +146,7 @@ int main(int argc, char **argv) {
}
void Application::loadGeometry() {
geometryConfig.load(string(config.path.user, "bsnes-phoenix-geometry.cfg"));
geometryConfig.load(string(config.path.user, "bsnes-geometry.cfg"));
foreach(window, windows) {
lstring position;
position.split(",", window->position);
@ -160,5 +160,5 @@ void Application::saveGeometry() {
Geometry geom = window->geometry();
window->position = { geom.x, ",", geom.y };
}
geometryConfig.save(string(config.path.user, "bsnes-phoenix-geometry.cfg"));
geometryConfig.save(string(config.path.user, "bsnes-geometry.cfg"));
}