auto PPU::readVRAM(uint mode, uint32 addr) -> uint32 { addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff; if(mode & Word) { addr &= ~3; return vram[addr + 0] << 0 | vram[addr + 1] << 8 | vram[addr + 2] << 16 | vram[addr + 3] << 24; } else if(mode & Half) { addr &= ~1; return vram[addr + 0] << 0 | vram[addr + 1] << 8; } else if(mode & Byte) { return vram[addr]; } unreachable; } auto PPU::writeVRAM(uint mode, uint32 addr, uint32 word) -> void { addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff; if(mode & Word) { addr &= ~3; vram[addr + 0] = word >> 0; vram[addr + 1] = word >> 8; vram[addr + 2] = word >> 16; vram[addr + 3] = word >> 24; } else if(mode & Half) { addr &= ~1; vram[addr + 0] = word >> 0; vram[addr + 1] = word >> 8; } else if(mode & Byte) { //8-bit writes to OBJ section of VRAM are ignored if(Background::IO::mode <= 2 && addr >= 0x10000) return; if(Background::IO::mode <= 5 && addr >= 0x14000) return; addr &= ~1; vram[addr + 0] = (uint8)word; vram[addr + 1] = (uint8)word; } } auto PPU::readPRAM(uint mode, uint32 addr) -> uint32 { if(mode & Word) return readPRAM(Half, addr & ~2) << 0 | readPRAM(Half, addr | 2) << 16; if(mode & Byte) return readPRAM(Half, addr) >> ((addr & 1) * 8); return pram[addr >> 1 & 511]; } auto PPU::writePRAM(uint mode, uint32 addr, uint32 word) -> void { if(mode & Word) { writePRAM(Half, addr & ~2, word >> 0); writePRAM(Half, addr | 2, word >> 16); return; } if(mode & Byte) { word = (uint8)word; return writePRAM(Half, addr, word << 8 | word << 0); } pram[addr >> 1 & 511] = (uint16)word; } auto PPU::readOAM(uint mode, uint32 addr) -> uint32 { if(mode & Word) return readOAM(Half, addr & ~2) << 0 | readOAM(Half, addr | 2) << 16; if(mode & Byte) return readOAM(Half, addr) >> ((addr & 1) * 8); auto& obj = object[addr >> 3 & 127]; auto& par = objectParam[addr >> 5 & 31]; switch(addr & 6) { case 0: return ( (obj.y << 0) | (obj.affine << 8) | (obj.affineSize << 9) | (obj.mode << 10) | (obj.mosaic << 12) | (obj.colors << 13) | (obj.shape << 14) ); case 2: return ( (obj.x << 0) | (obj.affineParam << 9) | (obj.hflip << 12) | (obj.vflip << 13) | (obj.size << 14) ); case 4: return ( (obj.character << 0) | (obj.priority << 10) | (obj.palette << 12) ); case 6: switch(addr >> 3 & 3) { case 0: return par.pa; case 1: return par.pb; case 2: return par.pc; case 3: return par.pd; } } } auto PPU::writeOAM(uint mode, uint32 addr, uint32 word) -> void { if(mode & Word) { writeOAM(Half, addr & ~2, word >> 0); writeOAM(Half, addr | 2, word >> 16); return; } if(mode & Byte) return; //8-bit writes to OAM are ignored auto& obj = object[addr >> 3 & 127]; auto& par = objectParam[addr >> 5 & 31]; switch(addr & 6) { case 0: obj.y = word >> 0; obj.affine = word >> 8; obj.affineSize = word >> 9; obj.mode = word >> 10; obj.mosaic = word >> 12; obj.colors = word >> 13; obj.shape = word >> 14; break; case 2: obj.x = word >> 0; obj.affineParam = word >> 9; obj.hflip = word >> 12; obj.vflip = word >> 13; obj.size = word >> 14; break; case 4: obj.character = word >> 0; obj.priority = word >> 10; obj.palette = word >> 12; break; case 6: switch(addr >> 3 & 3) { case 0: par.pa = word; break; case 1: par.pb = word; break; case 2: par.pc = word; break; case 3: par.pd = word; break; } } static uint widths[] = { 8, 16, 32, 64, 16, 32, 32, 64, 8, 8, 16, 32, 8, 8, 8, 8, //invalid modes }; static uint heights[] = { 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64, 8, 8, 8, 8, //invalid modes }; obj.width = widths [obj.shape * 4 + obj.size]; obj.height = heights[obj.shape * 4 + obj.size]; } auto PPU::readObjectVRAM(uint addr) const -> uint8 { if(Background::IO::mode == 3 || Background::IO::mode == 4 || Background::IO::mode == 5) { if(addr <= 0x3fff) return 0u; } return vram[0x10000 + (addr & 0x7fff)]; }