* started removing nall-specific components from the fast PPU renderer
* corrected compilation issues with Super Game Boy support
This commit is contained in:
byuu 2019-07-19 00:44:09 +09:00
parent 14d87f6bf3
commit 0623d6ac2b
15 changed files with 345 additions and 346 deletions

View File

@ -32,7 +32,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "bsnes"; static const string Name = "bsnes";
static const string Version = "107.8"; static const string Version = "107.9";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org/"; static const string Website = "https://byuu.org/";

View File

@ -1,10 +1,10 @@
auto PPUfast::Line::renderBackground(PPUfast::IO::Background& self, uint source) -> void { auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void {
if(!self.aboveEnable && !self.belowEnable) return; if(!self.aboveEnable && !self.belowEnable) return;
if(self.tileMode == TileMode::Mode7) return renderMode7(self, source); if(self.tileMode == TileMode::Mode7) return renderMode7(self, source);
if(self.tileMode == TileMode::Inactive) return; if(self.tileMode == TileMode::Inactive) return;
array<bool[256]> windowAbove; bool windowAbove[256];
array<bool[256]> windowBelow; bool windowBelow[256];
renderWindow(self.window, self.window.aboveEnable, windowAbove); renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow); renderWindow(self.window, self.window.belowEnable, windowBelow);
@ -23,13 +23,13 @@ auto PPUfast::Line::renderBackground(PPUfast::IO::Background& self, uint source)
uint hscroll = self.hoffset; uint hscroll = self.hoffset;
uint vscroll = self.voffset; uint vscroll = self.voffset;
uint hmask = (width << self.tileSize << bit1(self.screenSize,0)) - 1; uint hmask = (width << self.tileSize << !!(self.screenSize & 1)) - 1;
uint vmask = (width << self.tileSize << bit1(self.screenSize,1)) - 1; uint vmask = (width << self.tileSize << !!(self.screenSize & 2)) - 1;
uint y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); uint y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
if(hires) { if(hires) {
hscroll <<= 1; hscroll <<= 1;
if(io.interlace) y = y << 1 | ppufast.field(); if(io.interlace) y = y << 1 | ppu.field();
} }
uint mosaicCounter = 1; uint mosaicCounter = 1;
@ -79,7 +79,7 @@ auto PPUfast::Line::renderBackground(PPUfast::IO::Background& self, uint source)
if(tileHeight == 4 && (bool(voffset & 8) ^ bool(mirrorY))) tileNumber += 16; if(tileHeight == 4 && (bool(voffset & 8) ^ bool(mirrorY))) tileNumber += 16;
tileNumber = (tileNumber & 0x03ff) + tiledataIndex & tileMask; tileNumber = (tileNumber & 0x03ff) + tiledataIndex & tileMask;
auto tiledata = ppufast.tilecache[self.tileMode] + (tileNumber << 6); auto tiledata = ppu.tilecache[self.tileMode] + (tileNumber << 6);
tiledata += (voffset & 7 ^ mirrorY) << 3; tiledata += (voffset & 7 ^ mirrorY) << 3;
for(uint tileX = 0; tileX < 8; tileX++, x++) { for(uint tileX = 0; tileX < 8; tileX++, x++) {
@ -101,7 +101,7 @@ auto PPUfast::Line::renderBackground(PPUfast::IO::Background& self, uint source)
if(self.belowEnable && !windowBelow[x]) plotBelow(x, source, mosaicPriority, mosaicColor); if(self.belowEnable && !windowBelow[x]) plotBelow(x, source, mosaicPriority, mosaicColor);
} else { } else {
uint X = x >> 1; uint X = x >> 1;
if(!ppufast.hd()) { if(!ppu.hd()) {
if(x & 1) { if(x & 1) {
if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor); if(self.aboveEnable && !windowAbove[X]) plotAbove(X, source, mosaicPriority, mosaicColor);
} else { } else {
@ -116,17 +116,16 @@ auto PPUfast::Line::renderBackground(PPUfast::IO::Background& self, uint source)
} }
} }
auto PPUfast::Line::getTile(PPUfast::IO::Background& self, uint hoffset, uint voffset) -> uint { auto PPU::Line::getTile(PPU::IO::Background& self, uint hoffset, uint voffset) -> uint {
bool hires = io.bgMode == 5 || io.bgMode == 6; bool hires = io.bgMode == 5 || io.bgMode == 6;
uint tileHeight = 3 + self.tileSize; uint tileHeight = 3 + self.tileSize;
uint tileWidth = !hires ? tileHeight : 4; uint tileWidth = !hires ? tileHeight : 4;
uint screenX = (self.screenSize & 1) ? 32 << 5 : 0; uint screenX = self.screenSize & 1 ? 32 << 5 : 0;
uint screenY = (self.screenSize & 2) ? 32 << 5 + (self.screenSize & 1) : 0; uint screenY = self.screenSize & 2 ? 32 << 5 + (self.screenSize & 1) : 0;
uint tileX = hoffset >> tileWidth; uint tileX = hoffset >> tileWidth;
uint tileY = voffset >> tileHeight; uint tileY = voffset >> tileHeight;
uint offset = (tileY & 0x1f) << 5 | (tileX & 0x1f); uint offset = (tileY & 0x1f) << 5 | (tileX & 0x1f);
if(tileX & 0x20) offset += screenX; if(tileX & 0x20) offset += screenX;
if(tileY & 0x20) offset += screenY; if(tileY & 0x20) offset += screenY;
uint15 address = self.screenAddress + offset; return ppu.vram[self.screenAddress + offset & 0x7fff];
return ppufast.vram[address];
} }

View File

@ -1,28 +1,28 @@
auto PPUfast::latchCounters() -> void { auto PPU::latchCounters() -> void {
io.hcounter = cpu.hdot(); io.hcounter = cpu.hdot();
io.vcounter = cpu.vcounter(); io.vcounter = cpu.vcounter();
latch.counters = 1; latch.counters = 1;
} }
auto PPUfast::vramAddress() const -> uint15 { //uint15 for 64K VRAM; uint16 for 128K VRAM auto PPU::vramAddress() const -> uint {
uint15 address = io.vramAddress; uint address = io.vramAddress;
switch(io.vramMapping) { switch(io.vramMapping) {
case 0: return address; case 0: return address & 0x7fff;
case 1: return bits(address, 8-15) << 8 | bits(address,0-4) << 3 | bits(address,5-7); case 1: return address & 0x7f00 | address << 3 & 0x00f8 | address >> 5 & 7;
case 2: return bits(address, 9-15) << 9 | bits(address,0-5) << 3 | bits(address,6-8); case 2: return address & 0x7e00 | address << 3 & 0x01f8 | address >> 6 & 7;
case 3: return bits(address,10-15) << 10 | bits(address,0-6) << 3 | bits(address,7-9); case 3: return address & 0x7c00 | address << 3 & 0x03f8 | address >> 7 & 7;
} }
unreachable; unreachable;
} }
auto PPUfast::readVRAM() -> uint16 { auto PPU::readVRAM() -> uint16 {
if(!io.displayDisable && cpu.vcounter() < vdisp()) return 0x0000; if(!io.displayDisable && cpu.vcounter() < vdisp()) return 0x0000;
auto address = vramAddress(); auto address = vramAddress();
return vram[address]; return vram[address];
} }
template<bool Byte> template<bool Byte>
auto PPUfast::writeVRAM(uint8 data) -> void { auto PPU::writeVRAM(uint8_t data) -> void {
if(!io.displayDisable && cpu.vcounter() < vdisp()) return; if(!io.displayDisable && cpu.vcounter() < vdisp()) return;
Line::flush(); Line::flush();
auto address = vramAddress(); auto address = vramAddress();
@ -35,11 +35,11 @@ auto PPUfast::writeVRAM(uint8 data) -> void {
updateTiledata(address); updateTiledata(address);
} }
auto PPUfast::updateTiledata(uint address) -> void { auto PPU::updateTiledata(uint address) -> void {
auto word = vram[address]; auto word = vram[address & 0x7fff];
auto line2bpp = tilecache[TileMode::BPP2] + ((address & 0x7fff) << 3); auto line2bpp = tilecache[TileMode::BPP2] + (address << 3 & 0x3fff8);
auto line4bpp = tilecache[TileMode::BPP4] + ((address & 0x7ff0) << 2) + ((address & 7) << 3); auto line4bpp = tilecache[TileMode::BPP4] + (address << 2 & 0x1ffc0) + (address << 3 & 0x38);
auto line8bpp = tilecache[TileMode::BPP8] + ((address & 0x7fe0) << 1) + ((address & 7) << 3); auto line8bpp = tilecache[TileMode::BPP8] + (address << 1 & 0x0ffc0) + (address << 3 & 0x38);
uint plane4bpp = address >> 2 & 2; uint plane4bpp = address >> 2 & 2;
uint plane8bpp = address >> 2 & 6; uint plane8bpp = address >> 2 & 6;
for(uint x : range(8)) { for(uint x : range(8)) {
@ -49,20 +49,20 @@ auto PPUfast::updateTiledata(uint address) -> void {
} }
} }
auto PPUfast::readOAM(uint10 address) -> uint8 { auto PPU::readOAM(uint10 address) -> uint8 {
if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress; if(!io.displayDisable && cpu.vcounter() < vdisp()) address = latch.oamAddress;
return readObject(address); return readObject(address);
} }
auto PPUfast::writeOAM(uint10 address, uint8 data) -> void { auto PPU::writeOAM(uint10 address, uint8_t data) -> void {
Line::flush(); Line::flush();
//Uniracers 2-player mode hack //0x0218: Uniracers (2-player mode) hack; requires cycle timing for latch.oamAddress to be correct
if(!io.displayDisable && cpu.vcounter() < vdisp()) address = 0x0218; //latch.oamAddress; if(!io.displayDisable && cpu.vcounter() < vdisp()) address = 0x0218; //latch.oamAddress;
return writeObject(address, data); return writeObject(address, data);
} }
template<bool Byte> template<bool Byte>
auto PPUfast::readCGRAM(uint8 address) -> uint8 { auto PPU::readCGRAM(uint8_t address) -> uint8 {
if(!io.displayDisable if(!io.displayDisable
&& cpu.vcounter() > 0 && cpu.vcounter() < vdisp() && cpu.vcounter() > 0 && cpu.vcounter() < vdisp()
&& cpu.hcounter() >= 88 && cpu.hcounter() < 1096 && cpu.hcounter() >= 88 && cpu.hcounter() < 1096
@ -75,7 +75,7 @@ auto PPUfast::readCGRAM(uint8 address) -> uint8 {
} }
} }
auto PPUfast::writeCGRAM(uint8 address, uint15 data) -> void { auto PPU::writeCGRAM(uint8_t address, uint15 data) -> void {
if(!io.displayDisable if(!io.displayDisable
&& cpu.vcounter() > 0 && cpu.vcounter() < vdisp() && cpu.vcounter() > 0 && cpu.vcounter() < vdisp()
&& cpu.hcounter() >= 88 && cpu.hcounter() < 1096 && cpu.hcounter() >= 88 && cpu.hcounter() < 1096
@ -83,8 +83,8 @@ auto PPUfast::writeCGRAM(uint8 address, uint15 data) -> void {
cgram[address] = data; cgram[address] = data;
} }
auto PPUfast::readIO(uint address, uint8 data) -> uint8 { auto PPU::readIO(uint address, uint8 data) -> uint8 {
cpu.synchronize(ppufast); cpu.synchronize(ppu);
switch(address & 0xffff) { switch(address & 0xffff) {
@ -97,22 +97,22 @@ auto PPUfast::readIO(uint address, uint8 data) -> uint8 {
} }
case 0x2134: { //MPYL case 0x2134: { //MPYL
uint24 result = (int16)io.mode7.a * (int8)(io.mode7.b >> 8); uint result = (int16_t)io.mode7.a * (int8_t)(io.mode7.b >> 8);
return latch.ppu1.mdr = bit8(result,0); return latch.ppu1.mdr = result >> 0;
} }
case 0x2135: { //MPYM case 0x2135: { //MPYM
uint24 result = (int16)io.mode7.a * (int8)(io.mode7.b >> 8); uint result = (int16_t)io.mode7.a * (int8_t)(io.mode7.b >> 8);
return latch.ppu1.mdr = bit8(result,1); return latch.ppu1.mdr = result >> 8;
} }
case 0x2136: { //MPYH case 0x2136: { //MPYH
uint24 result = (int16)io.mode7.a * (int8)(io.mode7.b >> 8); uint result = (int16_t)io.mode7.a * (int8_t)(io.mode7.b >> 8);
return latch.ppu1.mdr = bit8(result,2); return latch.ppu1.mdr = result >> 16;
} }
case 0x2137: { //SLHV case 0x2137: { //SLHV
if(cbit1(cpu.pio(),7)) latchCounters(); if(cpu.pio() & 0x80) latchCounters();
return data; //CPU MDR return data; //CPU MDR
} }
@ -142,9 +142,9 @@ auto PPUfast::readIO(uint address, uint8 data) -> uint8 {
case 0x213b: { //CGDATAREAD case 0x213b: { //CGDATAREAD
if(io.cgramAddressLatch++ == 0) { if(io.cgramAddressLatch++ == 0) {
bits(latch.ppu2.mdr,0-7) = readCGRAM<0>(io.cgramAddress); latch.ppu2.mdr = readCGRAM<0>(io.cgramAddress);
} else { } else {
bits(latch.ppu2.mdr,0-6) = readCGRAM<1>(io.cgramAddress++); latch.ppu2.mdr = readCGRAM<1>(io.cgramAddress++) & 0x7f | latch.ppu2.mdr & 0x80;
} }
return latch.ppu2.mdr; return latch.ppu2.mdr;
} }
@ -152,10 +152,10 @@ auto PPUfast::readIO(uint address, uint8 data) -> uint8 {
case 0x213c: { //OPHCT case 0x213c: { //OPHCT
if(latch.hcounter == 0) { if(latch.hcounter == 0) {
latch.hcounter = 1; latch.hcounter = 1;
bits(latch.ppu2.mdr,0-7) = bits(io.hcounter,0-7); latch.ppu2.mdr = io.hcounter;
} else { } else {
latch.hcounter = 0; latch.hcounter = 0;
bit1(latch.ppu2.mdr,0) = bit1(io.hcounter,8); latch.ppu2.mdr = io.hcounter >> 8 | latch.ppu2.mdr & 0xfe;
} }
return latch.ppu2.mdr; return latch.ppu2.mdr;
} }
@ -163,34 +163,30 @@ auto PPUfast::readIO(uint address, uint8 data) -> uint8 {
case 0x213d: { //OPVCT case 0x213d: { //OPVCT
if(latch.vcounter == 0) { if(latch.vcounter == 0) {
latch.vcounter = 1; latch.vcounter = 1;
bits(latch.ppu2.mdr,0-7) = bits(io.vcounter,0-7); latch.ppu2.mdr = io.vcounter;
} else { } else {
latch.vcounter = 0; latch.vcounter = 0;
bit1(latch.ppu2.mdr,0) = bit1(io.vcounter,8); latch.ppu2.mdr = io.vcounter >> 8 | latch.ppu2.mdr & 0xfe;
} }
return latch.ppu2.mdr; return latch.ppu2.mdr;
} }
case 0x213e: { //STAT77 case 0x213e: { //STAT77
bits(latch.ppu1.mdr,0-3) = 1; //PPU1 version latch.ppu1.mdr = 0x01 | io.obj.rangeOver << 6 | io.obj.timeOver << 7;
bit1(latch.ppu1.mdr,5) = 0;
bit1(latch.ppu1.mdr,6) = io.obj.rangeOver;
bit1(latch.ppu1.mdr,7) = io.obj.timeOver;
return latch.ppu1.mdr; return latch.ppu1.mdr;
} }
case 0x213f: { //STAT78 case 0x213f: { //STAT78
latch.hcounter = 0; latch.hcounter = 0;
latch.vcounter = 0; latch.vcounter = 0;
bits(latch.ppu2.mdr,0-3) = 3; //PPU2 version latch.ppu2.mdr &= 1 << 5;
bit1(latch.ppu2.mdr,4) = Region::PAL(); //0 = NTSC, 1 = PAL latch.ppu2.mdr |= 0x03 | Region::PAL() << 4 | field() << 7;
if(!cbit1(cpu.pio(),7)) { if(!(cpu.pio() & 0x80)) {
bit1(latch.ppu2.mdr,6) = 1; latch.ppu2.mdr |= 1 << 6;
} else { } else {
bit1(latch.ppu2.mdr,6) = latch.counters; latch.ppu2.mdr |= latch.counters << 6;
latch.counters = 0; latch.counters = 0;
} }
bit1(latch.ppu2.mdr,7) = field();
return latch.ppu2.mdr; return latch.ppu2.mdr;
} }
@ -199,22 +195,22 @@ auto PPUfast::readIO(uint address, uint8 data) -> uint8 {
return data; return data;
} }
auto PPUfast::writeIO(uint address, uint8 data) -> void { auto PPU::writeIO(uint address, uint8 data) -> void {
cpu.synchronize(ppufast); cpu.synchronize(ppu);
switch(address & 0xffff) { switch(address & 0xffff) {
case 0x2100: { //INIDISP case 0x2100: { //INIDISP
if(io.displayDisable && cpu.vcounter() == vdisp()) oamAddressReset(); if(io.displayDisable && cpu.vcounter() == vdisp()) oamAddressReset();
io.displayBrightness = bits(data,0-3); io.displayBrightness = data >> 0 & 15;
io.displayDisable = bit1(data,7); io.displayDisable = data >> 7 & 1;
return; return;
} }
case 0x2101: { //OBSEL case 0x2101: { //OBSEL
io.obj.tiledataAddress = bits(data,0-2) << 13; io.obj.tiledataAddress = (data & 7) << 13;
io.obj.nameselect = bits(data,3-4); io.obj.nameselect = data >> 3 & 3;
io.obj.baseSize = bits(data,5-7); io.obj.baseSize = data >> 5 & 7;
return; return;
} }
@ -225,17 +221,17 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
} }
case 0x2103: { //OAMADDH case 0x2103: { //OAMADDH
io.oamBaseAddress = bit1(data,0) << 9 | (io.oamBaseAddress & 0x01fe); io.oamBaseAddress = (data & 1) << 9 | io.oamBaseAddress & 0x01fe;
io.oamPriority = bit1(data,7); io.oamPriority = data >> 7 & 1;
oamAddressReset(); oamAddressReset();
return; return;
} }
case 0x2104: { //OAMDATA case 0x2104: { //OAMDATA
uint1 latchBit = io.oamAddress & 1; bool latchBit = io.oamAddress & 1;
uint10 address = io.oamAddress++; uint address = io.oamAddress++;
if(latchBit == 0) latch.oam = data; if(latchBit == 0) latch.oam = data;
if(bit1(address,9)) { if(address & 0x200) {
writeOAM(address, data); writeOAM(address, data);
} else if(latchBit == 1) { } else if(latchBit == 1) {
writeOAM((address & ~1) + 0, latch.oam); writeOAM((address & ~1) + 0, latch.oam);
@ -246,58 +242,58 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
} }
case 0x2105: { //BGMODE case 0x2105: { //BGMODE
io.bgMode = bits(data,0-2); io.bgMode = data >> 0 & 7;
io.bgPriority = bit1(data,3); io.bgPriority = data >> 3 & 1;
io.bg1.tileSize = bit1(data,4); io.bg1.tileSize = data >> 4 & 1;
io.bg2.tileSize = bit1(data,5); io.bg2.tileSize = data >> 5 & 1;
io.bg3.tileSize = bit1(data,6); io.bg3.tileSize = data >> 6 & 1;
io.bg4.tileSize = bit1(data,7); io.bg4.tileSize = data >> 7 & 1;
updateVideoMode(); updateVideoMode();
return; return;
} }
case 0x2106: { //MOSAIC case 0x2106: { //MOSAIC
io.bg1.mosaicEnable = bit1(data,0); io.bg1.mosaicEnable = data >> 0 & 1;
io.bg2.mosaicEnable = bit1(data,1); io.bg2.mosaicEnable = data >> 1 & 1;
io.bg3.mosaicEnable = bit1(data,2); io.bg3.mosaicEnable = data >> 2 & 1;
io.bg4.mosaicEnable = bit1(data,3); io.bg4.mosaicEnable = data >> 3 & 1;
io.mosaicSize = bits(data,4-7); io.mosaicSize = data >> 4 & 15;
return; return;
} }
case 0x2107: { //BG1SC case 0x2107: { //BG1SC
io.bg1.screenSize = bits(data,0-1); io.bg1.screenSize = data >> 0 & 3;
io.bg1.screenAddress = bits(data,2-7) << 10; io.bg1.screenAddress = data >> 2 << 10;
return; return;
} }
case 0x2108: { //BG2SC case 0x2108: { //BG2SC
io.bg2.screenSize = bits(data,0-1); io.bg2.screenSize = data >> 0 & 3;
io.bg2.screenAddress = bits(data,2-7) << 10; io.bg2.screenAddress = data >> 2 << 10;
return; return;
} }
case 0x2109: { //BG3SC case 0x2109: { //BG3SC
io.bg3.screenSize = bits(data,0-1); io.bg3.screenSize = data >> 0 & 3;
io.bg3.screenAddress = bits(data,2-7) << 10; io.bg3.screenAddress = data >> 2 << 10;
return; return;
} }
case 0x210a: { //BG4SC case 0x210a: { //BG4SC
io.bg4.screenSize = bits(data,0-1); io.bg4.screenSize = data >> 0 & 3;
io.bg4.screenAddress = bits(data,2-7) << 10; io.bg4.screenAddress = data >> 2 << 10;
return; return;
} }
case 0x210b: { //BG12NBA case 0x210b: { //BG12NBA
io.bg1.tiledataAddress = bits(data,0-3) << 12; io.bg1.tiledataAddress = (data & 15) << 12;
io.bg2.tiledataAddress = bits(data,4-7) << 12; io.bg2.tiledataAddress = (data >> 4) << 12;
return; return;
} }
case 0x210c: { //BG34NBA case 0x210c: { //BG34NBA
io.bg3.tiledataAddress = bits(data,0-3) << 12; io.bg3.tiledataAddress = (data & 15) << 12;
io.bg4.tiledataAddress = bits(data,4-7) << 12; io.bg4.tiledataAddress = (data >> 4) << 12;
return; return;
} }
@ -362,8 +358,8 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
case 0x2115: { //VMAIN case 0x2115: { //VMAIN
static const uint size[4] = {1, 32, 128, 128}; static const uint size[4] = {1, 32, 128, 128};
io.vramIncrementSize = size[data & 3]; io.vramIncrementSize = size[data & 3];
io.vramMapping = bits(data,2-3); io.vramMapping = data >> 2 & 3;
io.vramIncrementMode = bit1(data,7); io.vramIncrementMode = data >> 7 & 1;
return; return;
} }
@ -392,9 +388,9 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
} }
case 0x211a: { //M7SEL case 0x211a: { //M7SEL
io.mode7.hflip = bit1(data,0); io.mode7.hflip = data >> 0 & 1;
io.mode7.vflip = bit1(data,1); io.mode7.vflip = data >> 1 & 1;
io.mode7.repeat = bits(data,6-7); io.mode7.repeat = data >> 6 & 3;
return; return;
} }
@ -444,44 +440,44 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
if(io.cgramAddressLatch++ == 0) { if(io.cgramAddressLatch++ == 0) {
latch.cgram = data; latch.cgram = data;
} else { } else {
writeCGRAM(io.cgramAddress++, bits(data,0-6) << 8 | latch.cgram); writeCGRAM(io.cgramAddress++, (data & 0x7f) << 8 | latch.cgram);
} }
return; return;
} }
case 0x2123: { //W12SEL case 0x2123: { //W12SEL
io.bg1.window.oneInvert = bit1(data,0); io.bg1.window.oneInvert = data >> 0 & 1;
io.bg1.window.oneEnable = bit1(data,1); io.bg1.window.oneEnable = data >> 1 & 1;
io.bg1.window.twoInvert = bit1(data,2); io.bg1.window.twoInvert = data >> 2 & 1;
io.bg1.window.twoEnable = bit1(data,3); io.bg1.window.twoEnable = data >> 3 & 1;
io.bg2.window.oneInvert = bit1(data,4); io.bg2.window.oneInvert = data >> 4 & 1;
io.bg2.window.oneEnable = bit1(data,5); io.bg2.window.oneEnable = data >> 5 & 1;
io.bg2.window.twoInvert = bit1(data,6); io.bg2.window.twoInvert = data >> 6 & 1;
io.bg2.window.twoEnable = bit1(data,7); io.bg2.window.twoEnable = data >> 7 & 1;
return; return;
} }
case 0x2124: { //W34SEL case 0x2124: { //W34SEL
io.bg3.window.oneInvert = bit1(data,0); io.bg3.window.oneInvert = data >> 0 & 1;
io.bg3.window.oneEnable = bit1(data,1); io.bg3.window.oneEnable = data >> 1 & 1;
io.bg3.window.twoInvert = bit1(data,2); io.bg3.window.twoInvert = data >> 2 & 1;
io.bg3.window.twoEnable = bit1(data,3); io.bg3.window.twoEnable = data >> 3 & 1;
io.bg4.window.oneInvert = bit1(data,4); io.bg4.window.oneInvert = data >> 4 & 1;
io.bg4.window.oneEnable = bit1(data,5); io.bg4.window.oneEnable = data >> 5 & 1;
io.bg4.window.twoInvert = bit1(data,6); io.bg4.window.twoInvert = data >> 6 & 1;
io.bg4.window.twoEnable = bit1(data,7); io.bg4.window.twoEnable = data >> 7 & 1;
return; return;
} }
case 0x2125: { //WOBJSEL case 0x2125: { //WOBJSEL
io.obj.window.oneInvert = bit1(data,0); io.obj.window.oneInvert = data >> 0 & 1;
io.obj.window.oneEnable = bit1(data,1); io.obj.window.oneEnable = data >> 1 & 1;
io.obj.window.twoInvert = bit1(data,2); io.obj.window.twoInvert = data >> 2 & 1;
io.obj.window.twoEnable = bit1(data,3); io.obj.window.twoEnable = data >> 3 & 1;
io.col.window.oneInvert = bit1(data,4); io.col.window.oneInvert = data >> 4 & 1;
io.col.window.oneEnable = bit1(data,5); io.col.window.oneEnable = data >> 5 & 1;
io.col.window.twoInvert = bit1(data,6); io.col.window.twoInvert = data >> 6 & 1;
io.col.window.twoEnable = bit1(data,7); io.col.window.twoEnable = data >> 7 & 1;
return; return;
} }
@ -506,89 +502,89 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
} }
case 0x212a: { //WBGLOG case 0x212a: { //WBGLOG
io.bg1.window.mask = bits(data,0-1); io.bg1.window.mask = data >> 0 & 3;
io.bg2.window.mask = bits(data,2-3); io.bg2.window.mask = data >> 2 & 3;
io.bg3.window.mask = bits(data,4-5); io.bg3.window.mask = data >> 4 & 3;
io.bg4.window.mask = bits(data,6-7); io.bg4.window.mask = data >> 6 & 3;
return; return;
} }
case 0x212b: { //WOBJLOG case 0x212b: { //WOBJLOG
io.obj.window.mask = bits(data,0-1); io.obj.window.mask = data >> 0 & 3;
io.col.window.mask = bits(data,2-3); io.col.window.mask = data >> 2 & 3;
return; return;
} }
case 0x212c: { //TM case 0x212c: { //TM
io.bg1.aboveEnable = bit1(data,0); io.bg1.aboveEnable = data >> 0 & 1;
io.bg2.aboveEnable = bit1(data,1); io.bg2.aboveEnable = data >> 1 & 1;
io.bg3.aboveEnable = bit1(data,2); io.bg3.aboveEnable = data >> 2 & 1;
io.bg4.aboveEnable = bit1(data,3); io.bg4.aboveEnable = data >> 3 & 1;
io.obj.aboveEnable = bit1(data,4); io.obj.aboveEnable = data >> 4 & 1;
return; return;
} }
case 0x212d: { //TS case 0x212d: { //TS
io.bg1.belowEnable = bit1(data,0); io.bg1.belowEnable = data >> 0 & 1;
io.bg2.belowEnable = bit1(data,1); io.bg2.belowEnable = data >> 1 & 1;
io.bg3.belowEnable = bit1(data,2); io.bg3.belowEnable = data >> 2 & 1;
io.bg4.belowEnable = bit1(data,3); io.bg4.belowEnable = data >> 3 & 1;
io.obj.belowEnable = bit1(data,4); io.obj.belowEnable = data >> 4 & 1;
return; return;
} }
case 0x212e: { //TMW case 0x212e: { //TMW
io.bg1.window.aboveEnable = bit1(data,0); io.bg1.window.aboveEnable = data >> 0 & 1;
io.bg2.window.aboveEnable = bit1(data,1); io.bg2.window.aboveEnable = data >> 1 & 1;
io.bg3.window.aboveEnable = bit1(data,2); io.bg3.window.aboveEnable = data >> 2 & 1;
io.bg4.window.aboveEnable = bit1(data,3); io.bg4.window.aboveEnable = data >> 3 & 1;
io.obj.window.aboveEnable = bit1(data,4); io.obj.window.aboveEnable = data >> 4 & 1;
return; return;
} }
case 0x212f: { //TSW case 0x212f: { //TSW
io.bg1.window.belowEnable = bit1(data,0); io.bg1.window.belowEnable = data >> 0 & 1;
io.bg2.window.belowEnable = bit1(data,1); io.bg2.window.belowEnable = data >> 1 & 1;
io.bg3.window.belowEnable = bit1(data,2); io.bg3.window.belowEnable = data >> 2 & 1;
io.bg4.window.belowEnable = bit1(data,3); io.bg4.window.belowEnable = data >> 3 & 1;
io.obj.window.belowEnable = bit1(data,4); io.obj.window.belowEnable = data >> 4 & 1;
return; return;
} }
case 0x2130: { //CGWSEL case 0x2130: { //CGWSEL
io.col.directColor = bit1(data,0); io.col.directColor = data >> 0 & 1;
io.col.blendMode = bit1(data,1); io.col.blendMode = data >> 1 & 1;
io.col.window.belowMask = bits(data,4-5); io.col.window.belowMask = data >> 4 & 3;
io.col.window.aboveMask = bits(data,6-7); io.col.window.aboveMask = data >> 6 & 3;
return; return;
} }
case 0x2131: { //CGADDSUB case 0x2131: { //CGADDSUB
io.col.enable[Source::BG1 ] = bit1(data,0); io.col.enable[Source::BG1 ] = data >> 0 & 1;
io.col.enable[Source::BG2 ] = bit1(data,1); io.col.enable[Source::BG2 ] = data >> 1 & 1;
io.col.enable[Source::BG3 ] = bit1(data,2); io.col.enable[Source::BG3 ] = data >> 2 & 1;
io.col.enable[Source::BG4 ] = bit1(data,3); io.col.enable[Source::BG4 ] = data >> 3 & 1;
io.col.enable[Source::OBJ1] = 0; io.col.enable[Source::OBJ1] = 0;
io.col.enable[Source::OBJ2] = bit1(data,4); io.col.enable[Source::OBJ2] = data >> 4 & 1;
io.col.enable[Source::COL ] = bit1(data,5); io.col.enable[Source::COL ] = data >> 5 & 1;
io.col.halve = bit1(data,6); io.col.halve = data >> 6 & 1;
io.col.mathMode = bit1(data,7); io.col.mathMode = data >> 7 & 1;
return; return;
} }
case 0x2132: { //COLDATA case 0x2132: { //COLDATA
if(bit1(data,5)) bits(io.col.fixedColor, 0- 4) = data & 31; if(data & 0x20) io.col.fixedColor = io.col.fixedColor & 0b11111'11111'00000 | (data & 31) << 0;
if(bit1(data,6)) bits(io.col.fixedColor, 5- 9) = data & 31; if(data & 0x40) io.col.fixedColor = io.col.fixedColor & 0b11111'00000'11111 | (data & 31) << 5;
if(bit1(data,7)) bits(io.col.fixedColor,10-14) = data & 31; if(data & 0x80) io.col.fixedColor = io.col.fixedColor & 0b00000'11111'11111 | (data & 31) << 10;
return; return;
} }
case 0x2133: { //SETINI case 0x2133: { //SETINI
io.interlace = bit1(data,0); io.interlace = data >> 0 & 1;
io.obj.interlace = bit1(data,1); io.obj.interlace = data >> 1 & 1;
io.overscan = bit1(data,2); io.overscan = data >> 2 & 1;
io.pseudoHires = bit1(data,3); io.pseudoHires = data >> 3 & 1;
io.extbg = bit1(data,6); io.extbg = data >> 6 & 1;
updateVideoMode(); updateVideoMode();
return; return;
} }
@ -596,7 +592,7 @@ auto PPUfast::writeIO(uint address, uint8 data) -> void {
} }
} }
auto PPUfast::updateVideoMode() -> void { auto PPU::updateVideoMode() -> void {
ppubase.display.vdisp = !io.overscan ? 225 : 240; ppubase.display.vdisp = !io.overscan ? 225 : 240;
switch(io.bgMode) { switch(io.bgMode) {

View File

@ -1,29 +1,29 @@
uint PPUfast::Line::start = 0; uint PPU::Line::start = 0;
uint PPUfast::Line::count = 0; uint PPU::Line::count = 0;
auto PPUfast::Line::flush() -> void { auto PPU::Line::flush() -> void {
if(Line::count) { if(Line::count) {
#pragma omp parallel for if(Line::count >= 8) #pragma omp parallel for if(Line::count >= 8)
for(uint y = 0; y < Line::count; y++) { for(uint y = 0; y < Line::count; y++) {
ppufast.lines[Line::start + y].render(); ppu.lines[Line::start + y].render();
} }
Line::start = 0; Line::start = 0;
Line::count = 0; Line::count = 0;
} }
} }
auto PPUfast::Line::render() -> void { auto PPU::Line::render() -> void {
uint y = this->y + (!ppufast.latch.overscan ? 7 : 0); uint y = this->y + (!ppu.latch.overscan ? 7 : 0);
auto hd = ppufast.hd(); auto hd = ppu.hd();
auto ss = ppufast.ss(); auto ss = ppu.ss();
auto scale = ppufast.hdScale(); auto scale = ppu.hdScale();
auto output = ppufast.output + (!hd auto output = ppu.output + (!hd
? (y * 1024 + (ppufast.interlace() && ppufast.field() ? 512 : 0)) ? (y * 1024 + (ppu.interlace() && ppu.field() ? 512 : 0))
: (y * 256 * scale * scale) : (y * 256 * scale * scale)
); );
auto width = (!hd auto width = (!hd
? (!ppufast.hires() ? 256 : 512) ? (!ppu.hires() ? 256 : 512)
: (256 * scale * scale)); : (256 * scale * scale));
if(io.displayDisable) { if(io.displayDisable) {
@ -33,9 +33,9 @@ auto PPUfast::Line::render() -> void {
bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6;
auto aboveColor = cgram[0]; auto aboveColor = cgram[0];
auto belowColor = hires ? cgram[0] : (uint16)io.col.fixedColor; auto belowColor = hires ? cgram[0] : (uint16_t)io.col.fixedColor;
uint xa = (hd || ss) && ppufast.interlace() && ppufast.field() ? 256 * scale * scale / 2 : 0; uint xa = (hd || ss) && ppu.interlace() && ppu.field() ? 256 * scale * scale / 2 : 0;
uint xb = !(hd || ss) ? 256 : ppufast.interlace() && !ppufast.field() ? 256 * scale * scale / 2 : 256 * scale * scale; uint xb = !(hd || ss) ? 256 : ppu.interlace() && !ppu.field() ? 256 * scale * scale / 2 : 256 * scale * scale;
for(uint x = xa; x < xb; x++) { for(uint x = xa; x < xb; x++) {
above[x] = {Source::COL, 0, aboveColor}; above[x] = {Source::COL, 0, aboveColor};
below[x] = {Source::COL, 0, belowColor}; below[x] = {Source::COL, 0, belowColor};
@ -49,7 +49,7 @@ auto PPUfast::Line::render() -> void {
renderWindow(io.col.window, io.col.window.aboveMask, windowAbove); renderWindow(io.col.window, io.col.window.aboveMask, windowAbove);
renderWindow(io.col.window, io.col.window.belowMask, windowBelow); renderWindow(io.col.window, io.col.window.belowMask, windowBelow);
auto luma = ppufast.lightTable[io.displayBrightness]; auto luma = ppu.lightTable[io.displayBrightness];
uint curr = 0, prev = 0; uint curr = 0, prev = 0;
if(hd) for(uint x : range(256 * scale * scale)) { if(hd) for(uint x : range(256 * scale * scale)) {
*output++ = luma[pixel(x / scale & 255, above[x], below[x])]; *output++ = luma[pixel(x / scale & 255, above[x], below[x])];
@ -72,7 +72,7 @@ auto PPUfast::Line::render() -> void {
} }
} }
auto PPUfast::Line::pixel(uint x, Pixel above, Pixel below) const -> uint16 { auto PPU::Line::pixel(uint x, Pixel above, Pixel below) const -> uint16_t {
if(!windowAbove[x]) above.color = 0x0000; if(!windowAbove[x]) above.color = 0x0000;
if(!windowBelow[x]) return above.color; if(!windowBelow[x]) return above.color;
if(!io.col.enable[above.source]) return above.color; if(!io.col.enable[above.source]) return above.color;
@ -80,7 +80,7 @@ auto PPUfast::Line::pixel(uint x, Pixel above, Pixel below) const -> uint16 {
return blend(above.color, below.color, io.col.halve && windowAbove[x] && below.source != Source::COL); return blend(above.color, below.color, io.col.halve && windowAbove[x] && below.source != Source::COL);
} }
auto PPUfast::Line::blend(uint x, uint y, bool halve) const -> uint16 { auto PPU::Line::blend(uint x, uint y, bool halve) const -> uint16_t {
if(!io.col.mathMode) { //add if(!io.col.mathMode) { //add
if(!halve) { if(!halve) {
uint sum = x + y; uint sum = x + y;
@ -100,7 +100,7 @@ auto PPUfast::Line::blend(uint x, uint y, bool halve) const -> uint16 {
} }
} }
auto PPUfast::Line::directColor(uint paletteIndex, uint paletteColor) const -> uint16 { auto PPU::Line::directColor(uint paletteIndex, uint paletteColor) const -> uint16_t {
//paletteIndex = bgr //paletteIndex = bgr
//paletteColor = BBGGGRRR //paletteColor = BBGGGRRR
//output = 0 BBb00 GGGg0 RRRr0 //output = 0 BBb00 GGGg0 RRRr0
@ -109,25 +109,25 @@ auto PPUfast::Line::directColor(uint paletteIndex, uint paletteColor) const -> u
+ (paletteColor << 7 & 0x6000) + (paletteIndex << 10 & 0x1000); //B + (paletteColor << 7 & 0x6000) + (paletteIndex << 10 & 0x1000); //B
} }
auto PPUfast::Line::plotAbove(uint x, uint source, uint priority, uint color) -> void { auto PPU::Line::plotAbove(uint x, uint source, uint priority, uint color) -> void {
if(ppufast.hd()) return plotHD(above, x, source, priority, color, false, false); if(ppu.hd()) return plotHD(above, x, source, priority, color, false, false);
if(priority > above[x].priority) above[x] = {source, priority, color}; if(priority > above[x].priority) above[x] = {source, priority, color};
} }
auto PPUfast::Line::plotBelow(uint x, uint source, uint priority, uint color) -> void { auto PPU::Line::plotBelow(uint x, uint source, uint priority, uint color) -> void {
if(ppufast.hd()) return plotHD(below, x, source, priority, color, false, false); if(ppu.hd()) return plotHD(below, x, source, priority, color, false, false);
if(priority > below[x].priority) below[x] = {source, priority, color}; if(priority > below[x].priority) below[x] = {source, priority, color};
} }
//todo: name these variables more clearly ... //todo: name these variables more clearly ...
auto PPUfast::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void { auto PPU::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void {
auto scale = ppufast.hdScale(); auto scale = ppu.hdScale();
int xss = hires && subpixel ? scale / 2 : 0; int xss = hires && subpixel ? scale / 2 : 0;
int ys = ppufast.interlace() && ppufast.field() ? scale / 2 : 0; int ys = ppu.interlace() && ppu.field() ? scale / 2 : 0;
if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) { if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) {
Pixel p = {source, priority, color}; Pixel p = {source, priority, color};
int xsm = hires && !subpixel ? scale / 2 : scale; int xsm = hires && !subpixel ? scale / 2 : scale;
int ysm = ppufast.interlace() && !ppufast.field() ? scale / 2 : scale; int ysm = ppu.interlace() && !ppu.field() ? scale / 2 : scale;
for(int xs = xss; xs < xsm; xs++) { for(int xs = xss; xs < xsm; xs++) {
pixel[x * scale + xs + ys * 256 * scale] = p; pixel[x * scale + xs + ys * 256 * scale] = p;
} }

View File

@ -1,11 +1,11 @@
auto PPUfast::Line::renderMode7(PPUfast::IO::Background& self, uint source) -> void { auto PPU::Line::renderMode7(PPU::IO::Background& self, uint source) -> void {
//EXTBG is only really used by games to give the mode 7 layer two priority levels //EXTBG is only really used by games to give the mode 7 layer two priority levels
//especially with HD mode 7, it's just wasteful to render BG1 just to be overwritten by BG2 //especially with HD mode 7, it's just wasteful to render BG1 just to be overwritten by BG2
if(io.extbg && source == Source::BG1) return; if(io.extbg && source == Source::BG1) return;
//HD mode 7 support //HD mode 7 support
if(!ppufast.hdMosaic() || !self.mosaicEnable || !io.mosaicSize) { if(!ppu.hdMosaic() || !self.mosaicEnable || !io.mosaicSize) {
if(ppufast.hdScale() > 1) return renderMode7HD(self, source); if(ppu.hdScale() > 1) return renderMode7HD(self, source);
} }
int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
@ -29,8 +29,8 @@ auto PPUfast::Line::renderMode7(PPUfast::IO::Background& self, uint source) -> v
int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8); int originX = (a * clip(hoffset - hcenter) & ~63) + (b * clip(voffset - vcenter) & ~63) + (b * y & ~63) + (hcenter << 8);
int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8); int originY = (c * clip(hoffset - hcenter) & ~63) + (d * clip(voffset - vcenter) & ~63) + (d * y & ~63) + (vcenter << 8);
array<bool[256]> windowAbove; bool windowAbove[256];
array<bool[256]> windowBelow; bool windowBelow[256];
renderWindow(self.window, self.window.aboveEnable, windowAbove); renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow); renderWindow(self.window, self.window.belowEnable, windowBelow);
@ -43,8 +43,8 @@ auto PPUfast::Line::renderMode7(PPUfast::IO::Background& self, uint source) -> v
bool outOfBounds = (pixelX | pixelY) & ~1023; bool outOfBounds = (pixelX | pixelY) & ~1023;
uint15 tileAddress = tileY * 128 + tileX; uint15 tileAddress = tileY * 128 + tileX;
uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7); uint15 paletteAddress = ((pixelY & 7) << 3) + (pixelX & 7);
uint8 tile = io.mode7.repeat == 3 && outOfBounds ? 0 : (ppufast.vram[tileAddress] & 0xff); uint8_t tile = io.mode7.repeat == 3 && outOfBounds ? 0 : ppu.vram[tileAddress] >> 0;
uint8 palette = io.mode7.repeat == 2 && outOfBounds ? 0 : (ppufast.vram[paletteAddress + (tile << 6)] >> 8); uint8_t palette = io.mode7.repeat == 2 && outOfBounds ? 0 : ppu.vram[paletteAddress + (tile << 6)] >> 8;
uint priority; uint priority;
if(source == Source::BG1) { if(source == Source::BG1) {

View File

@ -1,6 +1,6 @@
auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) -> void { auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint source) -> void {
const bool extbg = source == Source::BG2; const bool extbg = source == Source::BG2;
const uint scale = ppufast.hdScale(); const uint scale = ppu.hdScale();
Pixel pixel; Pixel pixel;
Pixel* above = &this->above[-1]; Pixel* above = &this->above[-1];
@ -9,10 +9,10 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
//find the first and last scanline for interpolation //find the first and last scanline for interpolation
int y_a = y; int y_a = y;
int y_b = y; int y_b = y;
#define isLineMode7(n) (ppufast.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \ #define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \
(ppufast.lines[n].io.bg1.aboveEnable || ppufast.lines[n].io.bg1.belowEnable) \ (ppu.lines[n].io.bg1.aboveEnable || ppu.lines[n].io.bg1.belowEnable) \
)) ))
if(ppufast.hdPerspective()) { if(ppu.hdPerspective()) {
while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a += 1; while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a += 1;
while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b -= 8; while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b -= 8;
} else { } else {
@ -21,13 +21,13 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
} }
#undef isLineMode7 #undef isLineMode7
Line line_a = ppufast.lines[y_a]; Line line_a = ppu.lines[y_a];
float a_a = (int16)line_a.io.mode7.a; float a_a = (int16)line_a.io.mode7.a;
float b_a = (int16)line_a.io.mode7.b; float b_a = (int16)line_a.io.mode7.b;
float c_a = (int16)line_a.io.mode7.c; float c_a = (int16)line_a.io.mode7.c;
float d_a = (int16)line_a.io.mode7.d; float d_a = (int16)line_a.io.mode7.d;
Line line_b = ppufast.lines[y_b]; Line line_b = ppu.lines[y_b];
float a_b = (int16)line_b.io.mode7.a; float a_b = (int16)line_b.io.mode7.a;
float b_b = (int16)line_b.io.mode7.b; float b_b = (int16)line_b.io.mode7.b;
float c_b = (int16)line_b.io.mode7.c; float c_b = (int16)line_b.io.mode7.c;
@ -43,8 +43,8 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
y_b = 255 - y_b; y_b = 255 - y_b;
} }
array<bool[256]> windowAbove; bool windowAbove[256];
array<bool[256]> windowBelow; bool windowBelow[256];
renderWindow(self.window, self.window.aboveEnable, windowAbove); renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow); renderWindow(self.window, self.window.belowEnable, windowBelow);
@ -80,8 +80,8 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
//only compute color again when coordinates have changed //only compute color again when coordinates have changed
if(pixelX != pixelXp || pixelY != pixelYp) { if(pixelX != pixelXp || pixelY != pixelYp) {
uint tile = io.mode7.repeat == 3 && ((pixelX | pixelY) & ~1023) ? 0 : (ppufast.vram[(pixelY >> 3 & 127) * 128 + (pixelX >> 3 & 127)] & 0xff); uint tile = io.mode7.repeat == 3 && ((pixelX | pixelY) & ~1023) ? 0 : (ppu.vram[(pixelY >> 3 & 127) * 128 + (pixelX >> 3 & 127)] & 0xff);
uint palette = io.mode7.repeat == 2 && ((pixelX | pixelY) & ~1023) ? 0 : (ppufast.vram[(((pixelY & 7) << 3) + (pixelX & 7)) + (tile << 6)] >> 8); uint palette = io.mode7.repeat == 2 && ((pixelX | pixelY) & ~1023) ? 0 : (ppu.vram[(((pixelY & 7) << 3) + (pixelX & 7)) + (tile << 6)] >> 8);
uint priority; uint priority;
if(!extbg) { if(!extbg) {
@ -110,7 +110,7 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
} }
} }
if(ppufast.ss()) { if(ppu.ss()) {
uint divisor = scale * scale; uint divisor = scale * scale;
for(uint p : range(256)) { for(uint p : range(256)) {
uint ab = 0, bb = 0; uint ab = 0, bb = 0;
@ -139,7 +139,7 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
} }
//interpolation and extrapolation //interpolation and extrapolation
auto PPUfast::Line::lerp(float pa, float va, float pb, float vb, float pr) -> float { auto PPU::Line::lerp(float pa, float va, float pb, float vb, float pr) -> float {
if(va == vb || pr == pa) return va; if(va == vb || pr == pa) return va;
if(pr == pb) return vb; if(pr == pb) return vb;
return va + (vb - va) / (pb - pa) * (pr - pa); return va + (vb - va) / (pb - pa) * (pr - pa);

View File

@ -1,19 +1,19 @@
auto PPUfast::Line::renderObject(PPUfast::IO::Object& self) -> void { auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
if(!self.aboveEnable && !self.belowEnable) return; if(!self.aboveEnable && !self.belowEnable) return;
array<bool[256]> windowAbove; bool windowAbove[256];
array<bool[256]> windowBelow; bool windowBelow[256];
renderWindow(self.window, self.window.aboveEnable, windowAbove); renderWindow(self.window, self.window.aboveEnable, windowAbove);
renderWindow(self.window, self.window.belowEnable, windowBelow); renderWindow(self.window, self.window.belowEnable, windowBelow);
uint itemCount = 0; uint itemCount = 0;
uint tileCount = 0; uint tileCount = 0;
for(auto n : range(ppufast.ItemLimit)) items[n].valid = false; for(auto n : range(ppu.ItemLimit)) items[n].valid = false;
for(auto n : range(ppufast.TileLimit)) tiles[n].valid = false; for(auto n : range(ppu.TileLimit)) tiles[n].valid = false;
for(auto n : range(128)) { for(auto n : range(128)) {
ObjectItem item{true, self.first + n}; ObjectItem item{true, self.first + n};
const auto& object = ppufast.objects[item.index]; const auto& object = ppu.objects[item.index];
if(object.size == 0) { if(object.size == 0) {
static const uint widths[] = { 8, 8, 8, 16, 16, 32, 16, 16}; static const uint widths[] = { 8, 8, 8, 16, 16, 32, 16, 16};
@ -33,16 +33,16 @@ auto PPUfast::Line::renderObject(PPUfast::IO::Object& self) -> void {
if((y >= object.y && y < object.y + height) if((y >= object.y && y < object.y + height)
|| (object.y + height >= 256 && y < (object.y + height & 255)) || (object.y + height >= 256 && y < (object.y + height & 255))
) { ) {
if(itemCount++ >= ppufast.ItemLimit) break; if(itemCount++ >= ppu.ItemLimit) break;
items[itemCount - 1] = item; items[itemCount - 1] = item;
} }
} }
for(int n : reverse(range(ppufast.ItemLimit))) { for(int n : reverse(range(ppu.ItemLimit))) {
const auto& item = items[n]; const auto& item = items[n];
if(!item.valid) continue; if(!item.valid) continue;
const auto& object = ppufast.objects[item.index]; const auto& object = ppu.objects[item.index];
uint tileWidth = item.width >> 3; uint tileWidth = item.width >> 3;
int x = object.x; int x = object.x;
int y = this->y - object.y & 0xff; int y = this->y - object.y & 0xff;
@ -59,7 +59,7 @@ auto PPUfast::Line::renderObject(PPUfast::IO::Object& self) -> void {
} }
if(self.interlace) { if(self.interlace) {
y = !object.vflip ? y + ppufast.field() : y - ppufast.field(); y = !object.vflip ? y + ppu.field() : y - ppu.field();
} }
x &= 511; x &= 511;
@ -85,22 +85,22 @@ auto PPUfast::Line::renderObject(PPUfast::IO::Object& self) -> void {
uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4); uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4);
tile.number = address >> 4; tile.number = address >> 4;
if(tileCount++ >= ppufast.TileLimit) break; if(tileCount++ >= ppu.TileLimit) break;
tiles[tileCount - 1] = tile; tiles[tileCount - 1] = tile;
} }
} }
ppufast.io.obj.rangeOver |= itemCount > ppufast.ItemLimit; ppu.io.obj.rangeOver |= itemCount > ppu.ItemLimit;
ppufast.io.obj.timeOver |= tileCount > ppufast.TileLimit; ppu.io.obj.timeOver |= tileCount > ppu.TileLimit;
uint8 palette[256] = {}; uint8_t palette[256] = {};
uint8 priority[256] = {}; uint8_t priority[256] = {};
for(uint n : range(ppufast.TileLimit)) { for(uint n : range(ppu.TileLimit)) {
const auto& tile = tiles[n]; const auto& tile = tiles[n];
if(!tile.valid) continue; if(!tile.valid) continue;
auto tiledata = ppufast.tilecache[TileMode::BPP4] + (tile.number << 6) + ((tile.y & 7) << 3); auto tiledata = ppu.tilecache[TileMode::BPP4] + (tile.number << 6) + ((tile.y & 7) << 3);
uint tileX = tile.x; uint tileX = tile.x;
uint mirrorX = tile.hflip ? 7 : 0; uint mirrorX = tile.hflip ? 7 : 0;
for(uint x : range(8)) { for(uint x : range(8)) {
@ -123,16 +123,16 @@ auto PPUfast::Line::renderObject(PPUfast::IO::Object& self) -> void {
} }
} }
auto PPUfast::oamAddressReset() -> void { auto PPU::oamAddressReset() -> void {
io.oamAddress = io.oamBaseAddress; io.oamAddress = io.oamBaseAddress;
oamSetFirstObject(); oamSetFirstObject();
} }
auto PPUfast::oamSetFirstObject() -> void { auto PPU::oamSetFirstObject() -> void {
io.obj.first = !io.oamPriority ? 0 : uint(io.oamAddress >> 2); io.obj.first = !io.oamPriority ? 0 : io.oamAddress >> 2;
} }
auto PPUfast::readObject(uint10 address) -> uint8 { auto PPU::readObject(uint10 address) -> uint8 {
if(!(address & 0x200)) { if(!(address & 0x200)) {
uint n = address >> 2; //object# uint n = address >> 2; //object#
address &= 3; address &= 3;
@ -161,7 +161,7 @@ auto PPUfast::readObject(uint10 address) -> uint8 {
} }
} }
auto PPUfast::writeObject(uint10 address, uint8 data) -> void { auto PPU::writeObject(uint10 address, uint8 data) -> void {
if(!(address & 0x200)) { if(!(address & 0x200)) {
uint n = address >> 2; //object# uint n = address >> 2; //object#
address &= 3; address &= 3;

View File

@ -4,7 +4,10 @@ namespace SuperFamicom {
PPU& ppubase = ppu; PPU& ppubase = ppu;
PPUfast ppufast; #define PPU PPUfast
#define ppu ppufast
PPU ppu;
#include "io.cpp" #include "io.cpp"
#include "line.cpp" #include "line.cpp"
#include "background.cpp" #include "background.cpp"
@ -14,18 +17,20 @@ PPUfast ppufast;
#include "window.cpp" #include "window.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto PPUfast::interlace() const -> bool { return ppubase.display.interlace; } auto PPU::interlace() const -> bool { return ppubase.display.interlace; }
auto PPUfast::overscan() const -> bool { return ppubase.display.overscan; } auto PPU::overscan() const -> bool { return ppubase.display.overscan; }
auto PPUfast::vdisp() const -> uint { return ppubase.display.vdisp; } auto PPU::vdisp() const -> uint { return ppubase.display.vdisp; }
auto PPUfast::hires() const -> bool { return latch.hires; } auto PPU::hires() const -> bool { return latch.hires; }
auto PPUfast::hd() const -> bool { return latch.hd; } auto PPU::hd() const -> bool { return latch.hd; }
auto PPUfast::ss() const -> bool { return latch.ss; } auto PPU::ss() const -> bool { return latch.ss; }
auto PPUfast::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; } #undef ppu
auto PPUfast::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; } auto PPU::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; }
auto PPUfast::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; } auto PPU::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; }
auto PPUfast::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; } auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; }
auto PPU::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; }
#define ppu ppufast
PPUfast::PPUfast() { PPU::PPU() {
for(uint l : range(16)) { for(uint l : range(16)) {
for(uint r : range(32)) { for(uint r : range(32)) {
for(uint g : range(32)) { for(uint g : range(32)) {
@ -34,38 +39,38 @@ PPUfast::PPUfast() {
uint ar = (luma * r + 0.5); uint ar = (luma * r + 0.5);
uint ag = (luma * g + 0.5); uint ag = (luma * g + 0.5);
uint ab = (luma * b + 0.5); uint ab = (luma * b + 0.5);
lightTable[l][(r << 10) + (g << 5) + b] = (ab << 10) + (ag << 5) + ar; lightTable[l][r << 10 | g << 5 | b << 0] = ab << 10 | ag << 5 | ar << 0;
} }
} }
} }
} }
tilecache[TileMode::BPP2] = new uint8[4096 * 8 * 8]; tilecache[TileMode::BPP2] = new uint8_t[4096 * 8 * 8];
tilecache[TileMode::BPP4] = new uint8[2048 * 8 * 8]; tilecache[TileMode::BPP4] = new uint8_t[2048 * 8 * 8];
tilecache[TileMode::BPP8] = new uint8[1024 * 8 * 8]; tilecache[TileMode::BPP8] = new uint8_t[1024 * 8 * 8];
for(uint y : range(lines.size())) { for(uint y : range(240)) {
lines[y].y = y; lines[y].y = y;
} }
} }
PPUfast::~PPUfast() { PPU::~PPU() {
delete[] tilecache[TileMode::BPP2]; delete[] tilecache[TileMode::BPP2];
delete[] tilecache[TileMode::BPP4]; delete[] tilecache[TileMode::BPP4];
delete[] tilecache[TileMode::BPP8]; delete[] tilecache[TileMode::BPP8];
} }
auto PPUfast::Enter() -> void { auto PPU::Enter() -> void {
while(true) scheduler.synchronize(), ppufast.main(); while(true) scheduler.synchronize(), ppu.main();
} }
auto PPUfast::step(uint clocks) -> void { auto PPU::step(uint clocks) -> void {
tick(clocks); tick(clocks);
Thread::step(clocks); Thread::step(clocks);
synchronize(cpu); synchronize(cpu);
} }
auto PPUfast::main() -> void { auto PPU::main() -> void {
scanline(); scanline();
if(system.frameCounter == 0) { if(system.frameCounter == 0) {
@ -86,7 +91,7 @@ auto PPUfast::main() -> void {
step(lineclocks() - hcounter()); step(lineclocks() - hcounter());
} }
auto PPUfast::scanline() -> void { auto PPU::scanline() -> void {
if(vcounter() == 0) { if(vcounter() == 0) {
ppubase.display.interlace = io.interlace; ppubase.display.interlace = io.interlace;
ppubase.display.overscan = io.overscan; ppubase.display.overscan = io.overscan;
@ -114,7 +119,7 @@ auto PPUfast::scanline() -> void {
} }
} }
auto PPUfast::refresh() -> void { auto PPU::refresh() -> void {
if(system.frameCounter == 0) { if(system.frameCounter == 0) {
auto output = this->output; auto output = this->output;
uint pitch, width, height; uint pitch, width, height;
@ -148,17 +153,17 @@ auto PPUfast::refresh() -> void {
if(system.frameCounter++ >= system.frameSkip) system.frameCounter = 0; if(system.frameCounter++ >= system.frameSkip) system.frameCounter = 0;
} }
auto PPUfast::load() -> bool { auto PPU::load() -> bool {
return true; return true;
} }
auto PPUfast::power(bool reset) -> void { auto PPU::power(bool reset) -> void {
create(Enter, system.cpuFrequency()); Thread::create(Enter, system.cpuFrequency());
PPUcounter::reset(); PPUcounter::reset();
memory::fill<uint16>(output, 1024 * 960); memory::fill<uint16>(output, 1024 * 960);
function<auto (uint, uint8) -> uint8> reader{&PPUfast::readIO, this}; function<uint8 (uint, uint8)> reader{&PPU::readIO, this};
function<auto (uint, uint8) -> void> writer{&PPUfast::writeIO, this}; function<void (uint, uint8)> writer{&PPU::writeIO, this};
bus.map(reader, writer, "00-3f,80-bf:2100-213f"); bus.map(reader, writer, "00-3f,80-bf:2100-213f");
if(!reset) { if(!reset) {
@ -174,6 +179,7 @@ auto PPUfast::power(bool reset) -> void {
io = {}; io = {};
updateVideoMode(); updateVideoMode();
#undef ppu
ItemLimit = !configuration.hacks.ppu.noSpriteLimit ? 32 : 128; ItemLimit = !configuration.hacks.ppu.noSpriteLimit ? 32 : 128;
TileLimit = !configuration.hacks.ppu.noSpriteLimit ? 34 : 128; TileLimit = !configuration.hacks.ppu.noSpriteLimit ? 34 : 128;

View File

@ -5,7 +5,9 @@
//* vertical mosaic coordinates are not exact //* vertical mosaic coordinates are not exact
//* (hardware-mod) 128KB VRAM mode not supported //* (hardware-mod) 128KB VRAM mode not supported
struct PPUfast : Thread, PPUcounter { #define PPU PPUfast
struct PPU : Thread, PPUcounter {
alwaysinline auto interlace() const -> bool; alwaysinline auto interlace() const -> bool;
alwaysinline auto overscan() const -> bool; alwaysinline auto overscan() const -> bool;
alwaysinline auto vdisp() const -> uint; alwaysinline auto vdisp() const -> uint;
@ -18,8 +20,8 @@ struct PPUfast : Thread, PPUcounter {
alwaysinline auto hdMosaic() const -> bool; alwaysinline auto hdMosaic() const -> bool;
//ppu.cpp //ppu.cpp
PPUfast(); PPU();
~PPUfast(); ~PPU();
static auto Enter() -> void; static auto Enter() -> void;
alwaysinline auto step(uint clocks) -> void; alwaysinline auto step(uint clocks) -> void;
@ -47,24 +49,24 @@ public:
bool hd = 0; bool hd = 0;
bool ss = 0; bool ss = 0;
uint16 vram = 0; uint16_t vram = 0;
uint8 oam = 0; uint8_t oam = 0;
uint8 cgram = 0; uint8_t cgram = 0;
uint10 oamAddress = 0; uint10 oamAddress = 0;
uint8 cgramAddress = 0; uint8_t cgramAddress = 0;
uint8 mode7 = 0; uint8_t mode7 = 0;
bool counters = 0; bool counters = 0;
bool hcounter = 0; //hdot bool hcounter = 0; //hdot
bool vcounter = 0; bool vcounter = 0;
struct PPU { struct PPUstate {
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
uint8 mdr = 0; uint8_t mdr = 0;
uint8 bgofs = 0; uint8_t bgofs = 0;
} ppu1, ppu2; } ppu1, ppu2;
}; };
@ -114,10 +116,10 @@ public:
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
uint8 oneLeft = 0; uint8_t oneLeft = 0;
uint8 oneRight = 0; uint8_t oneRight = 0;
uint8 twoLeft = 0; uint8_t twoLeft = 0;
uint8 twoRight = 0; uint8_t twoRight = 0;
} window; } window;
struct WindowLayer { struct WindowLayer {
@ -200,8 +202,8 @@ public:
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
uint9 x = 0; uint9 x = 0;
uint8 y = 0; uint8_t y = 0;
uint8 character = 0; uint8_t character = 0;
bool nameselect = 0; bool nameselect = 0;
bool vflip = 0; bool vflip = 0;
bool hflip = 0; bool hflip = 0;
@ -213,16 +215,16 @@ public:
struct ObjectItem { struct ObjectItem {
bool valid = 0; bool valid = 0;
uint7 index = 0; uint7 index = 0;
uint8 width = 0; uint8_t width = 0;
uint8 height = 0; uint8_t height = 0;
}; };
struct ObjectTile { struct ObjectTile {
bool valid = 0; bool valid = 0;
uint9 x = 0; uint9 x = 0;
uint8 y = 0; uint8_t y = 0;
uint2 priority = 0; uint2 priority = 0;
uint8 palette = 0; uint8_t palette = 0;
bool hflip = 0; bool hflip = 0;
uint11 number = 0; uint11 number = 0;
}; };
@ -235,14 +237,14 @@ public:
//io.cpp //io.cpp
auto latchCounters() -> void; auto latchCounters() -> void;
alwaysinline auto vramAddress() const -> uint15; alwaysinline auto vramAddress() const -> uint;
alwaysinline auto readVRAM() -> uint16; alwaysinline auto readVRAM() -> uint16;
template<bool Byte> alwaysinline auto writeVRAM(uint8 data) -> void; template<bool Byte> alwaysinline auto writeVRAM(uint8_t data) -> void;
alwaysinline auto updateTiledata(uint address) -> void; alwaysinline auto updateTiledata(uint address) -> void;
alwaysinline auto readOAM(uint10 address) -> uint8; alwaysinline auto readOAM(uint10 address) -> uint8;
alwaysinline auto writeOAM(uint10 address, uint8 data) -> void; alwaysinline auto writeOAM(uint10 address, uint8_t data) -> void;
template<bool Byte> alwaysinline auto readCGRAM(uint8 address) -> uint8; template<bool Byte> alwaysinline auto readCGRAM(uint8_t address) -> uint8;
alwaysinline auto writeCGRAM(uint8 address, uint15 data) -> void; alwaysinline auto writeCGRAM(uint8_t address, uint15 data) -> void;
auto readIO(uint address, uint8 data) -> uint8; auto readIO(uint address, uint8 data) -> uint8;
auto writeIO(uint address, uint8 data) -> void; auto writeIO(uint address, uint8 data) -> void;
auto updateVideoMode() -> void; auto updateVideoMode() -> void;
@ -257,14 +259,14 @@ public:
Latch latch; Latch latch;
IO io; IO io;
uint16 vram[32 * 1024] = {}; uint16_t vram[32 * 1024] = {};
uint16 cgram[256] = {}; uint16_t cgram[256] = {};
Object objects[128] = {}; Object objects[128] = {};
//[unserialized] //[unserialized]
uint16 output[2304 * 2160] = {}; uint16_t output[2304 * 2160] = {};
uint16 lightTable[16][32768] = {}; uint16_t lightTable[16][32768] = {};
uint8* tilecache[3] = {}; //bitplane -> bitmap tiledata uint8_t* tilecache[3] = {}; //bitplane -> bitmap tiledata
uint ItemLimit = 0; uint ItemLimit = 0;
uint TileLimit = 0; uint TileLimit = 0;
@ -272,51 +274,51 @@ public:
//line.cpp //line.cpp
static auto flush() -> void; static auto flush() -> void;
auto render() -> void; auto render() -> void;
auto pixel(uint x, Pixel above, Pixel below) const -> uint16; auto pixel(uint x, Pixel above, Pixel below) const -> uint16_t;
auto blend(uint x, uint y, bool halve) const -> uint16; auto blend(uint x, uint y, bool halve) const -> uint16_t;
alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint16; alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint16_t;
alwaysinline auto plotAbove(uint x, uint source, uint priority, uint color) -> void; alwaysinline auto plotAbove(uint x, uint source, uint priority, uint color) -> void;
alwaysinline auto plotBelow(uint x, uint source, uint priority, uint color) -> void; alwaysinline auto plotBelow(uint x, uint source, uint priority, uint color) -> void;
alwaysinline auto plotHD(Pixel*, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void; alwaysinline auto plotHD(Pixel*, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void;
//background.cpp //background.cpp
auto renderBackground(PPUfast::IO::Background&, uint source) -> void; auto renderBackground(PPU::IO::Background&, uint source) -> void;
auto getTile(PPUfast::IO::Background&, uint hoffset, uint voffset) -> uint; auto getTile(PPU::IO::Background&, uint hoffset, uint voffset) -> uint;
//mode7.cpp //mode7.cpp
auto renderMode7(PPUfast::IO::Background&, uint source) -> void; auto renderMode7(PPU::IO::Background&, uint source) -> void;
//mode7hd.cpp //mode7hd.cpp
auto renderMode7HD(PPUfast::IO::Background&, uint source) -> void; auto renderMode7HD(PPU::IO::Background&, uint source) -> void;
alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float; alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float;
//object.cpp //object.cpp
auto renderObject(PPUfast::IO::Object&) -> void; auto renderObject(PPU::IO::Object&) -> void;
//window.cpp //window.cpp
auto renderWindow(PPUfast::IO::WindowLayer&, bool, array<bool[256]>&) -> void; auto renderWindow(PPU::IO::WindowLayer&, bool enable, bool output[256]) -> void;
auto renderWindow(PPUfast::IO::WindowColor&, uint, array<bool[256]>&) -> void; auto renderWindow(PPU::IO::WindowColor&, uint mask, bool output[256]) -> void;
//[unserialized] //[unserialized]
uint9 y; //constant uint9 y; //constant
IO io; IO io;
array<uint16[256]> cgram; uint16_t cgram[256];
array<ObjectItem[128]> items; //32 on real hardware ObjectItem items[128]; //32 on real hardware
array<ObjectTile[128]> tiles; //34 on real hardware; 1024 max (128 * 64-width tiles) ObjectTile tiles[128]; //34 on real hardware; 1024 max (128 * 64-width tiles)
Pixel above[256 * 9 * 9]; Pixel above[256 * 9 * 9];
Pixel below[256 * 9 * 9]; Pixel below[256 * 9 * 9];
array<bool[256]> windowAbove; bool windowAbove[256];
array<bool[256]> windowBelow; bool windowBelow[256];
//flush() //flush()
static uint start; static uint start;
static uint count; static uint count;
}; };
array<Line[240]> lines; Line lines[240];
//used to help detect when the video output size changes between frames to clear overscan area. //used to help detect when the video output size changes between frames to clear overscan area.
struct Frame { struct Frame {
@ -326,4 +328,6 @@ public:
} frame; } frame;
}; };
extern PPUfast ppufast; extern PPU ppufast;
#undef PPU

View File

@ -1,4 +1,4 @@
auto PPUfast::serialize(serializer& s) -> void { auto PPU::serialize(serializer& s) -> void {
Thread::serialize(s); Thread::serialize(s);
PPUcounter::serialize(s); PPUcounter::serialize(s);
@ -13,7 +13,7 @@ auto PPUfast::serialize(serializer& s) -> void {
Line::count = 0; Line::count = 0;
} }
auto PPUfast::Latch::serialize(serializer& s) -> void { auto PPU::Latch::serialize(serializer& s) -> void {
s.integer(interlace); s.integer(interlace);
s.integer(overscan); s.integer(overscan);
s.integer(hires); s.integer(hires);
@ -32,12 +32,12 @@ auto PPUfast::Latch::serialize(serializer& s) -> void {
ppu2.serialize(s); ppu2.serialize(s);
} }
auto PPUfast::Latch::PPU::serialize(serializer& s) -> void { auto PPU::Latch::PPUstate::serialize(serializer& s) -> void {
s.integer(mdr); s.integer(mdr);
s.integer(bgofs); s.integer(bgofs);
} }
auto PPUfast::IO::serialize(serializer& s) -> void { auto PPU::IO::serialize(serializer& s) -> void {
s.integer(displayDisable); s.integer(displayDisable);
s.integer(displayBrightness); s.integer(displayBrightness);
s.integer(oamBaseAddress); s.integer(oamBaseAddress);
@ -69,7 +69,7 @@ auto PPUfast::IO::serialize(serializer& s) -> void {
col.serialize(s); col.serialize(s);
} }
auto PPUfast::IO::Mode7::serialize(serializer& s) -> void { auto PPU::IO::Mode7::serialize(serializer& s) -> void {
s.integer(hflip); s.integer(hflip);
s.integer(vflip); s.integer(vflip);
s.integer(repeat); s.integer(repeat);
@ -83,14 +83,14 @@ auto PPUfast::IO::Mode7::serialize(serializer& s) -> void {
s.integer(voffset); s.integer(voffset);
} }
auto PPUfast::IO::Window::serialize(serializer& s) -> void { auto PPU::IO::Window::serialize(serializer& s) -> void {
s.integer(oneLeft); s.integer(oneLeft);
s.integer(oneRight); s.integer(oneRight);
s.integer(twoLeft); s.integer(twoLeft);
s.integer(twoRight); s.integer(twoRight);
} }
auto PPUfast::IO::WindowLayer::serialize(serializer& s) -> void { auto PPU::IO::WindowLayer::serialize(serializer& s) -> void {
s.integer(oneEnable); s.integer(oneEnable);
s.integer(oneInvert); s.integer(oneInvert);
s.integer(twoEnable); s.integer(twoEnable);
@ -100,7 +100,7 @@ auto PPUfast::IO::WindowLayer::serialize(serializer& s) -> void {
s.integer(belowEnable); s.integer(belowEnable);
} }
auto PPUfast::IO::WindowColor::serialize(serializer& s) -> void { auto PPU::IO::WindowColor::serialize(serializer& s) -> void {
s.integer(oneEnable); s.integer(oneEnable);
s.integer(oneInvert); s.integer(oneInvert);
s.integer(twoEnable); s.integer(twoEnable);
@ -110,7 +110,7 @@ auto PPUfast::IO::WindowColor::serialize(serializer& s) -> void {
s.integer(belowMask); s.integer(belowMask);
} }
auto PPUfast::IO::Background::serialize(serializer& s) -> void { auto PPU::IO::Background::serialize(serializer& s) -> void {
window.serialize(s); window.serialize(s);
s.integer(aboveEnable); s.integer(aboveEnable);
s.integer(belowEnable); s.integer(belowEnable);
@ -125,7 +125,7 @@ auto PPUfast::IO::Background::serialize(serializer& s) -> void {
s.array(priority); s.array(priority);
} }
auto PPUfast::IO::Object::serialize(serializer& s) -> void { auto PPU::IO::Object::serialize(serializer& s) -> void {
window.serialize(s); window.serialize(s);
s.integer(aboveEnable); s.integer(aboveEnable);
s.integer(belowEnable); s.integer(belowEnable);
@ -139,7 +139,7 @@ auto PPUfast::IO::Object::serialize(serializer& s) -> void {
s.array(priority); s.array(priority);
} }
auto PPUfast::IO::Color::serialize(serializer& s) -> void { auto PPU::IO::Color::serialize(serializer& s) -> void {
window.serialize(s); window.serialize(s);
s.array(enable); s.array(enable);
s.integer(directColor); s.integer(directColor);
@ -149,7 +149,7 @@ auto PPUfast::IO::Color::serialize(serializer& s) -> void {
s.integer(fixedColor); s.integer(fixedColor);
} }
auto PPUfast::Object::serialize(serializer& s) -> void { auto PPU::Object::serialize(serializer& s) -> void {
s.integer(x); s.integer(x);
s.integer(y); s.integer(y);
s.integer(character); s.integer(character);

View File

@ -1,6 +1,6 @@
auto PPUfast::Line::renderWindow(PPUfast::IO::WindowLayer& self, bool enable, array<bool[256]>& output) -> void { auto PPU::Line::renderWindow(PPU::IO::WindowLayer& self, bool enable, bool output[256]) -> void {
if(!enable || (!self.oneEnable && !self.twoEnable)) { if(!enable || (!self.oneEnable && !self.twoEnable)) {
output.fill(0); memory::fill<bool>(output, 256, 0);
return; return;
} }
@ -32,17 +32,17 @@ auto PPUfast::Line::renderWindow(PPUfast::IO::WindowLayer& self, bool enable, ar
} }
} }
auto PPUfast::Line::renderWindow(PPUfast::IO::WindowColor& self, uint mask, array<bool[256]>& output) -> void { auto PPU::Line::renderWindow(PPU::IO::WindowColor& self, uint mask, bool output[256]) -> void {
bool set, clear; bool set, clear;
switch(mask) { switch(mask) {
case 0: output.fill(1); return; //always case 0: memory::fill<bool>(output, 256, 1); return; //always
case 1: set = 1, clear = 0; break; //inside case 1: set = 1, clear = 0; break; //inside
case 2: set = 0, clear = 1; break; //outside case 2: set = 0, clear = 1; break; //outside
case 3: output.fill(0); return; //never case 3: memory::fill<bool>(output, 256, 0); return; //never
} }
if(!self.oneEnable && !self.twoEnable) { if(!self.oneEnable && !self.twoEnable) {
output.fill(clear); memory::fill<bool>(output, 256, clear);
return; return;
} }

View File

@ -26,7 +26,7 @@ auto PPU::Object::scanline() -> void {
auto oamTile = t.tile[t.active]; auto oamTile = t.tile[t.active];
if(t.y == ppu.vdisp() && !ppu.io.displayDisable) addressReset(); if(t.y == ppu.vdisp() && !ppu.io.displayDisable) addressReset();
if(t.y >= ppu.vdisp() - 1) return; if(t.y >= ppu.vdisp() - 1 || ppu.io.displayDisable) return;
for(auto n : range(32)) oamItem[n].valid = false; for(auto n : range(32)) oamItem[n].valid = false;
for(auto n : range(34)) oamTile[n].valid = false; for(auto n : range(34)) oamTile[n].valid = false;

View File

@ -62,7 +62,7 @@ auto PPU::main() -> void {
bg3.begin(); bg3.begin();
bg4.begin(); bg4.begin();
if(vcounter() <= 239) { if(vcounter() < vdisp()) {
for(int pixel = -7; pixel <= 255; pixel++) { for(int pixel = -7; pixel <= 255; pixel++) {
bg1.run(1); bg1.run(1);
bg2.run(1); bg2.run(1);
@ -210,16 +210,17 @@ auto PPU::power(bool reset) -> void {
screen.power(); screen.power();
updateVideoMode(); updateVideoMode();
frame();
} }
auto PPU::scanline() -> void { auto PPU::scanline() -> void {
if(vcounter() == 0) { if(vcounter() == 0) {
frame(); display.interlace = io.interlace;
display.overscan = io.overscan;
bg1.frame(); bg1.frame();
bg2.frame(); bg2.frame();
bg3.frame(); bg3.frame();
bg4.frame(); bg4.frame();
obj.frame();
} }
bg1.scanline(); bg1.scanline();
@ -235,12 +236,6 @@ auto PPU::scanline() -> void {
} }
} }
auto PPU::frame() -> void {
obj.frame();
display.interlace = io.interlace;
display.overscan = io.overscan;
}
auto PPU::refresh() -> void { auto PPU::refresh() -> void {
if(system.fastPPU()) { if(system.fastPPU()) {
return ppufast.refresh(); return ppufast.refresh();

View File

@ -50,7 +50,6 @@ private:
} display; } display;
auto scanline() -> void; auto scanline() -> void;
auto frame() -> void;
auto refresh() -> void; auto refresh() -> void;
struct { struct {

View File

@ -162,7 +162,7 @@ private:
} }
-(void) reshape { -(void) reshape {
video->output(); video->output(0, 0);
} }
@end @end