mirror of https://github.com/bsnes-emu/bsnes.git
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<system> names as shorthand. The simplification is mostly to make the branding easier.
This commit is contained in:
parent
19e1d89f00
commit
7403e69307
|
@ -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/";
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2011-09-05
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/r6502/r6502.hpp>
|
||||
|
||||
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 <libco/libco.h>
|
||||
|
||||
namespace Famicom {
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2010-12-27
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/lr35902/lr35902.hpp>
|
||||
|
||||
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 <libco/libco.h>
|
||||
|
||||
namespace GameBoy {
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2012-03-19
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
|
||||
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 <libco/libco.h>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
|
||||
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
|
||||
function<auto (uint24, uint8) -> uint8> reader{&PPU::read, this};
|
||||
function<auto (uint24, uint8) -> 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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2004-10-14
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
#include <processor/gsu/gsu.hpp>
|
||||
|
@ -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 <libco/libco.h>
|
||||
|
||||
#if defined(SFC_SUPERGAMEBOY)
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2016-01-26
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/v30mz/v30mz.hpp>
|
||||
|
||||
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 <libco/libco.h>
|
||||
|
||||
namespace WonderSwan {
|
||||
|
|
Loading…
Reference in New Issue