mirror of https://github.com/bsnes-emu/bsnes.git
v107.9
* started removing nall-specific components from the fast PPU renderer * corrected compilation issues with Super Game Boy support
This commit is contained in:
parent
14d87f6bf3
commit
0623d6ac2b
|
@ -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/";
|
||||||
|
|
|
@ -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];
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -50,7 +50,6 @@ private:
|
||||||
} display;
|
} display;
|
||||||
|
|
||||||
auto scanline() -> void;
|
auto scanline() -> void;
|
||||||
auto frame() -> void;
|
|
||||||
auto refresh() -> void;
|
auto refresh() -> void;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -162,7 +162,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void) reshape {
|
-(void) reshape {
|
||||||
video->output();
|
video->output(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
Loading…
Reference in New Issue