From 7403e69307399662869dc55842dbf14f526f7a18 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 9 Apr 2016 15:20:41 +1000 Subject: [PATCH] Update to v098r02 release. byuu says: Changelog: - SFC: fixed a regression on auto joypad polling due to missing parentheses - SFC: exported new PPU::vdisp() const -> uint; function [1] - SFC: merged PPU MMIO functions into the read/write handles (as I previously did for the CPU) - higan: removed individual emulator core names (bnes, bsnes, bgb, bgba, bws) [2] Forgot: - to remove /tomoko from the about dialog [1] note that technically I was relying on the cached, per-frame overscan setting when the CPU and light guns were polling the number of active display scanlines per frame. This was technically incorrect as you can change this value mid-frame and it'll kick in. I've never seen any game toggle overscan every frame, we only know about this because anomie tested this a long time ago. So, nothing should break, but ... you know how the SNES is. You can't even look at the code without something breaking, so I figured I'd mention it >_> [2] I'll probably keep referring to the SNES core as bsnes anyway. I don't mind if you guys use the b names as shorthand. The simplification is mostly to make the branding easier. --- higan/emulator/emulator.hpp | 2 +- higan/fc/fc.hpp | 11 +- higan/gb/gb.hpp | 11 +- higan/gba/gba.hpp | 11 +- higan/sfc/controller/justifier/justifier.cpp | 2 +- .../sfc/controller/superscope/superscope.cpp | 4 +- higan/sfc/cpu/cpu.hpp | 2 +- higan/sfc/cpu/irq.cpp | 4 +- higan/sfc/cpu/joypad.cpp | 2 +- higan/sfc/cpu/mmio.cpp | 4 +- higan/sfc/cpu/timing.cpp | 2 +- higan/sfc/ppu/memory.cpp | 49 + higan/sfc/ppu/mmio.cpp | 721 ++++++++++++++ higan/sfc/ppu/mmio/mmio.cpp | 883 ------------------ higan/sfc/ppu/mmio/mmio.hpp | 165 ---- higan/sfc/ppu/ppu.cpp | 104 ++- higan/sfc/ppu/ppu.hpp | 122 ++- higan/sfc/ppu/sprite/sprite.cpp | 10 +- higan/sfc/sfc.hpp | 11 +- higan/ws/ws.hpp | 11 +- 20 files changed, 1004 insertions(+), 1127 deletions(-) create mode 100644 higan/sfc/ppu/memory.cpp create mode 100644 higan/sfc/ppu/mmio.cpp delete mode 100644 higan/sfc/ppu/mmio/mmio.cpp delete mode 100644 higan/sfc/ppu/mmio/mmio.hpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 075468e6..2c3006f2 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -7,7 +7,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "098.01"; + static const string Version = "098.02"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp index 65365aee..b178c4bb 100644 --- a/higan/fc/fc.hpp +++ b/higan/fc/fc.hpp @@ -1,22 +1,17 @@ #pragma once +//license: GPLv3 +//started: 2011-09-05 + #include #include namespace Famicom { namespace Info { - static const string Name = "bnes"; static const uint SerializerVersion = 2; } } -/* - bnes - Famicom emulator - authors: byuu, Ryphecha - license: GPLv3 - project started: 2011-09-05 -*/ - #include namespace Famicom { diff --git a/higan/gb/gb.hpp b/higan/gb/gb.hpp index aa23e8e7..a4218891 100644 --- a/higan/gb/gb.hpp +++ b/higan/gb/gb.hpp @@ -1,22 +1,17 @@ #pragma once +//license: GPLv3 +//started: 2010-12-27 + #include #include namespace GameBoy { namespace Info { - static const string Name = "bgb"; static const uint SerializerVersion = 4; } } -/* - bgb - Game Boy, Super Game Boy, and Game Boy Color emulator - author: byuu - license: GPLv3 - project started: 2010-12-27 -*/ - #include namespace GameBoy { diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp index f67b82ae..673c7911 100644 --- a/higan/gba/gba.hpp +++ b/higan/gba/gba.hpp @@ -1,22 +1,17 @@ #pragma once +//license: GPLv3 +//started: 2012-03-19 + #include #include namespace GameBoyAdvance { namespace Info { - static const string Name = "bgba"; static const uint SerializerVersion = 3; } } -/* - bgba - Game Boy Advance emulator - authors: byuu, Cydrak - license: GPLv3 - project started: 2012-03-19 -*/ - #include namespace GameBoyAdvance { diff --git a/higan/sfc/controller/justifier/justifier.cpp b/higan/sfc/controller/justifier/justifier.cpp index 8530a185..df499da7 100644 --- a/higan/sfc/controller/justifier/justifier.cpp +++ b/higan/sfc/controller/justifier/justifier.cpp @@ -32,7 +32,7 @@ auto Justifier::main() -> void { unsigned next = cpu.vcounter() * 1364 + cpu.hcounter(); signed x = (active == 0 ? player1.x : player2.x), y = (active == 0 ? player1.y : player2.y); - bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); + bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= ppu.vdisp()); if(offscreen == false) { unsigned target = y * 1364 + (x + 24) * 4; diff --git a/higan/sfc/controller/superscope/superscope.cpp b/higan/sfc/controller/superscope/superscope.cpp index e12169ba..575c3884 100644 --- a/higan/sfc/controller/superscope/superscope.cpp +++ b/higan/sfc/controller/superscope/superscope.cpp @@ -52,7 +52,7 @@ auto SuperScope::main() -> void { ny += y; x = max(-16, min(256 + 16, nx)); y = max(-16, min(240 + 16, ny)); - offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); + offscreen = (x < 0 || y < 0 || x >= 256 || y >= ppu.vdisp()); } prev = next; @@ -96,7 +96,7 @@ auto SuperScope::data() -> uint2 { pauselock = false; } - offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); + offscreen = (x < 0 || y < 0 || x >= 256 || y >= ppu.vdisp()); } switch(counter++) { diff --git a/higan/sfc/cpu/cpu.hpp b/higan/sfc/cpu/cpu.hpp index d8e8abcd..236750b5 100644 --- a/higan/sfc/cpu/cpu.hpp +++ b/higan/sfc/cpu/cpu.hpp @@ -1,4 +1,4 @@ -struct CPU : Processor::R65816, Thread, public PPUcounter { +struct CPU : Processor::R65816, Thread, PPUcounter { auto interruptPending() const -> bool override; auto pio() const -> uint8; auto joylatch() const -> bool; diff --git a/higan/sfc/cpu/irq.cpp b/higan/sfc/cpu/irq.cpp index b7e81973..a80965ec 100644 --- a/higan/sfc/cpu/irq.cpp +++ b/higan/sfc/cpu/irq.cpp @@ -11,7 +11,7 @@ auto CPU::pollInterrupts() -> void { } //NMI test - bool nmi_valid = (vcounter(2) >= (!ppu.overscan() ? 225 : 240)); + bool nmi_valid = vcounter(2) >= ppu.vdisp(); if(!status.nmi_valid && nmi_valid) { //0->1 edge sensitive transition status.nmi_line = true; @@ -29,7 +29,7 @@ auto CPU::pollInterrupts() -> void { } //IRQ test - bool irq_valid = (status.virq_enabled || status.hirq_enabled); + bool irq_valid = status.virq_enabled || status.hirq_enabled; if(irq_valid) { if((status.virq_enabled && vcounter(10) != (status.virq_pos)) || (status.hirq_enabled && hcounter(10) != (status.hirq_pos + 1) * 4) diff --git a/higan/sfc/cpu/joypad.cpp b/higan/sfc/cpu/joypad.cpp index 0d257b03..e60402d3 100644 --- a/higan/sfc/cpu/joypad.cpp +++ b/higan/sfc/cpu/joypad.cpp @@ -1,6 +1,6 @@ //called every 256 clocks; see CPU::addClocks() auto CPU::stepAutoJoypadPoll() -> void { - if(vcounter() >= !ppu.overscan() ? 225 : 240) { + if(vcounter() >= ppu.vdisp()) { //cache enable state at first iteration if(status.auto_joypad_counter == 0) status.auto_joypad_latch = status.auto_joypad_poll; status.auto_joypad_active = status.auto_joypad_counter <= 15; diff --git a/higan/sfc/cpu/mmio.cpp b/higan/sfc/cpu/mmio.cpp index e3e068f4..08228b4d 100644 --- a/higan/sfc/cpu/mmio.cpp +++ b/higan/sfc/cpu/mmio.cpp @@ -59,7 +59,7 @@ auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 { uint8 r = (regs.mdr & 0x3e); if(status.auto_joypad_active) r |= 0x01; if(hcounter() <= 2 || hcounter() >= 1096) r |= 0x40; //hblank - if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) r |= 0x80; //vblank + if(vcounter() >= ppu.vdisp()) r |= 0x80; //vblank return r; } @@ -195,7 +195,7 @@ auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void { //WRIO if(addr == 0x4201) { - if(status.pio.bit(7) && !data.bit(7)) ppu.latch_counters(); + if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters(); status.pio = data; } diff --git a/higan/sfc/cpu/timing.cpp b/higan/sfc/cpu/timing.cpp index 4ceeecab..f56f680f 100644 --- a/higan/sfc/cpu/timing.cpp +++ b/higan/sfc/cpu/timing.cpp @@ -53,7 +53,7 @@ auto CPU::scanline() -> void { status.dram_refreshed = false; //HDMA triggers once every visible scanline - if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) { + if(vcounter() < ppu.vdisp()) { status.hdma_position = 1104; status.hdma_triggered = false; } diff --git a/higan/sfc/ppu/memory.cpp b/higan/sfc/ppu/memory.cpp new file mode 100644 index 00000000..4aba04f6 --- /dev/null +++ b/higan/sfc/ppu/memory.cpp @@ -0,0 +1,49 @@ +auto PPU::getVramAddress() -> uint16 { + uint16 addr = regs.vram_addr; + switch(regs.vram_mapping) { + case 0: break; //direct mapping + case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break; + case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break; + case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break; + } + return (addr << 1); +} + +auto PPU::vramRead(uint addr) -> uint8 { + uint8 data = 0x00; + if(regs.display_disable || vcounter() >= vdisp()) { + data = vram[addr]; + debugger.vram_read(addr, data); + } + return data; +} + +auto PPU::vramWrite(uint addr, uint8 data) -> void { + if(regs.display_disable || vcounter() >= vdisp()) { + vram[addr] = data; + debugger.vram_write(addr, data); + } +} + +auto PPU::oamRead(uint addr) -> uint8 { + uint8 data = oam[addr]; + debugger.oam_read(addr, data); + return data; +} + +auto PPU::oamWrite(uint addr, uint8 data) -> void { + oam[addr] = data; + sprite.update(addr, data); + debugger.oam_write(addr, data); +} + +auto PPU::cgramRead(uint addr) -> uint8 { + uint8 data = cgram[addr]; + debugger.cgram_read(addr, data); + return data; +} + +auto PPU::cgramWrite(uint addr, uint8 data) -> void { + cgram[addr] = data; + debugger.cgram_write(addr, data); +} diff --git a/higan/sfc/ppu/mmio.cpp b/higan/sfc/ppu/mmio.cpp new file mode 100644 index 00000000..d21764a8 --- /dev/null +++ b/higan/sfc/ppu/mmio.cpp @@ -0,0 +1,721 @@ +auto PPU::read(uint24 addr, uint8 data) -> uint8 { + cpu.synchronizePPU(); + + switch(addr & 0xffff) { + + case 0x2104: case 0x2105: case 0x2106: case 0x2108: + case 0x2109: case 0x210a: case 0x2114: case 0x2115: + case 0x2116: case 0x2118: case 0x2119: case 0x211a: + case 0x2124: case 0x2125: case 0x2126: case 0x2128: + case 0x2129: case 0x212a: { + return regs.ppu1_mdr; + } + + //MPYL + case 0x2134: { + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = (result >> 0); + return regs.ppu1_mdr; + } + + //MPYM + case 0x2135: { + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = (result >> 8); + return regs.ppu1_mdr; + } + + //MPYH + case 0x2136: { + unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); + regs.ppu1_mdr = (result >> 16); + return regs.ppu1_mdr; + } + + //SLHV + case 0x2137: { + if(cpu.pio() & 0x80) latchCounters(); + return cpu.regs.mdr; + } + + //OAMDATAREAD + case 0x2138: { + uint10 addr = regs.oam_addr++; + if(!regs.display_disable && vcounter() < vdisp()) addr = regs.oam_iaddr; + if(addr & 0x0200) addr &= 0x021f; + + regs.ppu1_mdr = oamRead(addr); + sprite.set_first_sprite(); + return regs.ppu1_mdr; + } + + //VMDATALREAD + case 0x2139: { + uint16 addr = getVramAddress() + 0; + regs.ppu1_mdr = regs.vram_readbuffer >> 0; + if(regs.vram_incmode == 0) { + addr &= ~1; + regs.vram_readbuffer = vramRead(addr + 0) << 0; + regs.vram_readbuffer |= vramRead(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; + } + + //VMDATAHREAD + case 0x213a: { + uint16 addr = getVramAddress() + 1; + regs.ppu1_mdr = regs.vram_readbuffer >> 8; + if(regs.vram_incmode == 1) { + addr &= ~1; + regs.vram_readbuffer = vramRead(addr + 0) << 0; + regs.vram_readbuffer |= vramRead(addr + 1) << 8; + regs.vram_addr += regs.vram_incsize; + } + return regs.ppu1_mdr; + } + + //CGDATAREAD + case 0x213b: { + bool latch = regs.cgram_addr & 1; + uint9 addr = regs.cgram_addr++; + if(!regs.display_disable + && vcounter() > 0 && vcounter() < vdisp() + && hcounter() >= 88 && hcounter() < 1096 + ) addr = regs.cgram_iaddr; + + if(latch == 0) { + regs.ppu2_mdr = cgramRead(addr); + } else { + regs.ppu2_mdr &= 0x80; + regs.ppu2_mdr |= cgramRead(addr); + } + return regs.ppu2_mdr; + } + + //OPHCT + case 0x213c: { + if(regs.latch_hcounter == 0) { + regs.ppu2_mdr = (regs.hcounter >> 0); + } else { + regs.ppu2_mdr &= 0xfe; + regs.ppu2_mdr |= (regs.hcounter >> 8) & 1; + } + regs.latch_hcounter ^= 1; + return regs.ppu2_mdr; + } + + //OPVCT + case 0x213d: { + if(regs.latch_vcounter == 0) { + regs.ppu2_mdr = (regs.vcounter >> 0); + } else { + regs.ppu2_mdr &= 0xfe; + regs.ppu2_mdr |= (regs.vcounter >> 8) & 1; + } + regs.latch_vcounter ^= 1; + return regs.ppu2_mdr; + } + + //STAT77 + case 0x213e: { + regs.ppu1_mdr &= 0x10; + 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; + } + + //STAT78 + case 0x213f: { + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + regs.ppu2_mdr &= 0x20; + regs.ppu2_mdr |= field() << 7; + if((cpu.pio() & 0x80) == 0) { + regs.ppu2_mdr |= 0x40; + } else if(regs.counters_latched) { + regs.ppu2_mdr |= 0x40; + regs.counters_latched = false; + } + regs.ppu2_mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4; + regs.ppu2_mdr |= ppu2_version & 0x0f; + return regs.ppu2_mdr; + } + + } + + return data; +} + +auto PPU::write(uint24 addr, uint8 data) -> void { + cpu.synchronizePPU(); + + switch(addr & 0xffff) { + + //INIDISP + case 0x2100: { + if(regs.display_disable && vcounter() == vdisp()) sprite.address_reset(); + regs.display_disable = data & 0x80; + regs.display_brightness = data & 0x0f; + return; + } + + //OBSEL + case 0x2101: { + sprite.regs.base_size = (data >> 5) & 7; + sprite.regs.nameselect = (data >> 3) & 3; + sprite.regs.tiledata_addr = (data & 3) << 14; + return; + } + + //OAMADDL + case 0x2102: { + regs.oam_baseaddr = (regs.oam_baseaddr & 0x0200) | (data << 1); + sprite.address_reset(); + return; + } + + //OAMADDH + case 0x2103: { + regs.oam_priority = data & 0x80; + regs.oam_baseaddr = ((data & 0x01) << 9) | (regs.oam_baseaddr & 0x01fe); + sprite.address_reset(); + return; + } + + //OAMDATA + case 0x2104: { + bool latch = regs.oam_addr & 1; + uint10 addr = regs.oam_addr++; + if(!regs.display_disable && vcounter() < vdisp()) addr = regs.oam_iaddr; + if(addr & 0x0200) addr &= 0x021f; + + if(latch == 0) regs.oam_latchdata = data; + if(addr & 0x0200) { + oamWrite(addr, data); + } else if(latch == 1) { + oamWrite((addr & ~1) + 0, regs.oam_latchdata); + oamWrite((addr & ~1) + 1, data); + } + sprite.set_first_sprite(); + return; + } + + //BGMODE + case 0x2105: { + bg4.regs.tile_size = (data & 0x80); + bg3.regs.tile_size = (data & 0x40); + bg2.regs.tile_size = (data & 0x20); + bg1.regs.tile_size = (data & 0x10); + regs.bg3_priority = (data & 0x08); + regs.bgmode = (data & 0x07); + updateVideoMode(); + return; + } + + //MOSAIC + case 0x2106: { + unsigned mosaic_size = (data >> 4) & 15; + bg4.regs.mosaic = (data & 0x08 ? mosaic_size : 0); + bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); + bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); + bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); + return; + } + + //BG1SC + case 0x2107: { + bg1.regs.screen_addr = (data & 0x7c) << 9; + bg1.regs.screen_size = data & 3; + return; + } + + //BG2SC + case 0x2108: { + bg2.regs.screen_addr = (data & 0x7c) << 9; + bg2.regs.screen_size = data & 3; + return; + } + + //BG3SC + case 0x2109: { + bg3.regs.screen_addr = (data & 0x7c) << 9; + bg3.regs.screen_size = data & 3; + return; + } + + //BG4SC + case 0x210a: { + bg4.regs.screen_addr = (data & 0x7c) << 9; + bg4.regs.screen_size = data & 3; + return; + } + + //BG12NBA + case 0x210b: { + bg1.regs.tiledata_addr = (data & 0x07) << 13; + bg2.regs.tiledata_addr = (data & 0x70) << 9; + return; + } + + //BG34NBA + case 0x210c: { + bg3.regs.tiledata_addr = (data & 0x07) << 13; + bg4.regs.tiledata_addr = (data & 0x70) << 9; + return; + } + + //BG1HOFS + case 0x210d: { + regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + + bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + //BG1VOFS + case 0x210e: { + regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + + bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + //BG2HOFS + case 0x210f: { + bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + //BG2VOFS + case 0x2110: { + bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + //BG3HOFS + case 0x2111: { + bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + //BG3VOFS + case 0x2112: { + bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + //BG4HOFS + case 0x2113: { + bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7); + regs.bgofs_latchdata = data; + return; + } + + //BG4VOFS + case 0x2114: { + bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata; + regs.bgofs_latchdata = data; + return; + } + + //VMAIN + case 0x2115: { + regs.vram_incmode = data & 0x80; + regs.vram_mapping = (data >> 2) & 3; + switch(data & 3) { + case 0: regs.vram_incsize = 1; break; + case 1: regs.vram_incsize = 32; break; + case 2: regs.vram_incsize = 128; break; + case 3: regs.vram_incsize = 128; break; + } + return; + } + + //VMADDL + case 0x2116: { + regs.vram_addr &= 0xff00; + regs.vram_addr |= (data << 0); + uint16 addr = getVramAddress(); + regs.vram_readbuffer = vramRead(addr + 0) << 0; + regs.vram_readbuffer |= vramRead(addr + 1) << 8; + return; + } + + //VMADDH + case 0x2117: { + regs.vram_addr &= 0x00ff; + regs.vram_addr |= (data << 8); + uint16 addr = getVramAddress(); + regs.vram_readbuffer = vramRead(addr + 0) << 0; + regs.vram_readbuffer |= vramRead(addr + 1) << 8; + return; + } + + //VMDATAL + case 0x2118: { + uint16 addr = getVramAddress() + 0; + vramWrite(addr, data); + if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize; + return; + } + + //VMDATAH + case 0x2119: { + uint16 addr = getVramAddress() + 1; + vramWrite(addr, data); + if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize; + return; + } + + //M7SEL + case 0x211a: { + regs.mode7_repeat = (data >> 6) & 3; + regs.mode7_vflip = data & 0x02; + regs.mode7_hflip = data & 0x01; + return; + } + + //M7A + case 0x211b: { + regs.m7a = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + //M7B + case 0x211c: { + regs.m7b = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + //M7C + case 0x211d: { + regs.m7c = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + //M7D + case 0x211e: { + regs.m7d = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + //M7X + case 0x211f: { + regs.m7x = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + //M7Y + case 0x2120: { + regs.m7y = (data << 8) | regs.mode7_latchdata; + regs.mode7_latchdata = data; + return; + } + + //CGADD + case 0x2121: { + regs.cgram_addr = data << 1; + return; + } + + //CGDATA + case 0x2122: { + bool latch = regs.cgram_addr & 1; + uint9 addr = regs.cgram_addr++; + if(!regs.display_disable + && vcounter() > 0 && vcounter() < vdisp() + && hcounter() >= 88 && hcounter() < 1096 + ) addr = regs.cgram_iaddr; + + if(latch == 0) { + regs.cgram_latchdata = data; + } else { + cgramWrite((addr & ~1) + 0, regs.cgram_latchdata); + cgramWrite((addr & ~1) + 1, data & 0x7f); + } + return; + } + + //W12SEL + case 0x2123: { + window.regs.bg2_two_enable = data & 0x80; + window.regs.bg2_two_invert = data & 0x40; + window.regs.bg2_one_enable = data & 0x20; + window.regs.bg2_one_invert = data & 0x10; + window.regs.bg1_two_enable = data & 0x08; + window.regs.bg1_two_invert = data & 0x04; + window.regs.bg1_one_enable = data & 0x02; + window.regs.bg1_one_invert = data & 0x01; + return; + } + + //W34SEL + case 0x2124: { + window.regs.bg4_two_enable = data & 0x80; + window.regs.bg4_two_invert = data & 0x40; + window.regs.bg4_one_enable = data & 0x20; + window.regs.bg4_one_invert = data & 0x10; + window.regs.bg3_two_enable = data & 0x08; + window.regs.bg3_two_invert = data & 0x04; + window.regs.bg3_one_enable = data & 0x02; + window.regs.bg3_one_invert = data & 0x01; + return; + } + + //WOBJSEL + case 0x2125: { + window.regs.col_two_enable = data & 0x80; + window.regs.col_two_invert = data & 0x40; + window.regs.col_one_enable = data & 0x20; + window.regs.col_one_invert = data & 0x10; + window.regs.oam_two_enable = data & 0x08; + window.regs.oam_two_invert = data & 0x04; + window.regs.oam_one_enable = data & 0x02; + window.regs.oam_one_invert = data & 0x01; + return; + } + + //WH0 + case 0x2126: { + window.regs.one_left = data; + return; + } + + //WH1 + case 0x2127: { + window.regs.one_right = data; + return; + } + + //WH2 + case 0x2128: { + window.regs.two_left = data; + return; + } + + //WH3 + case 0x2129: { + window.regs.two_right = data; + return; + } + + //WBGLOG + case 0x212a: { + window.regs.bg4_mask = (data >> 6) & 3; + window.regs.bg3_mask = (data >> 4) & 3; + window.regs.bg2_mask = (data >> 2) & 3; + window.regs.bg1_mask = (data >> 0) & 3; + return; + } + + //WOBJLOG + case 0x212b: { + window.regs.col_mask = (data >> 2) & 3; + window.regs.oam_mask = (data >> 0) & 3; + return; + } + + //TM + case 0x212c: { + sprite.regs.main_enable = data & 0x10; + bg4.regs.main_enable = data & 0x08; + bg3.regs.main_enable = data & 0x04; + bg2.regs.main_enable = data & 0x02; + bg1.regs.main_enable = data & 0x01; + return; + } + + //TS + case 0x212d: { + sprite.regs.sub_enable = data & 0x10; + bg4.regs.sub_enable = data & 0x08; + bg3.regs.sub_enable = data & 0x04; + bg2.regs.sub_enable = data & 0x02; + bg1.regs.sub_enable = data & 0x01; + return; + } + + //TMW + case 0x212e: { + window.regs.oam_main_enable = data & 0x10; + window.regs.bg4_main_enable = data & 0x08; + window.regs.bg3_main_enable = data & 0x04; + window.regs.bg2_main_enable = data & 0x02; + window.regs.bg1_main_enable = data & 0x01; + return; + } + + //TSW + case 0x212f: { + window.regs.oam_sub_enable = data & 0x10; + window.regs.bg4_sub_enable = data & 0x08; + window.regs.bg3_sub_enable = data & 0x04; + window.regs.bg2_sub_enable = data & 0x02; + window.regs.bg1_sub_enable = data & 0x01; + return; + } + + //CGWSEL + case 0x2130: { + window.regs.col_main_mask = (data >> 6) & 3; + window.regs.col_sub_mask = (data >> 4) & 3; + screen.regs.addsub_mode = data & 0x02; + screen.regs.direct_color = data & 0x01; + return; + } + + //CGADDSUB + case 0x2131: { + screen.regs.color_mode = data & 0x80; + screen.regs.color_halve = data & 0x40; + screen.regs.back_color_enable = data & 0x20; + screen.regs.oam_color_enable = data & 0x10; + screen.regs.bg4_color_enable = data & 0x08; + screen.regs.bg3_color_enable = data & 0x04; + screen.regs.bg2_color_enable = data & 0x02; + screen.regs.bg1_color_enable = data & 0x01; + return; + } + + //COLDATA + case 0x2132: { + if(data & 0x80) screen.regs.color_b = data & 0x1f; + if(data & 0x40) screen.regs.color_g = data & 0x1f; + if(data & 0x20) screen.regs.color_r = data & 0x1f; + return; + } + + //SETINI + case 0x2133: { + regs.mode7_extbg = data & 0x40; + regs.pseudo_hires = data & 0x08; + regs.overscan = data & 0x04; + sprite.regs.interlace = data & 0x02; + regs.interlace = data & 0x01; + updateVideoMode(); + return; + } + + } +} + +auto PPU::latchCounters() -> void { + cpu.synchronizePPU(); + regs.hcounter = hdot(); + regs.vcounter = vcounter(); + regs.counters_latched = true; +} + +auto PPU::updateVideoMode() -> void { + switch(regs.bgmode) { + case 0: + bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11; + 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; + sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12; + break; + + case 1: + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::BPP2; + bg4.regs.mode = Background::Mode::Inactive; + if(regs.bg3_priority) { + bg1.regs.priority0 = 5; bg1.regs.priority1 = 8; + bg2.regs.priority0 = 4; bg2.regs.priority1 = 7; + bg3.regs.priority0 = 1; bg3.regs.priority1 = 10; + 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; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10; + } + break; + + case 2: + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + break; + + case 3: + bg1.regs.mode = Background::Mode::BPP8; + bg2.regs.mode = Background::Mode::BPP4; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + break; + + case 4: + bg1.regs.mode = Background::Mode::BPP8; + bg2.regs.mode = Background::Mode::BPP2; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + break; + + case 5: + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::BPP2; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + break; + + case 6: + bg1.regs.mode = Background::Mode::BPP4; + bg2.regs.mode = Background::Mode::Inactive; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 2; bg1.regs.priority1 = 5; + sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6; + break; + + case 7: + if(regs.mode7_extbg == false) { + bg1.regs.mode = Background::Mode::Mode7; + bg2.regs.mode = Background::Mode::Inactive; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 2; bg1.regs.priority1 = 2; + 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; + bg3.regs.mode = Background::Mode::Inactive; + bg4.regs.mode = Background::Mode::Inactive; + bg1.regs.priority0 = 3; bg1.regs.priority1 = 3; + bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; + sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7; + } + break; + } +} diff --git a/higan/sfc/ppu/mmio/mmio.cpp b/higan/sfc/ppu/mmio/mmio.cpp deleted file mode 100644 index d42ecf8f..00000000 --- a/higan/sfc/ppu/mmio/mmio.cpp +++ /dev/null @@ -1,883 +0,0 @@ -auto PPU::interlace() const -> bool { - return display.interlace; -} - -auto PPU::overscan() const -> bool { - return display.overscan; -} - -auto PPU::latch_counters() -> void { - cpu.synchronizePPU(); - regs.hcounter = hdot(); - regs.vcounter = vcounter(); - regs.counters_latched = true; -} - -auto PPU::get_vram_address() -> uint16 { - uint16 addr = regs.vram_addr; - switch(regs.vram_mapping) { - case 0: break; //direct mapping - case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break; - case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break; - case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break; - } - return (addr << 1); -} - -auto PPU::vram_read(uint addr) -> uint8 { - uint8 data = 0x00; - if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) { - data = vram[addr]; - debugger.vram_read(addr, data); - } - return data; -} - -auto PPU::vram_write(uint addr, uint8 data) -> void { - if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) { - vram[addr] = data; - debugger.vram_write(addr, data); - } -} - -auto PPU::oam_read(uint addr) -> uint8 { - uint8 data = oam[addr]; - debugger.oam_read(addr, data); - return data; -} - -auto PPU::oam_write(uint addr, uint8 data) -> void { - oam[addr] = data; - sprite.update(addr, data); - debugger.oam_write(addr, data); -} - -auto PPU::cgram_read(uint addr) -> uint8 { - uint8 data = cgram[addr]; - debugger.cgram_read(addr, data); - return data; -} - -auto PPU::cgram_write(uint addr, uint8 data) -> void { - cgram[addr] = data; - debugger.cgram_write(addr, data); -} - -auto PPU::mmio_update_video_mode() -> void { - switch(regs.bgmode) { - case 0: - bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11; - 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; - sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12; - break; - - case 1: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::BPP4; - bg3.regs.mode = Background::Mode::BPP2; - bg4.regs.mode = Background::Mode::Inactive; - if(regs.bg3_priority) { - bg1.regs.priority0 = 5; bg1.regs.priority1 = 8; - bg2.regs.priority0 = 4; bg2.regs.priority1 = 7; - bg3.regs.priority0 = 1; bg3.regs.priority1 = 10; - 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; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10; - } - break; - - case 2: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::BPP4; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; - break; - - case 3: - bg1.regs.mode = Background::Mode::BPP8; - bg2.regs.mode = Background::Mode::BPP4; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; - break; - - case 4: - bg1.regs.mode = Background::Mode::BPP8; - bg2.regs.mode = Background::Mode::BPP2; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; - break; - - case 5: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::BPP2; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; - break; - - case 6: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::Inactive; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 2; bg1.regs.priority1 = 5; - sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6; - break; - - case 7: - if(regs.mode7_extbg == false) { - bg1.regs.mode = Background::Mode::Mode7; - bg2.regs.mode = Background::Mode::Inactive; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 2; bg1.regs.priority1 = 2; - 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; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 3; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7; - } - break; - } -} - -//INIDISP -auto PPU::mmio_w2100(uint8 data) -> void { - if(regs.display_disable && vcounter() == (!regs.overscan ? 225 : 240)) sprite.address_reset(); - regs.display_disable = data & 0x80; - regs.display_brightness = data & 0x0f; -} - -//OBSEL -auto PPU::mmio_w2101(uint8 data) -> void { - sprite.regs.base_size = (data >> 5) & 7; - sprite.regs.nameselect = (data >> 3) & 3; - sprite.regs.tiledata_addr = (data & 3) << 14; -} - -//OAMADDL -auto PPU::mmio_w2102(uint8 data) -> void { - regs.oam_baseaddr = (regs.oam_baseaddr & 0x0200) | (data << 1); - sprite.address_reset(); -} - -//OAMADDH -auto PPU::mmio_w2103(uint8 data) -> void { - regs.oam_priority = data & 0x80; - regs.oam_baseaddr = ((data & 0x01) << 9) | (regs.oam_baseaddr & 0x01fe); - sprite.address_reset(); -} - -//OAMDATA -auto PPU::mmio_w2104(uint8 data) -> void { - bool latch = regs.oam_addr & 1; - uint10 addr = regs.oam_addr++; - if(regs.display_disable == false && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.oam_iaddr; - if(addr & 0x0200) addr &= 0x021f; - - if(latch == 0) regs.oam_latchdata = data; - if(addr & 0x0200) { - oam_write(addr, data); - } else if(latch == 1) { - oam_write((addr & ~1) + 0, regs.oam_latchdata); - oam_write((addr & ~1) + 1, data); - } - sprite.set_first_sprite(); -} - -//BGMODE -auto PPU::mmio_w2105(uint8 data) -> void { - bg4.regs.tile_size = (data & 0x80); - bg3.regs.tile_size = (data & 0x40); - bg2.regs.tile_size = (data & 0x20); - bg1.regs.tile_size = (data & 0x10); - regs.bg3_priority = (data & 0x08); - regs.bgmode = (data & 0x07); - mmio_update_video_mode(); -} - -//MOSAIC -auto PPU::mmio_w2106(uint8 data) -> void { - unsigned mosaic_size = (data >> 4) & 15; - bg4.regs.mosaic = (data & 0x08 ? mosaic_size : 0); - bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); - bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); - bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); -} - -//BG1SC -auto PPU::mmio_w2107(uint8 data) -> void { - bg1.regs.screen_addr = (data & 0x7c) << 9; - bg1.regs.screen_size = data & 3; -} - -//BG2SC -auto PPU::mmio_w2108(uint8 data) -> void { - bg2.regs.screen_addr = (data & 0x7c) << 9; - bg2.regs.screen_size = data & 3; -} - -//BG3SC -auto PPU::mmio_w2109(uint8 data) -> void { - bg3.regs.screen_addr = (data & 0x7c) << 9; - bg3.regs.screen_size = data & 3; -} - -//BG4SC -auto PPU::mmio_w210a(uint8 data) -> void { - bg4.regs.screen_addr = (data & 0x7c) << 9; - bg4.regs.screen_size = data & 3; -} - -//BG12NBA -auto PPU::mmio_w210b(uint8 data) -> void { - bg1.regs.tiledata_addr = (data & 0x07) << 13; - bg2.regs.tiledata_addr = (data & 0x70) << 9; -} - -//BG34NBA -auto PPU::mmio_w210c(uint8 data) -> void { - bg3.regs.tiledata_addr = (data & 0x07) << 13; - bg4.regs.tiledata_addr = (data & 0x70) << 9; -} - -//BG1HOFS -auto PPU::mmio_w210d(uint8 data) -> void { - regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; - - bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; -} - -//BG1VOFS -auto PPU::mmio_w210e(uint8 data) -> void { - regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; - - bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; -} - -//BG2HOFS -auto PPU::mmio_w210f(uint8 data) -> void { - bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; -} - -//BG2VOFS -auto PPU::mmio_w2110(uint8 data) -> void { - bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; -} - -//BG3HOFS -auto PPU::mmio_w2111(uint8 data) -> void { - bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; -} - -//BG3VOFS -auto PPU::mmio_w2112(uint8 data) -> void { - bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; -} - -//BG4HOFS -auto PPU::mmio_w2113(uint8 data) -> void { - bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; -} - -//BG4VOFS -auto PPU::mmio_w2114(uint8 data) -> void { - bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; -} - -//VMAIN -auto PPU::mmio_w2115(uint8 data) -> void { - regs.vram_incmode = data & 0x80; - regs.vram_mapping = (data >> 2) & 3; - switch(data & 3) { - case 0: regs.vram_incsize = 1; break; - case 1: regs.vram_incsize = 32; break; - case 2: regs.vram_incsize = 128; break; - case 3: regs.vram_incsize = 128; break; - } -} - -//VMADDL -auto PPU::mmio_w2116(uint8 data) -> void { - regs.vram_addr &= 0xff00; - regs.vram_addr |= (data << 0); - uint16 addr = get_vram_address(); - regs.vram_readbuffer = vram_read(addr + 0) << 0; - regs.vram_readbuffer |= vram_read(addr + 1) << 8; -} - -//VMADDH -auto PPU::mmio_w2117(uint8 data) -> void { - regs.vram_addr &= 0x00ff; - regs.vram_addr |= (data << 8); - uint16 addr = get_vram_address(); - regs.vram_readbuffer = vram_read(addr + 0) << 0; - regs.vram_readbuffer |= vram_read(addr + 1) << 8; -} - -//VMDATAL -auto PPU::mmio_w2118(uint8 data) -> void { - uint16 addr = get_vram_address() + 0; - vram_write(addr, data); - if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize; -} - -//VMDATAH -auto PPU::mmio_w2119(uint8 data) -> void { - uint16 addr = get_vram_address() + 1; - vram_write(addr, data); - if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize; -} - -//M7SEL -auto PPU::mmio_w211a(uint8 data) -> void { - regs.mode7_repeat = (data >> 6) & 3; - regs.mode7_vflip = data & 0x02; - regs.mode7_hflip = data & 0x01; -} - -//M7A -auto PPU::mmio_w211b(uint8 data) -> void { - regs.m7a = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; -} - -//M7B -auto PPU::mmio_w211c(uint8 data) -> void { - regs.m7b = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; -} - -//M7C -auto PPU::mmio_w211d(uint8 data) -> void { - regs.m7c = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; -} - -//M7D -auto PPU::mmio_w211e(uint8 data) -> void { - regs.m7d = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; -} - -//M7X -auto PPU::mmio_w211f(uint8 data) -> void { - regs.m7x = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; -} - -//M7Y -auto PPU::mmio_w2120(uint8 data) -> void { - regs.m7y = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; -} - -//CGADD -auto PPU::mmio_w2121(uint8 data) -> void { - regs.cgram_addr = data << 1; -} - -//CGDATA -auto PPU::mmio_w2122(uint8 data) -> void { - bool latch = regs.cgram_addr & 1; - uint9 addr = regs.cgram_addr++; - if(regs.display_disable == false - && vcounter() > 0 && vcounter() < (!regs.overscan ? 225 : 240) - && hcounter() >= 88 && hcounter() < 1096 - ) addr = regs.cgram_iaddr; - - if(latch == 0) { - regs.cgram_latchdata = data; - } else { - cgram_write((addr & ~1) + 0, regs.cgram_latchdata); - cgram_write((addr & ~1) + 1, data & 0x7f); - } -} - -//W12SEL -auto PPU::mmio_w2123(uint8 data) -> void { - window.regs.bg2_two_enable = data & 0x80; - window.regs.bg2_two_invert = data & 0x40; - window.regs.bg2_one_enable = data & 0x20; - window.regs.bg2_one_invert = data & 0x10; - window.regs.bg1_two_enable = data & 0x08; - window.regs.bg1_two_invert = data & 0x04; - window.regs.bg1_one_enable = data & 0x02; - window.regs.bg1_one_invert = data & 0x01; -} - -//W34SEL -auto PPU::mmio_w2124(uint8 data) -> void { - window.regs.bg4_two_enable = data & 0x80; - window.regs.bg4_two_invert = data & 0x40; - window.regs.bg4_one_enable = data & 0x20; - window.regs.bg4_one_invert = data & 0x10; - window.regs.bg3_two_enable = data & 0x08; - window.regs.bg3_two_invert = data & 0x04; - window.regs.bg3_one_enable = data & 0x02; - window.regs.bg3_one_invert = data & 0x01; -} - -//WOBJSEL -auto PPU::mmio_w2125(uint8 data) -> void { - window.regs.col_two_enable = data & 0x80; - window.regs.col_two_invert = data & 0x40; - window.regs.col_one_enable = data & 0x20; - window.regs.col_one_invert = data & 0x10; - window.regs.oam_two_enable = data & 0x08; - window.regs.oam_two_invert = data & 0x04; - window.regs.oam_one_enable = data & 0x02; - window.regs.oam_one_invert = data & 0x01; -} - -//WH0 -auto PPU::mmio_w2126(uint8 data) -> void { - window.regs.one_left = data; -} - -//WH1 -auto PPU::mmio_w2127(uint8 data) -> void { - window.regs.one_right = data; -} - -//WH2 -auto PPU::mmio_w2128(uint8 data) -> void { - window.regs.two_left = data; -} - -//WH3 -auto PPU::mmio_w2129(uint8 data) -> void { - window.regs.two_right = data; -} - -//WBGLOG -auto PPU::mmio_w212a(uint8 data) -> void { - window.regs.bg4_mask = (data >> 6) & 3; - window.regs.bg3_mask = (data >> 4) & 3; - window.regs.bg2_mask = (data >> 2) & 3; - window.regs.bg1_mask = (data >> 0) & 3; -} - -//WOBJLOG -auto PPU::mmio_w212b(uint8 data) -> void { - window.regs.col_mask = (data >> 2) & 3; - window.regs.oam_mask = (data >> 0) & 3; -} - -//TM -auto PPU::mmio_w212c(uint8 data) -> void { - sprite.regs.main_enable = data & 0x10; - bg4.regs.main_enable = data & 0x08; - bg3.regs.main_enable = data & 0x04; - bg2.regs.main_enable = data & 0x02; - bg1.regs.main_enable = data & 0x01; -} - -//TS -auto PPU::mmio_w212d(uint8 data) -> void { - sprite.regs.sub_enable = data & 0x10; - bg4.regs.sub_enable = data & 0x08; - bg3.regs.sub_enable = data & 0x04; - bg2.regs.sub_enable = data & 0x02; - bg1.regs.sub_enable = data & 0x01; -} - -//TMW -auto PPU::mmio_w212e(uint8 data) -> void { - window.regs.oam_main_enable = data & 0x10; - window.regs.bg4_main_enable = data & 0x08; - window.regs.bg3_main_enable = data & 0x04; - window.regs.bg2_main_enable = data & 0x02; - window.regs.bg1_main_enable = data & 0x01; -} - -//TSW -auto PPU::mmio_w212f(uint8 data) -> void { - window.regs.oam_sub_enable = data & 0x10; - window.regs.bg4_sub_enable = data & 0x08; - window.regs.bg3_sub_enable = data & 0x04; - window.regs.bg2_sub_enable = data & 0x02; - window.regs.bg1_sub_enable = data & 0x01; -} - -//CGWSEL -auto PPU::mmio_w2130(uint8 data) -> void { - window.regs.col_main_mask = (data >> 6) & 3; - window.regs.col_sub_mask = (data >> 4) & 3; - screen.regs.addsub_mode = data & 0x02; - screen.regs.direct_color = data & 0x01; -} - -//CGADDSUB -auto PPU::mmio_w2131(uint8 data) -> void { - screen.regs.color_mode = data & 0x80; - screen.regs.color_halve = data & 0x40; - screen.regs.back_color_enable = data & 0x20; - screen.regs.oam_color_enable = data & 0x10; - screen.regs.bg4_color_enable = data & 0x08; - screen.regs.bg3_color_enable = data & 0x04; - screen.regs.bg2_color_enable = data & 0x02; - screen.regs.bg1_color_enable = data & 0x01; -} - -//COLDATA -auto PPU::mmio_w2132(uint8 data) -> void { - if(data & 0x80) screen.regs.color_b = data & 0x1f; - if(data & 0x40) screen.regs.color_g = data & 0x1f; - if(data & 0x20) screen.regs.color_r = data & 0x1f; -} - -//SETINI -auto PPU::mmio_w2133(uint8 data) -> void { - regs.mode7_extbg = data & 0x40; - regs.pseudo_hires = data & 0x08; - regs.overscan = data & 0x04; - sprite.regs.interlace = data & 0x02; - regs.interlace = data & 0x01; - mmio_update_video_mode(); -} - -//MPYL -auto PPU::mmio_r2134() -> uint8 { - unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); - regs.ppu1_mdr = (result >> 0); - return regs.ppu1_mdr; -} - -//MPYM -auto PPU::mmio_r2135() -> uint8 { - unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); - regs.ppu1_mdr = (result >> 8); - return regs.ppu1_mdr; -} - -//MPYH -auto PPU::mmio_r2136() -> uint8 { - unsigned result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); - regs.ppu1_mdr = (result >> 16); - return regs.ppu1_mdr; -} - -//SLHV -auto PPU::mmio_r2137() -> uint8 { - if(cpu.pio() & 0x80) latch_counters(); - return cpu.regs.mdr; -} - -//OAMDATAREAD -auto PPU::mmio_r2138() -> uint8 { - uint10 addr = regs.oam_addr++; - if(regs.display_disable == false && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.oam_iaddr; - if(addr & 0x0200) addr &= 0x021f; - - regs.ppu1_mdr = oam_read(addr); - sprite.set_first_sprite(); - return regs.ppu1_mdr; -} - -//VMDATALREAD -auto PPU::mmio_r2139() -> uint8 { - uint16 addr = get_vram_address() + 0; - regs.ppu1_mdr = regs.vram_readbuffer >> 0; - if(regs.vram_incmode == 0) { - addr &= ~1; - regs.vram_readbuffer = vram_read(addr + 0) << 0; - regs.vram_readbuffer |= vram_read(addr + 1) << 8; - regs.vram_addr += regs.vram_incsize; - } - return regs.ppu1_mdr; -} - -//VMDATAHREAD -auto PPU::mmio_r213a() -> uint8 { - uint16 addr = get_vram_address() + 1; - regs.ppu1_mdr = regs.vram_readbuffer >> 8; - if(regs.vram_incmode == 1) { - addr &= ~1; - regs.vram_readbuffer = vram_read(addr + 0) << 0; - regs.vram_readbuffer |= vram_read(addr + 1) << 8; - regs.vram_addr += regs.vram_incsize; - } - return regs.ppu1_mdr; -} - -//CGDATAREAD -auto PPU::mmio_r213b() -> uint8 { - bool latch = regs.cgram_addr & 1; - uint9 addr = regs.cgram_addr++; - if(regs.display_disable == false - && vcounter() > 0 && vcounter() < (!regs.overscan ? 225 : 240) - && hcounter() >= 88 && hcounter() < 1096 - ) addr = regs.cgram_iaddr; - - if(latch == 0) { - regs.ppu2_mdr = cgram_read(addr); - } else { - regs.ppu2_mdr &= 0x80; - regs.ppu2_mdr |= cgram_read(addr); - } - return regs.ppu2_mdr; -} - -//OPHCT -auto PPU::mmio_r213c() -> uint8 { - if(regs.latch_hcounter == 0) { - regs.ppu2_mdr = (regs.hcounter >> 0); - } else { - regs.ppu2_mdr &= 0xfe; - regs.ppu2_mdr |= (regs.hcounter >> 8) & 1; - } - regs.latch_hcounter ^= 1; - return regs.ppu2_mdr; -} - -//OPVCT -auto PPU::mmio_r213d() -> uint8 { - if(regs.latch_vcounter == 0) { - regs.ppu2_mdr = (regs.vcounter >> 0); - } else { - regs.ppu2_mdr &= 0xfe; - regs.ppu2_mdr |= (regs.vcounter >> 8) & 1; - } - regs.latch_vcounter ^= 1; - return regs.ppu2_mdr; -} - -//STAT77 -auto PPU::mmio_r213e() -> uint8 { - regs.ppu1_mdr &= 0x10; - 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; -} - -//STAT78 -auto PPU::mmio_r213f() -> uint8 { - regs.latch_hcounter = 0; - regs.latch_vcounter = 0; - - regs.ppu2_mdr &= 0x20; - regs.ppu2_mdr |= field() << 7; - if((cpu.pio() & 0x80) == 0) { - regs.ppu2_mdr |= 0x40; - } else if(regs.counters_latched) { - regs.ppu2_mdr |= 0x40; - regs.counters_latched = false; - } - regs.ppu2_mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4; - regs.ppu2_mdr |= ppu2_version & 0x0f; - return regs.ppu2_mdr; -} - -auto PPU::mmio_reset() -> void { - regs.ppu1_mdr = random(0xff); - regs.ppu2_mdr = random(0xff); - - regs.vram_readbuffer = random(0x0000); - regs.oam_latchdata = random(0x00); - regs.cgram_latchdata = random(0x00); - regs.bgofs_latchdata = random(0x00); - regs.mode7_latchdata = random(0x00); - regs.counters_latched = false; - regs.latch_hcounter = 0; - regs.latch_vcounter = 0; - - regs.oam_iaddr = 0x0000; - regs.cgram_iaddr = 0x00; - - //$2100 INIDISP - regs.display_disable = true; - regs.display_brightness = 0; - - //$2102 OAMADDL - //$2103 OAMADDH - regs.oam_baseaddr = random(0x0000); - regs.oam_addr = random(0x0000); - regs.oam_priority = random(false); - - //$2105 BGMODE - regs.bg3_priority = false; - regs.bgmode = 0; - - //$210d BG1HOFS - regs.mode7_hoffset = random(0x0000); - - //$210e BG1VOFS - regs.mode7_voffset = random(0x0000); - - //$2115 VMAIN - regs.vram_incmode = random(1); - regs.vram_mapping = random(0); - regs.vram_incsize = 1; - - //$2116 VMADDL - //$2117 VMADDH - regs.vram_addr = random(0x0000); - - //$211a M7SEL - regs.mode7_repeat = random(0); - regs.mode7_vflip = random(false); - regs.mode7_hflip = random(false); - - //$211b M7A - regs.m7a = random(0x0000); - - //$211c M7B - regs.m7b = random(0x0000); - - //$211d M7C - regs.m7c = random(0x0000); - - //$211e M7D - regs.m7d = random(0x0000); - - //$211f M7X - regs.m7x = random(0x0000); - - //$2120 M7Y - regs.m7y = random(0x0000); - - //$2121 CGADD - regs.cgram_addr = random(0x0000); - - //$2133 SETINI - regs.mode7_extbg = random(false); - regs.pseudo_hires = random(false); - regs.overscan = false; - regs.interlace = false; - - //$213c OPHCT - regs.hcounter = 0; - - //$213d OPVCT - regs.vcounter = 0; -} - -auto PPU::mmio_read(uint addr, uint8 data) -> uint8 { - cpu.synchronizePPU(); - - switch(addr & 0xffff) { - case 0x2104: - case 0x2105: - case 0x2106: - case 0x2108: - case 0x2109: - case 0x210a: - case 0x2114: - case 0x2115: - case 0x2116: - case 0x2118: - case 0x2119: - case 0x211a: - case 0x2124: - case 0x2125: - case 0x2126: - case 0x2128: - case 0x2129: - case 0x212a: return regs.ppu1_mdr; - case 0x2134: return mmio_r2134(); //MPYL - case 0x2135: return mmio_r2135(); //MPYM - case 0x2136: return mmio_r2136(); //MYPH - case 0x2137: return mmio_r2137(); //SLHV - case 0x2138: return mmio_r2138(); //OAMDATAREAD - case 0x2139: return mmio_r2139(); //VMDATALREAD - case 0x213a: return mmio_r213a(); //VMDATAHREAD - case 0x213b: return mmio_r213b(); //CGDATAREAD - case 0x213c: return mmio_r213c(); //OPHCT - case 0x213d: return mmio_r213d(); //OPVCT - case 0x213e: return mmio_r213e(); //STAT77 - case 0x213f: return mmio_r213f(); //STAT78 - } - - return data; -} - -auto PPU::mmio_write(uint addr, uint8 data) -> void { - cpu.synchronizePPU(); - - switch(addr & 0xffff) { - case 0x2100: return mmio_w2100(data); //INIDISP - case 0x2101: return mmio_w2101(data); //OBSEL - case 0x2102: return mmio_w2102(data); //OAMADDL - case 0x2103: return mmio_w2103(data); //OAMADDH - case 0x2104: return mmio_w2104(data); //OAMDATA - case 0x2105: return mmio_w2105(data); //BGMODE - case 0x2106: return mmio_w2106(data); //MOSAIC - case 0x2107: return mmio_w2107(data); //BG1SC - case 0x2108: return mmio_w2108(data); //BG2SC - case 0x2109: return mmio_w2109(data); //BG3SC - case 0x210a: return mmio_w210a(data); //BG4SC - case 0x210b: return mmio_w210b(data); //BG12NBA - case 0x210c: return mmio_w210c(data); //BG34NBA - case 0x210d: return mmio_w210d(data); //BG1HOFS - case 0x210e: return mmio_w210e(data); //BG1VOFS - case 0x210f: return mmio_w210f(data); //BG2HOFS - case 0x2110: return mmio_w2110(data); //BG2VOFS - case 0x2111: return mmio_w2111(data); //BG3HOFS - case 0x2112: return mmio_w2112(data); //BG3VOFS - case 0x2113: return mmio_w2113(data); //BG4HOFS - case 0x2114: return mmio_w2114(data); //BG4VOFS - case 0x2115: return mmio_w2115(data); //VMAIN - case 0x2116: return mmio_w2116(data); //VMADDL - case 0x2117: return mmio_w2117(data); //VMADDH - case 0x2118: return mmio_w2118(data); //VMDATAL - case 0x2119: return mmio_w2119(data); //VMDATAH - case 0x211a: return mmio_w211a(data); //M7SEL - case 0x211b: return mmio_w211b(data); //M7A - case 0x211c: return mmio_w211c(data); //M7B - case 0x211d: return mmio_w211d(data); //M7C - case 0x211e: return mmio_w211e(data); //M7D - case 0x211f: return mmio_w211f(data); //M7X - case 0x2120: return mmio_w2120(data); //M7Y - case 0x2121: return mmio_w2121(data); //CGADD - case 0x2122: return mmio_w2122(data); //CGDATA - case 0x2123: return mmio_w2123(data); //W12SEL - case 0x2124: return mmio_w2124(data); //W34SEL - case 0x2125: return mmio_w2125(data); //WOBJSEL - case 0x2126: return mmio_w2126(data); //WH0 - case 0x2127: return mmio_w2127(data); //WH1 - case 0x2128: return mmio_w2128(data); //WH2 - case 0x2129: return mmio_w2129(data); //WH3 - case 0x212a: return mmio_w212a(data); //WBGLOG - case 0x212b: return mmio_w212b(data); //WOBJLOG - case 0x212c: return mmio_w212c(data); //TM - case 0x212d: return mmio_w212d(data); //TS - case 0x212e: return mmio_w212e(data); //TMW - case 0x212f: return mmio_w212f(data); //TSW - case 0x2130: return mmio_w2130(data); //CGWSEL - case 0x2131: return mmio_w2131(data); //CGADDSUB - case 0x2132: return mmio_w2132(data); //COLDATA - case 0x2133: return mmio_w2133(data); //SETINI - } -} diff --git a/higan/sfc/ppu/mmio/mmio.hpp b/higan/sfc/ppu/mmio/mmio.hpp deleted file mode 100644 index 13eae372..00000000 --- a/higan/sfc/ppu/mmio/mmio.hpp +++ /dev/null @@ -1,165 +0,0 @@ -public: - auto mmio_read(uint addr, uint8 data) -> uint8; - auto mmio_write(uint addr, uint8 data) -> void; - -privileged: -struct { - uint8 ppu1_mdr; - uint8 ppu2_mdr; - - uint16 vram_readbuffer; - uint8 oam_latchdata; - uint8 cgram_latchdata; - uint8 bgofs_latchdata; - uint8 mode7_latchdata; - bool counters_latched; - bool latch_hcounter; - bool latch_vcounter; - - uint10 oam_iaddr; - uint9 cgram_iaddr; - - //$2100 INIDISP - bool display_disable; - uint4 display_brightness; - - //$2102 OAMADDL - //$2103 OAMADDH - uint10 oam_baseaddr; - uint10 oam_addr; - bool oam_priority; - - //$2105 BGMODE - bool bg3_priority; - uint8 bgmode; - - //$210d BG1HOFS - uint16 mode7_hoffset; - - //$210e BG1VOFS - uint16 mode7_voffset; - - //$2115 VMAIN - bool vram_incmode; - uint2 vram_mapping; - uint8 vram_incsize; - - //$2116 VMADDL - //$2117 VMADDH - uint16 vram_addr; - - //$211a M7SEL - uint2 mode7_repeat; - bool mode7_vflip; - bool mode7_hflip; - - //$211b M7A - uint16 m7a; - - //$211c M7B - uint16 m7b; - - //$211d M7C - uint16 m7c; - - //$211e M7D - uint16 m7d; - - //$211f M7X - uint16 m7x; - - //$2120 M7Y - uint16 m7y; - - //$2121 CGADD - uint9 cgram_addr; - - //$2133 SETINI - bool mode7_extbg; - bool pseudo_hires; - bool overscan; - bool interlace; - - //$213c OPHCT - uint16 hcounter; - - //$213d OPVCT - uint16 vcounter; -} regs; - -alwaysinline auto get_vram_address() -> uint16; -alwaysinline auto vram_read(uint addr) -> uint8; -alwaysinline auto vram_write(uint addr, uint8 data) -> void; -alwaysinline auto oam_read(uint addr) -> uint8; -alwaysinline auto oam_write(uint addr, uint8 data) -> void; -alwaysinline auto cgram_read(uint addr) -> uint8; -alwaysinline auto cgram_write(uint addr, uint8 data) -> void; - -auto mmio_update_video_mode() -> void; - -auto mmio_w2100(uint8) -> void; //INIDISP -auto mmio_w2101(uint8) -> void; //OBSEL -auto mmio_w2102(uint8) -> void; //OAMADDL -auto mmio_w2103(uint8) -> void; //OAMADDH -auto mmio_w2104(uint8) -> void; //OAMDATA -auto mmio_w2105(uint8) -> void; //BGMODE -auto mmio_w2106(uint8) -> void; //MOSAIC -auto mmio_w2107(uint8) -> void; //BG1SC -auto mmio_w2108(uint8) -> void; //BG2SC -auto mmio_w2109(uint8) -> void; //BG3SC -auto mmio_w210a(uint8) -> void; //BG4SC -auto mmio_w210b(uint8) -> void; //BG12NBA -auto mmio_w210c(uint8) -> void; //BG34NBA -auto mmio_w210d(uint8) -> void; //BG1HOFS -auto mmio_w210e(uint8) -> void; //BG1VOFS -auto mmio_w210f(uint8) -> void; //BG2HOFS -auto mmio_w2110(uint8) -> void; //BG2VOFS -auto mmio_w2111(uint8) -> void; //BG3HOFS -auto mmio_w2112(uint8) -> void; //BG3VOFS -auto mmio_w2113(uint8) -> void; //BG4HOFS -auto mmio_w2114(uint8) -> void; //BG4VOFS -auto mmio_w2115(uint8) -> void; //VMAIN -auto mmio_w2116(uint8) -> void; //VMADDL -auto mmio_w2117(uint8) -> void; //VMADDH -auto mmio_w2118(uint8) -> void; //VMDATAL -auto mmio_w2119(uint8) -> void; //VMDATAH -auto mmio_w211a(uint8) -> void; //M7SEL -auto mmio_w211b(uint8) -> void; //M7A -auto mmio_w211c(uint8) -> void; //M7B -auto mmio_w211d(uint8) -> void; //M7C -auto mmio_w211e(uint8) -> void; //M7D -auto mmio_w211f(uint8) -> void; //M7X -auto mmio_w2120(uint8) -> void; //M7Y -auto mmio_w2121(uint8) -> void; //CGADD -auto mmio_w2122(uint8) -> void; //CGDATA -auto mmio_w2123(uint8) -> void; //W12SEL -auto mmio_w2124(uint8) -> void; //W34SEL -auto mmio_w2125(uint8) -> void; //WOBJSEL -auto mmio_w2126(uint8) -> void; //WH0 -auto mmio_w2127(uint8) -> void; //WH1 -auto mmio_w2128(uint8) -> void; //WH2 -auto mmio_w2129(uint8) -> void; //WH3 -auto mmio_w212a(uint8) -> void; //WBGLOG -auto mmio_w212b(uint8) -> void; //WOBJLOG -auto mmio_w212c(uint8) -> void; //TM -auto mmio_w212d(uint8) -> void; //TS -auto mmio_w212e(uint8) -> void; //TMW -auto mmio_w212f(uint8) -> void; //TSW -auto mmio_w2130(uint8) -> void; //CGWSEL -auto mmio_w2131(uint8) -> void; //CGADDSUB -auto mmio_w2132(uint8) -> void; //COLDATA -auto mmio_w2133(uint8) -> void; //SETINI -auto mmio_r2134() -> uint8; //MPYL -auto mmio_r2135() -> uint8; //MPYM -auto mmio_r2136() -> uint8; //MPYH -auto mmio_r2137() -> uint8; //SLHV -auto mmio_r2138() -> uint8; //OAMDATAREAD -auto mmio_r2139() -> uint8; //VMDATALREAD -auto mmio_r213a() -> uint8; //VMDATAHREAD -auto mmio_r213b() -> uint8; //CGDATAREAD -auto mmio_r213c() -> uint8; //OPHCT -auto mmio_r213d() -> uint8; //OPVCT -auto mmio_r213e() -> uint8; //STAT77 -auto mmio_r213f() -> uint8; //STAT78 - -auto mmio_reset() -> void; diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index e76b77d3..2ad1cd5f 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -5,8 +5,9 @@ namespace SuperFamicom { PPU ppu; #include "video.cpp" +#include "memory.cpp" +#include "mmio.cpp" #include "background/background.cpp" -#include "mmio/mmio.cpp" #include "screen/screen.cpp" #include "sprite/sprite.cpp" #include "window/window.cpp" @@ -41,7 +42,7 @@ auto PPU::Enter() -> void { auto PPU::main() -> void { scanline(); - add_clocks(28); + addClocks(28); bg1.begin(); bg2.begin(); bg3.begin(); @@ -53,7 +54,7 @@ auto PPU::main() -> void { bg2.run(1); bg3.run(1); bg4.run(1); - add_clocks(2); + addClocks(2); bg1.run(0); bg2.run(0); @@ -64,19 +65,19 @@ auto PPU::main() -> void { window.run(); screen.run(); } - add_clocks(2); + addClocks(2); } - add_clocks(14); + addClocks(14); sprite.tilefetch(); } else { - add_clocks(1052 + 14 + 136); + addClocks(1052 + 14 + 136); } - add_clocks(lineclocks() - 28 - 1052 - 14 - 136); + addClocks(lineclocks() - 28 - 1052 - 14 - 136); } -auto PPU::add_clocks(uint clocks) -> void { +auto PPU::addClocks(uint clocks) -> void { clocks >>= 1; while(clocks--) { tick(2); @@ -86,8 +87,8 @@ auto PPU::add_clocks(uint clocks) -> void { } auto PPU::enable() -> void { - function uint8> reader{&PPU::mmio_read, (PPU*)&ppu}; - function void> writer{&PPU::mmio_write, (PPU*)&ppu}; + function uint8> reader{&PPU::read, this}; + function void> writer{&PPU::write, this}; bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f); bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f); @@ -104,7 +105,88 @@ auto PPU::reset() -> void { PPUcounter::reset(); memory::fill(output, 512 * 480 * sizeof(uint32)); - mmio_reset(); + regs.ppu1_mdr = random(0xff); + regs.ppu2_mdr = random(0xff); + + regs.vram_readbuffer = random(0x0000); + regs.oam_latchdata = random(0x00); + regs.cgram_latchdata = random(0x00); + regs.bgofs_latchdata = random(0x00); + regs.mode7_latchdata = random(0x00); + regs.counters_latched = false; + regs.latch_hcounter = 0; + regs.latch_vcounter = 0; + + regs.oam_iaddr = 0x0000; + regs.cgram_iaddr = 0x00; + + //$2100 INIDISP + regs.display_disable = true; + regs.display_brightness = 0; + + //$2102 OAMADDL + //$2103 OAMADDH + regs.oam_baseaddr = random(0x0000); + regs.oam_addr = random(0x0000); + regs.oam_priority = random(false); + + //$2105 BGMODE + regs.bg3_priority = false; + regs.bgmode = 0; + + //$210d BG1HOFS + regs.mode7_hoffset = random(0x0000); + + //$210e BG1VOFS + regs.mode7_voffset = random(0x0000); + + //$2115 VMAIN + regs.vram_incmode = random(1); + regs.vram_mapping = random(0); + regs.vram_incsize = 1; + + //$2116 VMADDL + //$2117 VMADDH + regs.vram_addr = random(0x0000); + + //$211a M7SEL + regs.mode7_repeat = random(0); + regs.mode7_vflip = random(false); + regs.mode7_hflip = random(false); + + //$211b M7A + regs.m7a = random(0x0000); + + //$211c M7B + regs.m7b = random(0x0000); + + //$211d M7C + regs.m7c = random(0x0000); + + //$211e M7D + regs.m7d = random(0x0000); + + //$211f M7X + regs.m7x = random(0x0000); + + //$2120 M7Y + regs.m7y = random(0x0000); + + //$2121 CGADD + regs.cgram_addr = random(0x0000); + + //$2133 SETINI + regs.mode7_extbg = random(false); + regs.pseudo_hires = random(false); + regs.overscan = false; + regs.interlace = false; + + //$213c OPHCT + regs.hcounter = 0; + + //$213d OPVCT + regs.vcounter = 0; + bg1.reset(); bg2.reset(); bg3.reset(); diff --git a/higan/sfc/ppu/ppu.hpp b/higan/sfc/ppu/ppu.hpp index 32bc5e27..7d9ae9d2 100644 --- a/higan/sfc/ppu/ppu.hpp +++ b/higan/sfc/ppu/ppu.hpp @@ -1,16 +1,17 @@ #include "video.hpp" -struct PPU : Thread, public PPUcounter { +struct PPU : Thread, PPUcounter { + alwaysinline auto interlace() const -> bool { return display.interlace; } + alwaysinline auto overscan() const -> bool { return display.overscan; } + alwaysinline auto vdisp() const -> uint { return !regs.overscan ? 225 : 240; } + PPU(); ~PPU(); alwaysinline auto step(uint clocks) -> void; alwaysinline auto synchronizeCPU() -> void; - auto latch_counters() -> void; - auto interlace() const -> bool; - auto overscan() const -> bool; - + static auto Enter() -> void; auto main() -> void; auto enable() -> void; auto power() -> void; @@ -18,6 +19,21 @@ struct PPU : Thread, public PPUcounter { auto serialize(serializer&) -> void; + //memory.cpp + alwaysinline auto getVramAddress() -> uint16; + alwaysinline auto vramRead(uint addr) -> uint8; + alwaysinline auto vramWrite(uint addr, uint8 data) -> void; + alwaysinline auto oamRead(uint addr) -> uint8; + alwaysinline auto oamWrite(uint addr, uint8 data) -> void; + alwaysinline auto cgramRead(uint addr) -> uint8; + alwaysinline auto cgramWrite(uint addr, uint8 data) -> void; + + //mmio.cpp + auto read(uint24 addr, uint8 data) -> uint8; + auto write(uint24 addr, uint8 data) -> void; + auto latchCounters() -> void; + auto updateVideoMode() -> void; + uint8 vram[64 * 1024]; uint8 oam[544]; uint8 cgram[512]; @@ -33,8 +49,96 @@ privileged: bool overscan; } display; + alwaysinline auto addClocks(uint) -> void; + + auto scanline() -> void; + auto frame() -> void; + + struct Registers { + uint8 ppu1_mdr; + uint8 ppu2_mdr; + + uint16 vram_readbuffer; + uint8 oam_latchdata; + uint8 cgram_latchdata; + uint8 bgofs_latchdata; + uint8 mode7_latchdata; + bool counters_latched; + bool latch_hcounter; + bool latch_vcounter; + + uint10 oam_iaddr; + uint9 cgram_iaddr; + + //$2100 INIDISP + bool display_disable; + uint4 display_brightness; + + //$2102 OAMADDL + //$2103 OAMADDH + uint10 oam_baseaddr; + uint10 oam_addr; + bool oam_priority; + + //$2105 BGMODE + bool bg3_priority; + uint8 bgmode; + + //$210d BG1HOFS + uint16 mode7_hoffset; + + //$210e BG1VOFS + uint16 mode7_voffset; + + //$2115 VMAIN + bool vram_incmode; + uint2 vram_mapping; + uint8 vram_incsize; + + //$2116 VMADDL + //$2117 VMADDH + uint16 vram_addr; + + //$211a M7SEL + uint2 mode7_repeat; + bool mode7_vflip; + bool mode7_hflip; + + //$211b M7A + uint16 m7a; + + //$211c M7B + uint16 m7b; + + //$211d M7C + uint16 m7c; + + //$211e M7D + uint16 m7d; + + //$211f M7X + uint16 m7x; + + //$2120 M7Y + uint16 m7y; + + //$2121 CGADD + uint9 cgram_addr; + + //$2133 SETINI + bool mode7_extbg; + bool pseudo_hires; + bool overscan; + bool interlace; + + //$213c OPHCT + uint16 hcounter; + + //$213d OPVCT + uint16 vcounter; + } regs; + #include "background/background.hpp" - #include "mmio/mmio.hpp" #include "screen/screen.hpp" #include "sprite/sprite.hpp" #include "window/window.hpp" @@ -47,12 +151,6 @@ privileged: Window window; Screen screen; - static auto Enter() -> void; - alwaysinline auto add_clocks(uint) -> void; - - auto scanline() -> void; - auto frame() -> void; - friend class PPU::Background; friend class PPU::Sprite; friend class PPU::Window; diff --git a/higan/sfc/ppu/sprite/sprite.cpp b/higan/sfc/ppu/sprite/sprite.cpp index 5b0f46e2..3bcd27d4 100644 --- a/higan/sfc/ppu/sprite/sprite.cpp +++ b/higan/sfc/ppu/sprite/sprite.cpp @@ -28,8 +28,8 @@ auto PPU::Sprite::scanline() -> void { auto oam_item = t.item[t.active]; auto oam_tile = t.tile[t.active]; - if(t.y == (!self.regs.overscan ? 225 : 240) && !self.regs.display_disable) address_reset(); - if(t.y >= (!self.regs.overscan ? 224 : 239)) return; + if(t.y == self.vdisp() && !self.regs.display_disable) address_reset(); + if(t.y >= self.vdisp() - 1) return; for(auto n : range(32)) oam_item[n].valid = false; //default to invalid for(auto n : range(34)) oam_tile[n].valid = false; //default to invalid @@ -148,15 +148,15 @@ auto PPU::Sprite::tilefetch() -> void { oam_tile[n].d0 = ppu.vram[addr + 0]; oam_tile[n].d1 = ppu.vram[addr + 1]; - self.add_clocks(2); + self.addClocks(2); oam_tile[n].d2 = ppu.vram[addr + 16]; oam_tile[n].d3 = ppu.vram[addr + 17]; - self.add_clocks(2); + self.addClocks(2); } } - if(t.tile_count < 34) self.add_clocks((34 - t.tile_count) * 4); + if(t.tile_count < 34) self.addClocks((34 - t.tile_count) * 4); regs.time_over |= (t.tile_count > 34); regs.range_over |= (t.item_count > 32); } diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index 6a0aef2a..de0ea562 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -1,5 +1,8 @@ #pragma once +//license: GPLv3 +//started: 2004-10-14 + #include #include #include @@ -10,18 +13,10 @@ namespace SuperFamicom { namespace Info { - static const string Name = "bsnes"; static const uint SerializerVersion = 30; } } -/* - bsnes - Super Famicom emulator - author: byuu - license: GPLv3 - project started: 2004-10-14 -*/ - #include #if defined(SFC_SUPERGAMEBOY) diff --git a/higan/ws/ws.hpp b/higan/ws/ws.hpp index f6144de3..f687d2de 100644 --- a/higan/ws/ws.hpp +++ b/higan/ws/ws.hpp @@ -1,22 +1,17 @@ #pragma once +//license: GPLv3 +//started: 2016-01-26 + #include #include namespace WonderSwan { namespace Info { - static const string Name = "bws"; static const uint SerializerVersion = 1; } } -/* - bws - WonderSwan, WonderSwan Color, and SwanCrystal emulator - author: byuu - license: GPLv3 - project started: 2016-01-26 -*/ - #include namespace WonderSwan {