mirror of https://github.com/bsnes-emu/bsnes.git
722 lines
18 KiB
C++
722 lines
18 KiB
C++
|
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;
|
||
|
}
|
||
|
}
|