diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 6641c1bf..447ee990 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.30"; + static const string Version = "106.31"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/fc/cpu/cpu.cpp b/higan/fc/cpu/cpu.cpp index 94a5f6ce..fa3d7502 100644 --- a/higan/fc/cpu/cpu.cpp +++ b/higan/fc/cpu/cpu.cpp @@ -39,7 +39,6 @@ auto CPU::power(bool reset) -> void { r.pc.byte(1) = bus.read(0xfffd); io = {}; - io.rdyLine = 1; } } diff --git a/higan/fc/cpu/cpu.hpp b/higan/fc/cpu/cpu.hpp index 62ae35cd..1f6685c5 100644 --- a/higan/fc/cpu/cpu.hpp +++ b/higan/fc/cpu/cpu.hpp @@ -46,7 +46,7 @@ struct CPU : Processor::MOS6502, Thread { bool irqLine = 0; bool apuLine = 0; - bool rdyLine = 0; + bool rdyLine = 1; bool rdyAddrValid = 0; uint16 rdyAddrValue; diff --git a/higan/fc/ppu/ppu.cpp b/higan/fc/ppu/ppu.cpp index 9ae85601..9d863fc5 100644 --- a/higan/fc/ppu/ppu.cpp +++ b/higan/fc/ppu/ppu.cpp @@ -59,7 +59,6 @@ auto PPU::power(bool reset) -> void { io = {}; latch = {}; - io.vramIncrement = 1; if(!reset) { for(auto& data : ciram ) data = 0; diff --git a/higan/fc/ppu/ppu.hpp b/higan/fc/ppu/ppu.hpp index 2dc874f9..6c4f91ae 100644 --- a/higan/fc/ppu/ppu.hpp +++ b/higan/fc/ppu/ppu.hpp @@ -64,7 +64,7 @@ struct PPU : Thread { bool nmiFlag = 0; //$2000 - uint vramIncrement = 0; + uint vramIncrement = 1; uint spriteAddress = 0; uint bgAddress = 0; uint spriteHeight = 0; diff --git a/higan/gb/cpu/cpu.cpp b/higan/gb/cpu/cpu.cpp index 55964d8a..7af4f813 100644 --- a/higan/gb/cpu/cpu.cpp +++ b/higan/gb/cpu/cpu.cpp @@ -124,8 +124,6 @@ auto CPU::power() -> void { for(auto& n : hram) n = 0x00; status = {}; - status.dmaCompleted = true; - status.wramBank = 1; } } diff --git a/higan/gb/cpu/cpu.hpp b/higan/gb/cpu/cpu.hpp index 8251aa94..05a6736e 100644 --- a/higan/gb/cpu/cpu.hpp +++ b/higan/gb/cpu/cpu.hpp @@ -84,13 +84,13 @@ struct CPU : Processor::LR35902, Thread, MMIO { //$ff55 HDMA5 bool dmaMode = 0; uint16 dmaLength; - bool dmaCompleted = 0; + bool dmaCompleted = 1; //$ff6c ??? uint8 ff6c; //$ff70 SVBK - uint3 wramBank; + uint3 wramBank = 1; //$ff72-$ff75 ??? uint8 ff72; diff --git a/higan/sfc/ppu-fast/background.cpp b/higan/sfc/ppu-fast/background.cpp index 630d8a77..6db0d8bc 100644 --- a/higan/sfc/ppu-fast/background.cpp +++ b/higan/sfc/ppu-fast/background.cpp @@ -1,2 +1,103 @@ -auto PPU::Line::renderBackground(PPU::IO::Background&) -> void { +auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void { + if(io.displayDisable) return; + if(self.tileMode == TileMode::Inactive) return; + if(self.tileMode == TileMode::Mode7) return; //todo + if(!self.aboveEnable && !self.belowEnable) return; + + bool hires = io.bgMode == 5 || io.bgMode == 6; + bool offsetPerTile = io.bgMode == 2 || io.bgMode == 4 || io.bgMode == 6; + bool directColor = io.col.directColor && source == Source::BG1 && (io.bgMode == 3 || io.bgMode == 4); + uint width = !hires ? 256 : 512; + + uint tileHeight = self.tileSize ? 4 : 3; + uint tileWidth = hires ? 4 : tileHeight; + uint tileMask = 0x0fff >> self.tileMode; + uint tiledataIndex = self.tiledataAddress >> 4 + self.tileMode; + + uint maskX = width << (tileHeight == 4); + uint maskY = maskX; + if(self.screenSize.bit(0)) maskX <<= 1; + if(self.screenSize.bit(1)) maskY <<= 1; + maskX--; + maskY--; + + uint screenX = self.screenSize.bit(0) ? 32 << 5 : 0; + uint screenY = self.screenSize.bit(1) ? 32 << 5 : 0; + if(self.screenSize == 3) screenY <<= 1; + + uint paletteBase = io.bgMode == 0 ? source << 5 : 0; + uint paletteShift = 2 << self.tileMode; + + uint hscroll = self.hoffset; + uint vscroll = self.voffset; + + uint y = this->y; //todo: vmosaic + if(hires) { + hscroll <<= 1; + if(io.interlace) y = y << 1 | ppu.PPUcounter::field(); + } + + uint mosaicCounter = 1; + uint mosaicPalette = 0; + uint mosaicPriority = 0; + uint mosaicColor = 0; + + auto getTile = [&](uint hoffset, uint voffset) -> uint { + uint tileX = (hoffset & maskX) >> tileWidth; + uint tileY = (voffset & maskY) >> tileHeight; + uint tilePosition = (tileY & 0x1f) << 5 | (tileX & 0x1f); + if(tileX & 0x20) tilePosition += screenX; + if(tileY & 0x20) tilePosition += screenY; + uint15 tiledataAddress = self.screenAddress + tilePosition; + return ppu.vram[tiledataAddress]; + }; + + int x = 0 - (hscroll & 7); + while(x < width) { + uint hoffset = x + hscroll; + uint voffset = y + vscroll; + if(offsetPerTile); //todo + hoffset &= maskX; + voffset &= maskY; + + uint tileNumber = getTile(hoffset, voffset); + uint mirrorY = tileNumber & 0x8000 ? 7 : 0; + uint mirrorX = tileNumber & 0x4000 ? 7 : 0; + uint tilePriority = tileNumber & 0x2000 ? self.priority[1] : self.priority[0]; + uint paletteNumber = tileNumber >> 10 & 7; + uint paletteIndex = (paletteBase + (paletteNumber << paletteShift)) & 0xff; + + if(tileWidth == 4 && (hoffset & 8) - 1 != mirrorX) tileNumber += 1; + if(tileHeight == 4 && (voffset & 8) - 1 != mirrorY) tileNumber += 16; + tileNumber = ((tileNumber & 0x03ff) + tiledataIndex) & tileMask; + + auto tiledata = ppu.tilecache[self.tileMode] + (tileNumber << 6); + tiledata += ((voffset & 7) ^ mirrorY) << 3; + + for(uint tileX = 0; tileX < 8; tileX++, x++) { + if(x & width) continue; //x < 0 || x >= width + if(--mosaicCounter == 0) { + mosaicCounter = 1 + io.mosaicSize; + mosaicPalette = tiledata[tileX ^ mirrorX]; + mosaicPriority = tilePriority; + if(directColor) { + //todo + } else { + mosaicColor = cgram[paletteIndex + mosaicPalette]; + } + } + if(!mosaicPalette) continue; + + if(!hires) { + if(self.aboveEnable) { //todo: window + plotAbove(x, source, mosaicPriority, mosaicColor); + } + if(self.belowEnable) { //todo: window + plotBelow(x, source, mosaicPriority, mosaicColor); + } + } else { + //todo + } + } + } } diff --git a/higan/sfc/ppu-fast/io.cpp b/higan/sfc/ppu-fast/io.cpp index d3981c25..85e24177 100644 --- a/higan/sfc/ppu-fast/io.cpp +++ b/higan/sfc/ppu-fast/io.cpp @@ -26,6 +26,21 @@ auto PPU::writeVRAM(uint1 byte, uint8 data) -> void { if(!io.displayDisable && vcounter() < vdisp()) return; auto address = vramAddress(); vram[address].byte(byte) = data; + + auto word = vram[address]; + auto line2bpp = tilecache[0] + (address.bits(3,14) << 6) + (address.bits(0,2) << 3); + auto line4bpp = tilecache[1] + (address.bits(4,14) << 6) + (address.bits(0,2) << 3); + auto line8bpp = tilecache[2] + (address.bits(5,14) << 6) + (address.bits(0,2) << 3); + uint plane4bpp = address.bit(3) << 1; + uint plane8bpp = address.bit(3) << 1 | address.bit(4) << 2; + for(uint x : range(8)) { + line2bpp[7 - x].bit( 0) = word.bit(x + 0); + line2bpp[7 - x].bit( 1) = word.bit(x + 8); + line4bpp[7 - x].bit(plane4bpp + 0) = word.bit(x + 0); + line4bpp[7 - x].bit(plane4bpp + 1) = word.bit(x + 8); + line8bpp[7 - x].bit(plane8bpp + 0) = word.bit(x + 0); + line8bpp[7 - x].bit(plane8bpp + 1) = word.bit(x + 8); + } } auto PPU::readOAM(uint10 address) -> uint8 { diff --git a/higan/sfc/ppu-fast/line.cpp b/higan/sfc/ppu-fast/line.cpp index da3ed91f..501e703d 100644 --- a/higan/sfc/ppu-fast/line.cpp +++ b/higan/sfc/ppu-fast/line.cpp @@ -1,21 +1,52 @@ auto PPU::Line::render() -> void { + if(io.displayDisable) { + for(uint x : range(512)) { + outputLo[x] = 0; + outputHi[x] = 0; + } + } else { + auto aboveColor = cgram[0]; + auto belowColor = 0; + for(uint x : range(256)) { + above[x].source = Source::COL; + above[x].priority = 0; + above[x].color = aboveColor; + below[x].source = Source::COL; + below[x].priority = 0; + below[x].color = belowColor; + } + } + renderWindow(io.bg1.window); renderWindow(io.bg2.window); renderWindow(io.bg3.window); renderWindow(io.bg4.window); renderWindow(io.obj.window); renderWindow(io.col.window); - renderBackground(io.bg1); - renderBackground(io.bg2); - renderBackground(io.bg3); - renderBackground(io.bg4); + renderBackground(io.bg1, Source::BG1); + renderBackground(io.bg2, Source::BG2); + renderBackground(io.bg3, Source::BG3); + renderBackground(io.bg4, Source::BG4); renderObject(io.obj); - if(io.displayDisable) { - for(uint x : range(512)) { - outputLo[x] = 0; - outputHi[x] = 0; - } - return; + for(uint x : range(512)) { + outputLo[x] = io.displayBrightness << 15 | above[x >> 1].color; + outputHi[x] = io.displayBrightness << 15 | above[x >> 1].color; + } +} + +auto PPU::Line::plotAbove(uint x, uint source, uint priority, uint color) -> void { + if(priority > above[x].priority) { + above[x].source = source; + above[x].priority = priority; + above[x].color = color; + } +} + +auto PPU::Line::plotBelow(uint x, uint source, uint priority, uint color) -> void { + if(priority > below[x].priority) { + below[x].source = source; + below[x].priority = priority; + below[x].color = color; } } diff --git a/higan/sfc/ppu-fast/ppu.cpp b/higan/sfc/ppu-fast/ppu.cpp index 8ca8f116..4dad4220 100644 --- a/higan/sfc/ppu-fast/ppu.cpp +++ b/higan/sfc/ppu-fast/ppu.cpp @@ -18,6 +18,10 @@ PPU::PPU() { output = new uint32[512 * 512]; output += 16 * 512; //overscan offset + tilecache[0] = new uint8[4096 * 8 * 8]; + tilecache[1] = new uint8[2048 * 8 * 8]; + tilecache[2] = new uint8[1024 * 8 * 8]; + for(uint y : range(240)) { lines[y].y = y; lines[y].outputLo = output + (y * 2 + 0) * 512; @@ -28,6 +32,10 @@ PPU::PPU() { PPU::~PPU() { output -= 16 * 512; //overscan offset delete[] output; + + delete[] tilecache[0]; + delete[] tilecache[1]; + delete[] tilecache[2]; } auto PPU::Enter() -> void { @@ -59,9 +67,10 @@ auto PPU::scanline() -> void { frame(); } - if(PPUcounter::vcounter() == 241) { + if(PPUcounter::vcounter() == 240) { + const uint limit = vdisp(); #pragma omp parallel for - for(uint y = 1; y < vdisp(); y++) { + for(uint y = 1; y < limit; y++) { lines[y].render(); } scheduler.exit(Scheduler::Event::Frame); diff --git a/higan/sfc/ppu-fast/ppu.hpp b/higan/sfc/ppu-fast/ppu.hpp index 27650faf..afc91f17 100644 --- a/higan/sfc/ppu-fast/ppu.hpp +++ b/higan/sfc/ppu-fast/ppu.hpp @@ -34,6 +34,7 @@ struct PPU : Thread, PPUcounter { public: uint32* output = nullptr; + uint8* tilecache[3] = {}; //bitplane -> bitmap tiledata uint16 vram[32 * 1024]; uint16 cgram[256]; @@ -70,10 +71,9 @@ public: auto writeIO(uint24 address, uint8 data) -> void; auto updateVideoMode() -> void; + struct Source { enum : uint { BG1, BG2, BG3, BG4, OBJ1, OBJ2, COL }; }; struct TileMode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; }; - struct TileSize { enum : uint { Size8x8, Size16x16 }; }; struct ScreenMode { enum : uint { Above, Below }; }; - struct ScreenSize { enum : uint { Size32x32, Size32x64, Size64x32, Size64x64 }; }; struct IO { uint1 displayDisable; @@ -197,17 +197,14 @@ public: uint1 size; } object[128]; - //bitplane -> bitmap tile caches - uint8 vram2bpp[4096 * 8 * 8]; - uint8 vram4bpp[2048 * 8 * 8]; - uint8 vram8bpp[1024 * 8 * 8]; - struct Line { //line.cpp auto render() -> 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; //background.cpp - auto renderBackground(PPU::IO::Background&) -> void; + auto renderBackground(PPU::IO::Background&, uint source) -> void; //object.cpp auto renderObject(PPU::IO::Object&) -> void; @@ -222,6 +219,12 @@ public: uint15 cgram[256]; IO io; + + struct Screen { + uint source; + uint priority; + uint color; + } above[256], below[256]; } lines[240]; }; diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index 35dae7a5..75bc241d 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -210,7 +210,7 @@ auto PPU::scanline() -> void { window.scanline(); screen.scanline(); - if(vcounter() == 241) { + if(vcounter() == 240) { scheduler.exit(Scheduler::Event::Frame); } }