2010-08-09 13:28:56 +00:00
|
|
|
//INIDISP
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2100(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) {
|
|
|
|
regs.oam_addr = regs.oam_baseaddr << 1;
|
|
|
|
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
|
|
|
}
|
|
|
|
|
|
|
|
regs.display_disabled = !!(value & 0x80);
|
|
|
|
regs.display_brightness = value & 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OBSEL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2101(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.oam_basesize = (value >> 5) & 7;
|
|
|
|
regs.oam_nameselect = (value >> 3) & 3;
|
|
|
|
regs.oam_tdaddr = (value & 3) << 14;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OAMADDL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2102(uint8 data) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.oam_baseaddr = (regs.oam_baseaddr & ~0xff) | (data << 0);
|
|
|
|
regs.oam_baseaddr &= 0x01ff;
|
|
|
|
regs.oam_addr = regs.oam_baseaddr << 1;
|
|
|
|
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OAMADDH
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2103(uint8 data) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.oam_priority = !!(data & 0x80);
|
|
|
|
regs.oam_baseaddr = (regs.oam_baseaddr & 0xff) | (data << 8);
|
|
|
|
regs.oam_baseaddr &= 0x01ff;
|
|
|
|
regs.oam_addr = regs.oam_baseaddr << 1;
|
|
|
|
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OAMDATA
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2104(uint8 data) -> void {
|
2010-09-24 13:15:21 +00:00
|
|
|
if((regs.oam_addr & 1) == 0) regs.oam_latchdata = data;
|
|
|
|
|
2010-08-09 13:28:56 +00:00
|
|
|
if(regs.oam_addr & 0x0200) {
|
|
|
|
oam_mmio_write(regs.oam_addr, data);
|
2010-09-24 13:15:21 +00:00
|
|
|
} else if((regs.oam_addr & 1) == 1) {
|
2010-08-09 13:28:56 +00:00
|
|
|
oam_mmio_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
|
|
|
|
oam_mmio_write((regs.oam_addr & ~1) + 1, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
regs.oam_addr++;
|
|
|
|
regs.oam_addr &= 0x03ff;
|
|
|
|
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BGMODE
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2105(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_tilesize[BG4] = !!(value & 0x80);
|
|
|
|
regs.bg_tilesize[BG3] = !!(value & 0x40);
|
|
|
|
regs.bg_tilesize[BG2] = !!(value & 0x20);
|
|
|
|
regs.bg_tilesize[BG1] = !!(value & 0x10);
|
|
|
|
regs.bg3_priority = !!(value & 0x08);
|
|
|
|
regs.bg_mode = (value & 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
//MOSAIC
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2106(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.mosaic_size = (value >> 4) & 15;
|
|
|
|
regs.mosaic_enabled[BG4] = !!(value & 0x08);
|
|
|
|
regs.mosaic_enabled[BG3] = !!(value & 0x04);
|
|
|
|
regs.mosaic_enabled[BG2] = !!(value & 0x02);
|
|
|
|
regs.mosaic_enabled[BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG1SC
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2107(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_scaddr[BG1] = (value & 0x7c) << 9;
|
|
|
|
regs.bg_scsize[BG1] = value & 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG2SC
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2108(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_scaddr[BG2] = (value & 0x7c) << 9;
|
|
|
|
regs.bg_scsize[BG2] = value & 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG3SC
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2109(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_scaddr[BG3] = (value & 0x7c) << 9;
|
|
|
|
regs.bg_scsize[BG3] = value & 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG4SC
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w210a(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_scaddr[BG4] = (value & 0x7c) << 9;
|
|
|
|
regs.bg_scsize[BG4] = value & 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG12NBA
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w210b(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_tdaddr[BG1] = (value & 0x07) << 13;
|
|
|
|
regs.bg_tdaddr[BG2] = (value & 0x70) << 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG34NBA
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w210c(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_tdaddr[BG3] = (value & 0x07) << 13;
|
|
|
|
regs.bg_tdaddr[BG4] = (value & 0x70) << 9;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG1HOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w210d(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7_hofs = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
|
|
|
|
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG1] >> 8) & 7);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG1VOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w210e(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7_vofs = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
|
|
|
|
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG2HOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w210f(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG2VOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2110(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG3HOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2111(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG3VOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2112(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG4HOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2113(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//BG4VOFS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2114(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch);
|
|
|
|
regs.bg_ofslatch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMAIN
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2115(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.vram_incmode = !!(value & 0x80);
|
|
|
|
regs.vram_mapping = (value >> 2) & 3;
|
|
|
|
switch(value & 3) {
|
2013-05-05 09:21:30 +00:00
|
|
|
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;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMADDL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2116(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.vram_addr = (regs.vram_addr & 0xff00) | value;
|
|
|
|
uint16 addr = get_vram_address();
|
|
|
|
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
|
|
|
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMADDH
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2117(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.vram_addr = (value << 8) | (regs.vram_addr & 0x00ff);
|
|
|
|
uint16 addr = get_vram_address();
|
|
|
|
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
|
|
|
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMDATAL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2118(uint8 value) -> void {
|
|
|
|
uint16 addr = get_vram_address();
|
2010-08-09 13:28:56 +00:00
|
|
|
vram_mmio_write(addr, value);
|
|
|
|
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
|
|
|
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
|
|
|
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
|
|
|
|
|
|
|
if(regs.vram_incmode == 0) {
|
|
|
|
regs.vram_addr += regs.vram_incsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMDATAH
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2119(uint8 value) -> void {
|
|
|
|
uint16 addr = get_vram_address() + 1;
|
2010-08-09 13:28:56 +00:00
|
|
|
vram_mmio_write(addr, value);
|
|
|
|
bg_tiledata_state[TILE_2BIT][(addr >> 4)] = 1;
|
|
|
|
bg_tiledata_state[TILE_4BIT][(addr >> 5)] = 1;
|
|
|
|
bg_tiledata_state[TILE_8BIT][(addr >> 6)] = 1;
|
|
|
|
|
|
|
|
if(regs.vram_incmode == 1) {
|
|
|
|
regs.vram_addr += regs.vram_incsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7SEL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w211a(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.mode7_repeat = (value >> 6) & 3;
|
|
|
|
regs.mode7_vflip = !!(value & 0x02);
|
|
|
|
regs.mode7_hflip = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7A
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w211b(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7a = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7B
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w211c(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7b = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7C
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w211d(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7c = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7D
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w211e(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7d = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7X
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w211f(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7x = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//M7Y
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2120(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.m7y = (value << 8) | regs.m7_latch;
|
|
|
|
regs.m7_latch = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//CGADD
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2121(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.cgram_addr = value << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//CGDATA
|
|
|
|
//note: CGRAM palette data format is 15-bits
|
|
|
|
//(0,bbbbb,ggggg,rrrrr). Highest bit is ignored,
|
|
|
|
//as evidenced by $213b CGRAM data reads.
|
|
|
|
//
|
|
|
|
//anomie indicates writes to CGDATA work the same
|
|
|
|
//as writes to OAMDATA's low table. need to verify
|
|
|
|
//this on hardware.
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2122(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(!(regs.cgram_addr & 1)) {
|
|
|
|
regs.cgram_latchdata = value;
|
|
|
|
} else {
|
|
|
|
cgram_mmio_write((regs.cgram_addr & 0x01fe), regs.cgram_latchdata);
|
|
|
|
cgram_mmio_write((regs.cgram_addr & 0x01fe) + 1, value & 0x7f);
|
|
|
|
}
|
|
|
|
regs.cgram_addr++;
|
|
|
|
regs.cgram_addr &= 0x01ff;
|
|
|
|
}
|
|
|
|
|
|
|
|
//W12SEL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2123(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window2_enabled[BG2] = !!(value & 0x80);
|
|
|
|
regs.window2_invert [BG2] = !!(value & 0x40);
|
|
|
|
regs.window1_enabled[BG2] = !!(value & 0x20);
|
|
|
|
regs.window1_invert [BG2] = !!(value & 0x10);
|
|
|
|
regs.window2_enabled[BG1] = !!(value & 0x08);
|
|
|
|
regs.window2_invert [BG1] = !!(value & 0x04);
|
|
|
|
regs.window1_enabled[BG1] = !!(value & 0x02);
|
|
|
|
regs.window1_invert [BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//W34SEL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2124(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window2_enabled[BG4] = !!(value & 0x80);
|
|
|
|
regs.window2_invert [BG4] = !!(value & 0x40);
|
|
|
|
regs.window1_enabled[BG4] = !!(value & 0x20);
|
|
|
|
regs.window1_invert [BG4] = !!(value & 0x10);
|
|
|
|
regs.window2_enabled[BG3] = !!(value & 0x08);
|
|
|
|
regs.window2_invert [BG3] = !!(value & 0x04);
|
|
|
|
regs.window1_enabled[BG3] = !!(value & 0x02);
|
|
|
|
regs.window1_invert [BG3] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//WOBJSEL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2125(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window2_enabled[COL] = !!(value & 0x80);
|
|
|
|
regs.window2_invert [COL] = !!(value & 0x40);
|
|
|
|
regs.window1_enabled[COL] = !!(value & 0x20);
|
|
|
|
regs.window1_invert [COL] = !!(value & 0x10);
|
|
|
|
regs.window2_enabled[OAM] = !!(value & 0x08);
|
|
|
|
regs.window2_invert [OAM] = !!(value & 0x04);
|
|
|
|
regs.window1_enabled[OAM] = !!(value & 0x02);
|
|
|
|
regs.window1_invert [OAM] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//WH0
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2126(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window1_left = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//WH1
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2127(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window1_right = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//WH2
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2128(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window2_left = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//WH3
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2129(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window2_right = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
//WBGLOG
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w212a(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window_mask[BG4] = (value >> 6) & 3;
|
|
|
|
regs.window_mask[BG3] = (value >> 4) & 3;
|
|
|
|
regs.window_mask[BG2] = (value >> 2) & 3;
|
|
|
|
regs.window_mask[BG1] = (value ) & 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//WOBJLOG
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w212b(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window_mask[COL] = (value >> 2) & 3;
|
|
|
|
regs.window_mask[OAM] = (value ) & 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
//TM
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w212c(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bg_enabled[OAM] = !!(value & 0x10);
|
|
|
|
regs.bg_enabled[BG4] = !!(value & 0x08);
|
|
|
|
regs.bg_enabled[BG3] = !!(value & 0x04);
|
|
|
|
regs.bg_enabled[BG2] = !!(value & 0x02);
|
|
|
|
regs.bg_enabled[BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//TS
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w212d(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.bgsub_enabled[OAM] = !!(value & 0x10);
|
|
|
|
regs.bgsub_enabled[BG4] = !!(value & 0x08);
|
|
|
|
regs.bgsub_enabled[BG3] = !!(value & 0x04);
|
|
|
|
regs.bgsub_enabled[BG2] = !!(value & 0x02);
|
|
|
|
regs.bgsub_enabled[BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//TMW
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w212e(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.window_enabled[OAM] = !!(value & 0x10);
|
|
|
|
regs.window_enabled[BG4] = !!(value & 0x08);
|
|
|
|
regs.window_enabled[BG3] = !!(value & 0x04);
|
|
|
|
regs.window_enabled[BG2] = !!(value & 0x02);
|
|
|
|
regs.window_enabled[BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//TSW
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w212f(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.sub_window_enabled[OAM] = !!(value & 0x10);
|
|
|
|
regs.sub_window_enabled[BG4] = !!(value & 0x08);
|
|
|
|
regs.sub_window_enabled[BG3] = !!(value & 0x04);
|
|
|
|
regs.sub_window_enabled[BG2] = !!(value & 0x02);
|
|
|
|
regs.sub_window_enabled[BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CGWSEL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2130(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.color_mask = (value >> 6) & 3;
|
|
|
|
regs.colorsub_mask = (value >> 4) & 3;
|
|
|
|
regs.addsub_mode = !!(value & 0x02);
|
|
|
|
regs.direct_color = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//CGADDSUB
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2131(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.color_mode = !!(value & 0x80);
|
|
|
|
regs.color_halve = !!(value & 0x40);
|
|
|
|
regs.color_enabled[BACK] = !!(value & 0x20);
|
|
|
|
regs.color_enabled[OAM] = !!(value & 0x10);
|
|
|
|
regs.color_enabled[BG4] = !!(value & 0x08);
|
|
|
|
regs.color_enabled[BG3] = !!(value & 0x04);
|
|
|
|
regs.color_enabled[BG2] = !!(value & 0x02);
|
|
|
|
regs.color_enabled[BG1] = !!(value & 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
//COLDATA
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2132(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(value & 0x80) regs.color_b = value & 0x1f;
|
|
|
|
if(value & 0x40) regs.color_g = value & 0x1f;
|
|
|
|
if(value & 0x20) regs.color_r = value & 0x1f;
|
|
|
|
|
|
|
|
regs.color_rgb = (regs.color_r)
|
|
|
|
| (regs.color_g << 5)
|
|
|
|
| (regs.color_b << 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
//SETINI
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_w2133(uint8 value) -> void {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.mode7_extbg = !!(value & 0x40);
|
|
|
|
regs.pseudo_hires = !!(value & 0x08);
|
|
|
|
regs.overscan = !!(value & 0x04);
|
|
|
|
regs.oam_interlace = !!(value & 0x02);
|
|
|
|
regs.interlace = !!(value & 0x01);
|
|
|
|
|
|
|
|
display.overscan = regs.overscan;
|
|
|
|
sprite_list_valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//MPYL
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r2134() -> uint8 {
|
|
|
|
uint32 r;
|
2010-08-09 13:28:56 +00:00
|
|
|
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
|
|
|
regs.ppu1_mdr = r;
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//MPYM
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r2135() -> uint8 {
|
|
|
|
uint32 r;
|
2010-08-09 13:28:56 +00:00
|
|
|
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
|
|
|
regs.ppu1_mdr = r >> 8;
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//MPYH
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r2136() -> uint8 {
|
|
|
|
uint32 r;
|
2010-08-09 13:28:56 +00:00
|
|
|
r = ((int16)regs.m7a * (int8)(regs.m7b >> 8));
|
|
|
|
regs.ppu1_mdr = r >> 16;
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//SLHV
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r2137() -> uint8 {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(cpu.pio() & 0x80) {
|
|
|
|
latch_counters();
|
|
|
|
}
|
|
|
|
return cpu.regs.mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OAMDATAREAD
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r2138() -> uint8 {
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.ppu1_mdr = oam_mmio_read(regs.oam_addr);
|
|
|
|
|
|
|
|
regs.oam_addr++;
|
|
|
|
regs.oam_addr &= 0x03ff;
|
|
|
|
regs.oam_firstsprite = (regs.oam_priority == false) ? 0 : (regs.oam_addr >> 2) & 127;
|
|
|
|
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMDATALREAD
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r2139() -> uint8 {
|
|
|
|
uint16 addr = get_vram_address();
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.ppu1_mdr = regs.vram_readbuffer;
|
|
|
|
if(regs.vram_incmode == 0) {
|
|
|
|
addr &= 0xfffe;
|
|
|
|
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
|
|
|
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
|
|
|
regs.vram_addr += regs.vram_incsize;
|
|
|
|
}
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//VMDATAHREAD
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r213a() -> uint8 {
|
|
|
|
uint16 addr = get_vram_address() + 1;
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.ppu1_mdr = regs.vram_readbuffer >> 8;
|
|
|
|
if(regs.vram_incmode == 1) {
|
|
|
|
addr &= 0xfffe;
|
|
|
|
regs.vram_readbuffer = vram_mmio_read(addr + 0);
|
|
|
|
regs.vram_readbuffer |= vram_mmio_read(addr + 1) << 8;
|
|
|
|
regs.vram_addr += regs.vram_incsize;
|
|
|
|
}
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//CGDATAREAD
|
|
|
|
//note: CGRAM palette data is 15-bits (0,bbbbb,ggggg,rrrrr)
|
|
|
|
//therefore, the high byte read from each color does not
|
|
|
|
//update bit 7 of the PPU2 MDR.
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r213b() -> uint8 {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(!(regs.cgram_addr & 1)) {
|
|
|
|
regs.ppu2_mdr = cgram_mmio_read(regs.cgram_addr) & 0xff;
|
|
|
|
} else {
|
|
|
|
regs.ppu2_mdr &= 0x80;
|
|
|
|
regs.ppu2_mdr |= cgram_mmio_read(regs.cgram_addr) & 0x7f;
|
|
|
|
}
|
|
|
|
regs.cgram_addr++;
|
|
|
|
regs.cgram_addr &= 0x01ff;
|
|
|
|
return regs.ppu2_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OPHCT
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r213c() -> uint8 {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(!regs.latch_hcounter) {
|
|
|
|
regs.ppu2_mdr = regs.hcounter & 0xff;
|
|
|
|
} else {
|
|
|
|
regs.ppu2_mdr &= 0xfe;
|
|
|
|
regs.ppu2_mdr |= (regs.hcounter >> 8) & 1;
|
|
|
|
}
|
|
|
|
regs.latch_hcounter ^= 1;
|
|
|
|
return regs.ppu2_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//OPVCT
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r213d() -> uint8 {
|
2010-08-09 13:28:56 +00:00
|
|
|
if(!regs.latch_vcounter) {
|
|
|
|
regs.ppu2_mdr = regs.vcounter & 0xff;
|
|
|
|
} else {
|
|
|
|
regs.ppu2_mdr &= 0xfe;
|
|
|
|
regs.ppu2_mdr |= (regs.vcounter >> 8) & 1;
|
|
|
|
}
|
|
|
|
regs.latch_vcounter ^= 1;
|
|
|
|
return regs.ppu2_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//STAT77
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r213e() -> uint8 {
|
|
|
|
uint8 r = 0x00;
|
2010-08-09 13:28:56 +00:00
|
|
|
r |= (regs.time_over) ? 0x80 : 0x00;
|
|
|
|
r |= (regs.range_over) ? 0x40 : 0x00;
|
|
|
|
r |= (regs.ppu1_mdr & 0x10);
|
|
|
|
r |= (ppu1_version & 0x0f);
|
|
|
|
regs.ppu1_mdr = r;
|
|
|
|
return regs.ppu1_mdr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//STAT78
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_r213f() -> uint8 {
|
|
|
|
uint8 r = 0x00;
|
2010-08-09 13:28:56 +00:00
|
|
|
regs.latch_hcounter = 0;
|
|
|
|
regs.latch_vcounter = 0;
|
|
|
|
|
|
|
|
r |= cpu.field() << 7;
|
|
|
|
if(!(cpu.pio() & 0x80)) {
|
|
|
|
r |= 0x40;
|
|
|
|
} else if(regs.counters_latched == true) {
|
|
|
|
r |= 0x40;
|
|
|
|
regs.counters_latched = false;
|
|
|
|
}
|
|
|
|
r |= (regs.ppu2_mdr & 0x20);
|
|
|
|
r |= (region << 4); //0 = NTSC, 1 = PAL
|
|
|
|
r |= (ppu2_version & 0x0f);
|
|
|
|
regs.ppu2_mdr = r;
|
|
|
|
return regs.ppu2_mdr;
|
|
|
|
}
|
|
|
|
|
Update to higan and icarus v095r17 release.
byuu says:
higan supports Event mapping again.
Further, icarus can now detect Event ROMs and MSU1 games.
Event ROMs must be named "program.rom", "slot-(1,2,3).rom" MSU1 games
must contain "msu1.rom"; and tracks must be named "track-#.pcm"
When importing the CC'92, PF'94 ROMs, the program.rom and
slot-(1,2,3).rom files must be concatenated. The DSP firmware can
optionally be separate, but I'd recommend you go ahead and merge it all
to one file. Especially since that common "higan DSP pack" floating
around on the web left out the DSP1 ROMs (only has DSP1B) for god knows
what reason.
There is no support for loading "game.sfc+game.msu+game-*.pcm", because
I'm not going to support trying to pull in all of those files through
importing. Games will have to be distributed as game folders to use
MSU1. The MSU1 icarus support is simply so your game folders won't
require an unstable manifest.bml file to be played. So once they're in
there, they are good for life.
Note: the Event sizes in icarus' SFC heuristics are wrong for appended
firmware. Change from 0xXX8000 to 0xXX2000 and it works fine. Will be
fixed in r18.
Added Sintendo's flickering fixes. The window one's a big help for
regular controls, but the ListView double buffering does nothing for me
on Windows 7 :( Fairly sure I know why, but too lazy to try and fix that
now.
Also fixes the mMenu thing.
2015-12-20 02:53:40 +00:00
|
|
|
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
|
2015-12-05 05:44:49 +00:00
|
|
|
cpu.synchronizePPU();
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
switch(addr & 0xffff) {
|
2013-05-05 09:21:30 +00:00
|
|
|
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(); //MPYH
|
|
|
|
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
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
Update to higan and icarus v095r17 release.
byuu says:
higan supports Event mapping again.
Further, icarus can now detect Event ROMs and MSU1 games.
Event ROMs must be named "program.rom", "slot-(1,2,3).rom" MSU1 games
must contain "msu1.rom"; and tracks must be named "track-#.pcm"
When importing the CC'92, PF'94 ROMs, the program.rom and
slot-(1,2,3).rom files must be concatenated. The DSP firmware can
optionally be separate, but I'd recommend you go ahead and merge it all
to one file. Especially since that common "higan DSP pack" floating
around on the web left out the DSP1 ROMs (only has DSP1B) for god knows
what reason.
There is no support for loading "game.sfc+game.msu+game-*.pcm", because
I'm not going to support trying to pull in all of those files through
importing. Games will have to be distributed as game folders to use
MSU1. The MSU1 icarus support is simply so your game folders won't
require an unstable manifest.bml file to be played. So once they're in
there, they are good for life.
Note: the Event sizes in icarus' SFC heuristics are wrong for appended
firmware. Change from 0xXX8000 to 0xXX2000 and it works fine. Will be
fixed in r18.
Added Sintendo's flickering fixes. The window one's a big help for
regular controls, but the ListView double buffering does nothing for me
on Windows 7 :( Fairly sure I know why, but too lazy to try and fix that
now.
Also fixes the mMenu thing.
2015-12-20 02:53:40 +00:00
|
|
|
return data;
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 05:44:49 +00:00
|
|
|
auto PPU::mmio_write(uint addr, uint8 data) -> void {
|
|
|
|
cpu.synchronizePPU();
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
switch(addr & 0xffff) {
|
2013-05-05 09:21:30 +00:00
|
|
|
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
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
}
|