From ae5b4c3bb30112b13312a575f555424fb9b83e26 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 14 Jun 2016 20:51:54 +1000 Subject: [PATCH] Update to v099r01 release. byuu says: Changelog: - massive cleanups and optimizations on the PPU core - ~9% speedup over v099 official This is pretty much it for the low-hanging fruit of speeding up higan. Any more gains from this point will be extremely hard-fought, unfortunately. --- higan/emulator/emulator.hpp | 2 +- higan/sfc/ppu/background/background.cpp | 315 +++++---- higan/sfc/ppu/background/background.hpp | 76 +-- higan/sfc/ppu/background/mode7.cpp | 84 +-- higan/sfc/ppu/counter/counter-inline.hpp | 40 +- higan/sfc/ppu/counter/counter.hpp | 32 +- higan/sfc/ppu/memory.cpp | 42 +- higan/sfc/ppu/mmio.cpp | 642 +++++++++--------- higan/sfc/ppu/ppu.cpp | 117 ++-- higan/sfc/ppu/ppu.hpp | 103 +-- higan/sfc/ppu/screen/screen.cpp | 201 +++--- higan/sfc/ppu/screen/screen.hpp | 75 +- higan/sfc/ppu/serialization.cpp | 350 +++++----- higan/sfc/ppu/sprite/list.cpp | 36 +- higan/sfc/ppu/sprite/sprite.cpp | 197 +++--- higan/sfc/ppu/sprite/sprite.hpp | 115 ++-- higan/sfc/ppu/window/window.cpp | 234 +++---- higan/sfc/ppu/window/window.hpp | 104 +-- higan/sfc/system/system.cpp | 5 - higan/sfc/system/system.hpp | 8 +- .../presentation/presentation.cpp | 2 +- nall/memory.hpp | 134 +++- nall/memory/memory.hpp | 129 ---- nall/memory/pool.hpp | 62 -- 24 files changed, 1449 insertions(+), 1656 deletions(-) delete mode 100644 nall/memory/memory.hpp delete mode 100644 nall/memory/pool.hpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index e07b8fa6..b3c7db45 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -9,7 +9,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "099"; + static const string Version = "099.01"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/sfc/ppu/background/background.cpp b/higan/sfc/ppu/background/background.cpp index d121173b..54899da7 100644 --- a/higan/sfc/ppu/background/background.cpp +++ b/higan/sfc/ppu/background/background.cpp @@ -1,16 +1,13 @@ #include "mode7.cpp" -PPU::Background::Background(PPU &self, uint id) : self(self), id(id) { +auto PPU::Background::voffset() const -> uint16 { + if(r.mosaic) return latch.voffset; + return r.voffset; } -auto PPU::Background::voffset() const -> uint { - if(regs.mosaic) return cache.voffset; - return regs.voffset; -} - -auto PPU::Background::hoffset() const -> uint { - if(regs.mosaic) return cache.hoffset; - return regs.hoffset; +auto PPU::Background::hoffset() const -> uint16 { + if(r.mosaic) return latch.hoffset; + return r.hoffset; } //V = 0, H = 0 @@ -23,88 +20,88 @@ auto PPU::Background::scanline() -> void { //H = 28 auto PPU::Background::begin() -> void { - bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); x = -7; - y = self.vcounter(); + y = ppu.vcounter(); if(y == 1) { - mosaic.vcounter = regs.mosaic + 1; + mosaic.vcounter = r.mosaic + 1; mosaic.voffset = 1; - cache.hoffset = regs.hoffset; - cache.voffset = regs.voffset; + latch.hoffset = r.hoffset; + latch.voffset = r.voffset; } else if(--mosaic.vcounter == 0) { - mosaic.vcounter = regs.mosaic + 1; - mosaic.voffset += regs.mosaic + 1; - cache.hoffset = regs.hoffset; - cache.voffset = regs.voffset; + mosaic.vcounter = r.mosaic + 1; + mosaic.voffset += r.mosaic + 1; + latch.hoffset = r.hoffset; + latch.voffset = r.voffset; } - tile_counter = (7 - (cache.hoffset & 7)) << hires; - for(unsigned n = 0; n < 8; n++) data[n] = 0; + tileCounter = (7 - (latch.hoffset & 7)) << hires; + for(auto& d : data) d = 0; - mosaic.hcounter = regs.mosaic + 1; + mosaic.hcounter = r.mosaic + 1; mosaic.hoffset = 0; - if(regs.mode == Mode::Mode7) return begin_mode7(); - if(regs.mosaic == 0) { - cache.hoffset = regs.hoffset; - cache.voffset = regs.voffset; + if(r.mode == Mode::Mode7) return beginMode7(); + if(r.mosaic == 0) { + latch.hoffset = r.hoffset; + latch.voffset = r.voffset; } } -auto PPU::Background::get_tile() -> void { - bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); +auto PPU::Background::getTile() -> void { + bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); - unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2); - unsigned palette_offset = (self.regs.bgmode == 0 ? id << 5 : 0); - unsigned palette_size = 2 << color_depth; - unsigned tile_mask = 0x0fff >> color_depth; - unsigned tiledata_index = regs.tiledata_addr >> (4 + color_depth); + uint colorDepth = (r.mode == Mode::BPP2 ? 0 : r.mode == Mode::BPP4 ? 1 : 2); + uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0); + uint paletteSize = 2 << colorDepth; + uint tileMask = 0x0fff >> colorDepth; + uint tiledataIndex = r.tiledataAddress >> (4 + colorDepth); - unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4); - unsigned tile_width = (!hires ? tile_height : 4); + uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4); + uint tileWidth = (!hires ? tileHeight : 4); - unsigned width = 256 << hires; + uint width = 256 << hires; - unsigned hmask = (tile_height == 3 ? width : width << 1); - unsigned vmask = hmask; - if(regs.screen_size & 1) hmask <<= 1; - if(regs.screen_size & 2) vmask <<= 1; + uint hmask = (tileHeight == 3 ? width : width << 1); + uint vmask = hmask; + if(r.screenSize & 1) hmask <<= 1; + if(r.screenSize & 2) vmask <<= 1; hmask--; vmask--; - unsigned px = x << hires; - unsigned py = (regs.mosaic == 0 ? y : mosaic.voffset); + uint px = x << hires; + uint py = (r.mosaic == 0 ? y : mosaic.voffset); - unsigned hscroll = hoffset(); - unsigned vscroll = voffset(); + uint hscroll = hoffset(); + uint vscroll = voffset(); if(hires) { hscroll <<= 1; - if(self.regs.interlace) py = (py << 1) + self.field(); + if(ppu.r.interlace) py = (py << 1) + ppu.field(); } - unsigned hoffset = hscroll + px; - unsigned voffset = vscroll + py; + uint hoffset = hscroll + px; + uint voffset = vscroll + py; - if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) { - uint16 offset_x = (x + (hscroll & 7)); + if(ppu.r.bgMode == 2 || ppu.r.bgMode == 4 || ppu.r.bgMode == 6) { + uint16 offsetX = (x + (hscroll & 7)); - if(offset_x >= 8) { - unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.hoffset() & ~7), self.bg3.voffset() + 0); - unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.hoffset() & ~7), self.bg3.voffset() + 8); - unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000); + if(offsetX >= 8) { + uint hval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 0); + uint vval = ppu.bg3.getTile((offsetX - 8) + (ppu.bg3.hoffset() & ~7), ppu.bg3.voffset() + 8); + uint validMask = (id == ID::BG1 ? 0x2000 : 0x4000); - if(self.regs.bgmode == 4) { - if(hval & valid_mask) { + if(ppu.r.bgMode == 4) { + if(hval & validMask) { if((hval & 0x8000) == 0) { - hoffset = offset_x + (hval & ~7); + hoffset = offsetX + (hval & ~7); } else { voffset = y + hval; } } } else { - if(hval & valid_mask) hoffset = offset_x + (hval & ~7); - if(vval & valid_mask) voffset = y + vval; + if(hval & validMask) hoffset = offsetX + (hval & ~7); + if(vval & validMask) voffset = y + vval; } } } @@ -112,127 +109,127 @@ auto PPU::Background::get_tile() -> void { hoffset &= hmask; voffset &= vmask; - unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0); - unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0); - if(regs.screen_size == 3) screen_y <<= 1; + uint screenX = (r.screenSize & 1 ? 32 << 5 : 0); + uint screenY = (r.screenSize & 2 ? 32 << 5 : 0); + if(r.screenSize == 3) screenY <<= 1; - unsigned tx = hoffset >> tile_width; - unsigned ty = voffset >> tile_height; + uint tx = hoffset >> tileWidth; + uint ty = voffset >> tileHeight; uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f); - if(tx & 0x20) offset += screen_x; - if(ty & 0x20) offset += screen_y; + if(tx & 0x20) offset += screenX; + if(ty & 0x20) offset += screenY; - uint16 addr = regs.screen_addr + (offset << 1); - tile = (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8); - bool mirror_y = tile & 0x8000; - bool mirror_x = tile & 0x4000; - priority = (tile & 0x2000 ? regs.priority1 : regs.priority0); - palette_number = (tile >> 10) & 7; - palette_index = palette_offset + (palette_number << palette_size); + uint16 address = r.screenAddress + (offset << 1); + tile = (ppu.memory.vram[address + 0] << 0) + (ppu.memory.vram[address + 1] << 8); + bool mirrorY = tile & 0x8000; + bool mirrorX = tile & 0x4000; + priority = r.priority[bool(tile & 0x2000)]; + paletteNumber = (tile >> 10) & 7; + paletteIndex = paletteOffset + (paletteNumber << paletteSize); - if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile += 1; - if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile += 16; - uint16 character = ((tile & 0x03ff) + tiledata_index) & tile_mask; + if(tileWidth == 4 && (bool)(hoffset & 8) != mirrorX) tile += 1; + if(tileHeight == 4 && (bool)(voffset & 8) != mirrorY) tile += 16; + uint16 character = ((tile & 0x03ff) + tiledataIndex) & tileMask; - if(mirror_y) voffset ^= 7; - offset = (character << (4 + color_depth)) + ((voffset & 7) << 1); + if(mirrorY) voffset ^= 7; + offset = (character << (4 + colorDepth)) + ((voffset & 7) << 1); - switch(regs.mode) { + switch(r.mode) { case Mode::BPP8: - data[7] = ppu.vram[offset + 49]; - data[6] = ppu.vram[offset + 48]; - data[5] = ppu.vram[offset + 33]; - data[4] = ppu.vram[offset + 32]; + data[1].byte(3) = ppu.memory.vram[offset + 49]; + data[1].byte(2) = ppu.memory.vram[offset + 48]; + data[1].byte(1) = ppu.memory.vram[offset + 33]; + data[1].byte(0) = ppu.memory.vram[offset + 32]; case Mode::BPP4: - data[3] = ppu.vram[offset + 17]; - data[2] = ppu.vram[offset + 16]; + data[0].byte(3) = ppu.memory.vram[offset + 17]; + data[0].byte(2) = ppu.memory.vram[offset + 16]; case Mode::BPP2: - data[1] = ppu.vram[offset + 1]; - data[0] = ppu.vram[offset + 0]; + data[0].byte(1) = ppu.memory.vram[offset + 1]; + data[0].byte(0) = ppu.memory.vram[offset + 0]; } - if(mirror_x) for(unsigned n = 0; n < 8; n++) { - //reverse data bits in data[n]: 01234567 -> 76543210 - data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0); - data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc); - data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa); + if(mirrorX) for(auto n : range(2)) { + data[n] = ((data[n] >> 4) & 0x0f0f0f0f) | ((data[n] << 4) & 0xf0f0f0f0); + data[n] = ((data[n] >> 2) & 0x33333333) | ((data[n] << 2) & 0xcccccccc); + data[n] = ((data[n] >> 1) & 0x55555555) | ((data[n] << 1) & 0xaaaaaaaa); } } auto PPU::Background::run(bool screen) -> void { - if(self.vcounter() == 0) return; - bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); + if(ppu.vcounter() == 0) return; + bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); - if(screen == Screen::Sub) { - output.main.priority = 0; - output.sub.priority = 0; - if(hires == false) return; + if(screen == Screen::Below) { + output.above.priority = 0; + output.below.priority = 0; + if(!hires) return; } - if(tile_counter-- == 0) { - tile_counter = 7; - get_tile(); + if(tileCounter-- == 0) { + tileCounter = 7; + getTile(); } - if(regs.mode == Mode::Mode7) return run_mode7(); + if(r.mode == Mode::Mode7) return runMode7(); - uint8 palette = get_tile_color(); + uint8 palette = getTileColor(); if(x == 0) mosaic.hcounter = 1; if(x >= 0 && --mosaic.hcounter == 0) { - mosaic.hcounter = regs.mosaic + 1; + mosaic.hcounter = r.mosaic + 1; mosaic.priority = priority; - mosaic.palette = palette ? palette_index + palette : 0; + mosaic.palette = palette ? paletteIndex + palette : 0; mosaic.tile = tile; } - if(screen == Screen::Main) x++; + if(screen == Screen::Above) x++; if(mosaic.palette == 0) return; - if(hires == false || screen == Screen::Main) if(regs.main_enable) output.main = mosaic; - if(hires == false || screen == Screen::Sub ) if(regs.sub_enable ) output.sub = mosaic; + if(!hires || screen == Screen::Above) if(r.aboveEnable) output.above = mosaic; + if(!hires || screen == Screen::Below) if(r.belowEnable) output.below = mosaic; } -auto PPU::Background::get_tile_color() -> uint { - unsigned color = 0; +auto PPU::Background::getTileColor() -> uint { + uint color = 0; - switch(regs.mode) { + switch(r.mode) { case Mode::BPP8: - color += (data[7] >> 0) & 0x80; data[7] <<= 1; - color += (data[6] >> 1) & 0x40; data[6] <<= 1; - color += (data[5] >> 2) & 0x20; data[5] <<= 1; - color += (data[4] >> 3) & 0x10; data[4] <<= 1; + color += data[1] >> 28 & 0x80; + color += data[1] >> 21 & 0x40; + color += data[1] >> 14 & 0x20; + color += data[1] >> 7 & 0x10; + data[1] <<= 1; case Mode::BPP4: - color += (data[3] >> 4) & 0x08; data[3] <<= 1; - color += (data[2] >> 5) & 0x04; data[2] <<= 1; + color += data[0] >> 28 & 0x08; + color += data[0] >> 21 & 0x04; case Mode::BPP2: - color += (data[1] >> 6) & 0x02; data[1] <<= 1; - color += (data[0] >> 7) & 0x01; data[0] <<= 1; + color += data[0] >> 14 & 0x02; + color += data[0] >> 7 & 0x01; + data[0] <<= 1; } return color; } auto PPU::Background::reset() -> void { - regs.tiledata_addr = (random(0x0000) & 0x07) << 13; - regs.screen_addr = (random(0x0000) & 0x7c) << 9; - regs.screen_size = random(0); - regs.mosaic = random(0); - regs.tile_size = random(0); - regs.mode = 0; - regs.priority0 = 0; - regs.priority1 = 0; - regs.main_enable = random(0); - regs.sub_enable = random(0); - regs.hoffset = random(0x0000); - regs.voffset = random(0x0000); + r.tiledataAddress = (random(0x0000) & 0x07) << 13; + r.screenAddress = (random(0x0000) & 0x7c) << 9; + r.screenSize = random(0); + r.mosaic = random(0); + r.tileSize = random(0); + r.mode = 0; + for(auto& p : r.priority) p = 0; + r.aboveEnable = random(0); + r.belowEnable = random(0); + r.hoffset = random(0x0000); + r.voffset = random(0x0000); - cache.hoffset = 0; - cache.voffset = 0; + latch.hoffset = 0; + latch.voffset = 0; - output.main.palette = 0; - output.main.priority = 0; - output.sub.palette = 0; - output.sub.priority = 0; + output.above.palette = 0; + output.above.priority = 0; + output.below.palette = 0; + output.below.priority = 0; mosaic.priority = 0; mosaic.palette = 0; @@ -246,37 +243,37 @@ auto PPU::Background::reset() -> void { x = 0; y = 0; - tile_counter = 0; + tileCounter = 0; tile = 0; priority = 0; - palette_number = 0; - palette_index = 0; - for(unsigned n = 0; n < 8; n++) data[n] = 0; + paletteNumber = 0; + paletteIndex = 0; + for(auto& d : data) d = 0; } -auto PPU::Background::get_tile(uint x, uint y) -> uint { - bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); - unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4); - unsigned tile_width = (!hires ? tile_height : 4); - unsigned width = (!hires ? 256 : 512); - unsigned mask_x = (tile_height == 3 ? width : width << 1); - unsigned mask_y = mask_x; - if(regs.screen_size & 1) mask_x <<= 1; - if(regs.screen_size & 2) mask_y <<= 1; - mask_x--; - mask_y--; +auto PPU::Background::getTile(uint x, uint y) -> uint { + bool hires = (ppu.r.bgMode == 5 || ppu.r.bgMode == 6); + uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4); + uint tileWidth = (!hires ? tileHeight : 4); + uint width = (!hires ? 256 : 512); + uint maskX = (tileHeight == 3 ? width : width << 1); + uint maskY = maskX; + if(r.screenSize & 1) maskX <<= 1; + if(r.screenSize & 2) maskY <<= 1; + maskX--; + maskY--; - unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0); - unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0); - if(regs.screen_size == 3) screen_y <<= 1; + uint screenX = (r.screenSize & 1 ? 32 << 5 : 0); + uint screenY = (r.screenSize & 2 ? 32 << 5 : 0); + if(r.screenSize == 3) screenY <<= 1; - x = (x & mask_x) >> tile_width; - y = (y & mask_y) >> tile_height; + x = (x & maskX) >> tileWidth; + y = (y & maskY) >> tileHeight; uint16 offset = ((y & 0x1f) << 5) + (x & 0x1f); - if(x & 0x20) offset += screen_x; - if(y & 0x20) offset += screen_y; + if(x & 0x20) offset += screenX; + if(y & 0x20) offset += screenY; - uint16 addr = regs.screen_addr + (offset << 1); - return (ppu.vram[addr + 0] << 0) + (ppu.vram[addr + 1] << 8); + uint16 address = r.screenAddress + (offset << 1); + return (ppu.memory.vram[address + 0] << 0) + (ppu.memory.vram[address + 1] << 8); } diff --git a/higan/sfc/ppu/background/background.hpp b/higan/sfc/ppu/background/background.hpp index 1cf390f3..684e5083 100644 --- a/higan/sfc/ppu/background/background.hpp +++ b/higan/sfc/ppu/background/background.hpp @@ -1,46 +1,60 @@ struct Background { + Background(uint id) : id(id) {} + + alwaysinline auto voffset() const -> uint16; + alwaysinline auto hoffset() const -> uint16; + + auto frame() -> void; + auto scanline() -> void; + auto begin() -> void; + auto run(bool screen) -> void; + auto reset() -> void; + + auto getTile() -> void; + auto getTileColor() -> uint; + auto getTile(uint x, uint y) -> uint; + alwaysinline auto clip(int n) -> int; + auto beginMode7() -> void; + auto runMode7() -> void; + + auto serialize(serializer&) -> void; + struct ID { enum : uint { BG1, BG2, BG3, BG4 }; }; const uint id; struct Mode { enum : uint { BPP2, BPP4, BPP8, Mode7, Inactive }; }; struct ScreenSize { enum : uint { Size32x32, Size32x64, Size64x32, Size64x64 }; }; struct TileSize { enum : uint { Size8x8, Size16x16 }; }; - struct Screen { enum : uint { Main, Sub }; }; + struct Screen { enum : uint { Above, Below }; }; - Background(PPU& self, uint id); - - struct Regs { - uint16 tiledata_addr; - uint16 screen_addr; - uint2 screen_size; + struct Registers { + uint16 tiledataAddress; + uint16 screenAddress; + uint2 screenSize; uint4 mosaic; - bool tile_size; + bool tileSize; uint mode; - uint priority0; - uint priority1; + uint priority[2]; - bool main_enable; - bool sub_enable; + bool aboveEnable; + bool belowEnable; uint16 hoffset; uint16 voffset; - } regs; + } r; - struct Cache { + struct Latch { uint16 hoffset; uint16 voffset; - } cache; - - alwaysinline auto voffset() const -> uint; - alwaysinline auto hoffset() const -> uint; + } latch; struct Output { struct Pixel { uint priority; //0 = none (transparent) uint8 palette; uint16 tile; - } main, sub; + } above, below; } output; struct Mosaic : Output::Pixel { @@ -54,29 +68,13 @@ struct Background { int x; int y; - uint tile_counter; + uint tileCounter; uint tile; uint priority; - uint palette_number; - uint palette_index; - uint8 data[8]; + uint paletteNumber; + uint paletteIndex; + uint32 data[2]; }; - auto frame() -> void; - auto scanline() -> void; - auto begin() -> void; - auto run(bool screen) -> void; - auto reset() -> void; - - auto get_tile() -> void; - auto get_tile_color() -> uint; - auto get_tile(uint x, uint y) -> uint; - alwaysinline auto clip(int n) -> int; - auto begin_mode7() -> void; - auto run_mode7() -> void; - - auto serialize(serializer&) -> void; - - PPU& self; friend class PPU; }; diff --git a/higan/sfc/ppu/background/mode7.cpp b/higan/sfc/ppu/background/mode7.cpp index a07875f6..43d1a1bc 100644 --- a/higan/sfc/ppu/background/mode7.cpp +++ b/higan/sfc/ppu/background/mode7.cpp @@ -4,54 +4,54 @@ auto PPU::Background::clip(int n) -> int { } //H = 28 -auto PPU::Background::begin_mode7() -> void { - cache.hoffset = self.regs.mode7_hoffset; - cache.voffset = self.regs.mode7_voffset; +auto PPU::Background::beginMode7() -> void { + latch.hoffset = ppu.r.hoffsetMode7; + latch.voffset = ppu.r.voffsetMode7; } -auto PPU::Background::run_mode7() -> void { - signed a = sclip<16>(self.regs.m7a); - signed b = sclip<16>(self.regs.m7b); - signed c = sclip<16>(self.regs.m7c); - signed d = sclip<16>(self.regs.m7d); +auto PPU::Background::runMode7() -> void { + int a = (int16)ppu.r.m7a; + int b = (int16)ppu.r.m7b; + int c = (int16)ppu.r.m7c; + int d = (int16)ppu.r.m7d; - signed cx = sclip<13>(self.regs.m7x); - signed cy = sclip<13>(self.regs.m7y); - signed hoffset = sclip<13>(cache.hoffset); - signed voffset = sclip<13>(cache.voffset); + int cx = (int13)ppu.r.m7x; + int cy = (int13)ppu.r.m7y; + int hoffset = (int13)latch.hoffset; + int voffset = (int13)latch.voffset; if(Background::x++ & ~255) return; - unsigned x = mosaic.hoffset; - unsigned y = self.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size + uint x = mosaic.hoffset; + uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size if(--mosaic.hcounter == 0) { - mosaic.hcounter = regs.mosaic + 1; - mosaic.hoffset += regs.mosaic + 1; + mosaic.hcounter = r.mosaic + 1; + mosaic.hoffset += r.mosaic + 1; } - if(self.regs.mode7_hflip) x = 255 - x; - if(self.regs.mode7_vflip) y = 255 - y; + if(ppu.r.hflipMode7) x = 255 - x; + if(ppu.r.vflipMode7) y = 255 - y; - signed psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8); - signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8); + int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8); + int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8); - signed px = psx + (a * x); - signed py = psy + (c * x); + int px = psx + (a * x); + int py = psy + (c * x); //mask pseudo-FP bits px >>= 8; py >>= 8; - unsigned tile; - unsigned palette; - switch(self.regs.mode7_repeat) { + uint tile; + uint palette; + switch(ppu.r.repeatMode7) { //screen repetition outside of screen area case 0: case 1: px &= 1023; py &= 1023; - tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; - palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + tile = ppu.memory.vram[((py >> 3) * 128 + (px >> 3)) << 1]; + palette = ppu.memory.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; break; //palette color 0 outside of screen area @@ -61,8 +61,8 @@ auto PPU::Background::run_mode7() -> void { } else { px &= 1023; py &= 1023; - tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; - palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + tile = ppu.memory.vram[((py >> 3) * 128 + (px >> 3)) << 1]; + palette = ppu.memory.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; } break; @@ -73,31 +73,31 @@ auto PPU::Background::run_mode7() -> void { } else { px &= 1023; py &= 1023; - tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1]; + tile = ppu.memory.vram[((py >> 3) * 128 + (px >> 3)) << 1]; } - palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; + palette = ppu.memory.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1]; break; } - unsigned priority; + uint priority; if(id == ID::BG1) { - priority = regs.priority0; + priority = r.priority[0]; } else if(id == ID::BG2) { - priority = (palette & 0x80 ? regs.priority1 : regs.priority0); + priority = r.priority[bool(palette & 0x80)]; palette &= 0x7f; } if(palette == 0) return; - if(regs.main_enable) { - output.main.palette = palette; - output.main.priority = priority; - output.main.tile = 0; + if(r.aboveEnable) { + output.above.palette = palette; + output.above.priority = priority; + output.above.tile = 0; } - if(regs.sub_enable) { - output.sub.palette = palette; - output.sub.priority = priority; - output.sub.tile = 0; + if(r.belowEnable) { + output.below.palette = palette; + output.below.priority = priority; + output.below.tile = 0; } } diff --git a/higan/sfc/ppu/counter/counter-inline.hpp b/higan/sfc/ppu/counter/counter-inline.hpp index 2c21b6d1..711bf89b 100644 --- a/higan/sfc/ppu/counter/counter-inline.hpp +++ b/higan/sfc/ppu/counter/counter-inline.hpp @@ -1,10 +1,10 @@ //this should only be called by CPU::PPUcounter::tick(); //keeps track of previous counter positions in history table -void PPUcounter::tick() { +auto PPUcounter::tick() -> void { status.hcounter += 2; //increment by smallest unit of time if(status.hcounter >= 1360 && status.hcounter == lineclocks()) { status.hcounter = 0; - vcounter_tick(); + vcounterTick(); } history.index = (history.index + 1) & 2047; @@ -15,16 +15,16 @@ void PPUcounter::tick() { //this should only be called by PPU::PPUcounter::tick(n); //allows stepping by more than the smallest unit of time -void PPUcounter::tick(unsigned clocks) { +auto PPUcounter::tick(uint clocks) -> void { status.hcounter += clocks; if(status.hcounter >= lineclocks()) { status.hcounter -= lineclocks(); - vcounter_tick(); + vcounterTick(); } } //internal -void PPUcounter::vcounter_tick() { +auto PPUcounter::vcounterTick() -> void { if(++status.vcounter == 128) status.interlace = ppu.interlace(); if((system.region() == System::Region::NTSC && status.interlace == false && status.vcounter == 262) @@ -40,13 +40,13 @@ void PPUcounter::vcounter_tick() { if(scanline) scanline(); } -bool PPUcounter::field () const { return status.field; } -uint16 PPUcounter::vcounter() const { return status.vcounter; } -uint16 PPUcounter::hcounter() const { return status.hcounter; } +auto PPUcounter::field() const -> bool { return status.field; } +auto PPUcounter::vcounter() const -> uint16 { return status.vcounter; } +auto PPUcounter::hcounter() const -> uint16 { return status.hcounter; } -bool PPUcounter::field (unsigned offset) const { return history.field [(history.index - (offset >> 1)) & 2047]; } -uint16 PPUcounter::vcounter(unsigned offset) const { return history.vcounter[(history.index - (offset >> 1)) & 2047]; } -uint16 PPUcounter::hcounter(unsigned offset) const { return history.hcounter[(history.index - (offset >> 1)) & 2047]; } +auto PPUcounter::field(uint offset) const -> bool { return history.field[(history.index - (offset >> 1)) & 2047]; } +auto PPUcounter::vcounter(uint offset) const -> uint16 { return history.vcounter[(history.index - (offset >> 1)) & 2047]; } +auto PPUcounter::hcounter(uint offset) const -> uint16 { return history.hcounter[(history.index - (offset >> 1)) & 2047]; } //one PPU dot = 4 CPU clocks // @@ -54,10 +54,10 @@ uint16 PPUcounter::hcounter(unsigned offset) const { return history.hcounter[(hi //this does not apply to NTSC non-interlace scanline 240 on odd fields. this is //because the PPU skips one dot to alter the color burst phase of the video signal. // -//dot 323 range = { 1292, 1294, 1296 } -//dot 327 range = { 1310, 1312, 1314 } +//dot 323 range = {1292, 1294, 1296} +//dot 327 range = {1310, 1312, 1314} -uint16 PPUcounter::hdot() const { +auto PPUcounter::hdot() const -> uint16 { if(system.region() == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) { return (hcounter() >> 2); } else { @@ -65,21 +65,21 @@ uint16 PPUcounter::hdot() const { } } -uint16 PPUcounter::lineclocks() const { +auto PPUcounter::lineclocks() const -> uint16 { if(system.region() == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) return 1360; return 1364; } -void PPUcounter::reset() { +auto PPUcounter::reset() -> void { status.interlace = false; status.field = 0; status.vcounter = 0; status.hcounter = 0; history.index = 0; - for(unsigned i = 0; i < 2048; i++) { - history.field [i] = 0; - history.vcounter[i] = 0; - history.hcounter[i] = 0; + for(auto n : range(2048)) { + history.field [n] = 0; + history.vcounter[n] = 0; + history.hcounter[n] = 0; } } diff --git a/higan/sfc/ppu/counter/counter.hpp b/higan/sfc/ppu/counter/counter.hpp index b8d7aa7e..9937bdbb 100644 --- a/higan/sfc/ppu/counter/counter.hpp +++ b/higan/sfc/ppu/counter/counter.hpp @@ -10,27 +10,27 @@ //point before this in the frame, which is handled internally by this class at //V=128. -class PPUcounter { -public: - alwaysinline void tick(); - alwaysinline void tick(unsigned clocks); +struct PPUcounter { + alwaysinline auto tick() -> void; + alwaysinline auto tick(uint clocks) -> void; - alwaysinline bool field () const; - alwaysinline uint16 vcounter() const; - alwaysinline uint16 hcounter() const; - inline uint16 hdot() const; - inline uint16 lineclocks() const; + alwaysinline auto field() const -> bool; + alwaysinline auto vcounter() const -> uint16; + alwaysinline auto hcounter() const -> uint16; + inline auto hdot() const -> uint16; + inline auto lineclocks() const -> uint16; - alwaysinline bool field (unsigned offset) const; - alwaysinline uint16 vcounter(unsigned offset) const; - alwaysinline uint16 hcounter(unsigned offset) const; + alwaysinline auto field(uint offset) const -> bool; + alwaysinline auto vcounter(uint offset) const -> uint16; + alwaysinline auto hcounter(uint offset) const -> uint16; - inline void reset(); - function scanline; - void serialize(serializer&); + inline auto reset() -> void; + auto serialize(serializer&) -> void; + + function void> scanline; private: - inline void vcounter_tick(); + inline auto vcounterTick() -> void; struct { bool interlace; diff --git a/higan/sfc/ppu/memory.cpp b/higan/sfc/ppu/memory.cpp index 4aba04f6..901db794 100644 --- a/higan/sfc/ppu/memory.cpp +++ b/higan/sfc/ppu/memory.cpp @@ -1,49 +1,49 @@ auto PPU::getVramAddress() -> uint16 { - uint16 addr = regs.vram_addr; - switch(regs.vram_mapping) { + uint16 address = r.vramAddress; + switch(r.vramMapping) { case 0: break; //direct mapping - case 1: addr = (addr & 0xff00) | ((addr & 0x001f) << 3) | ((addr >> 5) & 7); break; - case 2: addr = (addr & 0xfe00) | ((addr & 0x003f) << 3) | ((addr >> 6) & 7); break; - case 3: addr = (addr & 0xfc00) | ((addr & 0x007f) << 3) | ((addr >> 7) & 7); break; + case 1: address = (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7); break; + case 2: address = (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7); break; + case 3: address = (address & 0xfc00) | ((address & 0x007f) << 3) | ((address >> 7) & 7); break; } - return (addr << 1); + return address << 1; } auto PPU::vramRead(uint addr) -> uint8 { uint8 data = 0x00; - if(regs.display_disable || vcounter() >= vdisp()) { - data = vram[addr]; - debugger.vram_read(addr, data); + if(r.displayDisable || vcounter() >= vdisp()) { + data = memory.vram[addr]; + debugger.vramRead(addr, data); } return data; } auto PPU::vramWrite(uint addr, uint8 data) -> void { - if(regs.display_disable || vcounter() >= vdisp()) { - vram[addr] = data; - debugger.vram_write(addr, data); + if(r.displayDisable || vcounter() >= vdisp()) { + memory.vram[addr] = data; + debugger.vramWrite(addr, data); } } auto PPU::oamRead(uint addr) -> uint8 { - uint8 data = oam[addr]; - debugger.oam_read(addr, data); + uint8 data = memory.oam[addr]; + debugger.oamRead(addr, data); return data; } auto PPU::oamWrite(uint addr, uint8 data) -> void { - oam[addr] = data; - sprite.update(addr, data); - debugger.oam_write(addr, data); + memory.oam[addr] = data; + oam.update(addr, data); + debugger.oamWrite(addr, data); } auto PPU::cgramRead(uint addr) -> uint8 { - uint8 data = cgram[addr]; - debugger.cgram_read(addr, data); + uint8 data = memory.cgram[addr]; + debugger.cgramRead(addr, data); return data; } auto PPU::cgramWrite(uint addr, uint8 data) -> void { - cgram[addr] = data; - debugger.cgram_write(addr, data); + memory.cgram[addr] = data; + debugger.cgramWrite(addr, data); } diff --git a/higan/sfc/ppu/mmio.cpp b/higan/sfc/ppu/mmio.cpp index 9a793f8c..1f7cf6f6 100644 --- a/higan/sfc/ppu/mmio.cpp +++ b/higan/sfc/ppu/mmio.cpp @@ -1,35 +1,35 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 { cpu.synchronizePPU(); - switch(addr & 0xffff) { + switch((uint16)addr) { case 0x2104: case 0x2105: case 0x2106: case 0x2108: case 0x2109: case 0x210a: case 0x2114: case 0x2115: case 0x2116: case 0x2118: case 0x2119: case 0x211a: case 0x2124: case 0x2125: case 0x2126: case 0x2128: case 0x2129: case 0x212a: { - return regs.ppu1_mdr; + return ppu1.mdr; } //MPYL case 0x2134: { - uint result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); - regs.ppu1_mdr = (result >> 0); - return regs.ppu1_mdr; + uint result = ((int16)r.m7a * (int8)(r.m7b >> 8)); + ppu1.mdr = (result >> 0); + return ppu1.mdr; } //MPYM case 0x2135: { - uint result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); - regs.ppu1_mdr = (result >> 8); - return regs.ppu1_mdr; + uint result = ((int16)r.m7a * (int8)(r.m7b >> 8)); + ppu1.mdr = (result >> 8); + return ppu1.mdr; } //MPYH case 0x2136: { - uint result = ((int16)regs.m7a * (int8)(regs.m7b >> 8)); - regs.ppu1_mdr = (result >> 16); - return regs.ppu1_mdr; + uint result = ((int16)r.m7a * (int8)(r.m7b >> 8)); + ppu1.mdr = (result >> 16); + return ppu1.mdr; } //SLHV @@ -40,108 +40,108 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 { //OAMDATAREAD case 0x2138: { - uint10 addr = regs.oam_addr++; - if(!regs.display_disable && vcounter() < vdisp()) addr = regs.oam_iaddr; + uint10 addr = r.oamAddress++; + if(!r.displayDisable && vcounter() < vdisp()) addr = latch.oamAddress; if(addr & 0x0200) addr &= 0x021f; - regs.ppu1_mdr = oamRead(addr); - sprite.set_first_sprite(); - return regs.ppu1_mdr; + ppu1.mdr = oamRead(addr); + oam.setFirstSprite(); + return ppu1.mdr; } //VMDATALREAD case 0x2139: { - uint16 addr = getVramAddress() + 0; - regs.ppu1_mdr = regs.vram_readbuffer >> 0; - if(regs.vram_incmode == 0) { + uint16 address = getVramAddress() + 0; + ppu1.mdr = latch.vram >> 0; + if(r.vramIncrementMode == 0) { addr &= ~1; - regs.vram_readbuffer = vramRead(addr + 0) << 0; - regs.vram_readbuffer |= vramRead(addr + 1) << 8; - regs.vram_addr += regs.vram_incsize; + latch.vram.byte(0) = vramRead(address + 0); + latch.vram.byte(1) = vramRead(address + 1); + r.vramAddress += r.vramIncrementSize; } - return regs.ppu1_mdr; + return ppu1.mdr; } //VMDATAHREAD case 0x213a: { - uint16 addr = getVramAddress() + 1; - regs.ppu1_mdr = regs.vram_readbuffer >> 8; - if(regs.vram_incmode == 1) { + uint16 address = getVramAddress() + 1; + ppu1.mdr = latch.vram >> 8; + if(r.vramIncrementMode == 1) { addr &= ~1; - regs.vram_readbuffer = vramRead(addr + 0) << 0; - regs.vram_readbuffer |= vramRead(addr + 1) << 8; - regs.vram_addr += regs.vram_incsize; + latch.vram.byte(0) = vramRead(address + 0); + latch.vram.byte(1) = vramRead(address + 1); + r.vramAddress += r.vramIncrementSize; } - return regs.ppu1_mdr; + return ppu1.mdr; } //CGDATAREAD case 0x213b: { - bool latch = regs.cgram_addr & 1; - uint9 addr = regs.cgram_addr++; - if(!regs.display_disable + bool l = r.cgramAddress & 1; + uint9 address = r.cgramAddress++; + if(!r.displayDisable && vcounter() > 0 && vcounter() < vdisp() && hcounter() >= 88 && hcounter() < 1096 - ) addr = regs.cgram_iaddr; + ) address = latch.cgramAddress; - if(latch == 0) { - regs.ppu2_mdr = cgramRead(addr); + if(l == 0) { + ppu2.mdr = cgramRead(address); } else { - regs.ppu2_mdr &= 0x80; - regs.ppu2_mdr |= cgramRead(addr); + ppu2.mdr &= 0x80; + ppu2.mdr |= cgramRead(address); } - return regs.ppu2_mdr; + return ppu2.mdr; } //OPHCT case 0x213c: { - if(regs.latch_hcounter == 0) { - regs.ppu2_mdr = (regs.hcounter >> 0); + if(latch.hcounter == 0) { + ppu2.mdr = (r.hcounter >> 0); } else { - regs.ppu2_mdr &= 0xfe; - regs.ppu2_mdr |= (regs.hcounter >> 8) & 1; + ppu2.mdr &= 0xfe; + ppu2.mdr |= (r.hcounter >> 8) & 1; } - regs.latch_hcounter ^= 1; - return regs.ppu2_mdr; + latch.hcounter ^= 1; + return ppu2.mdr; } //OPVCT case 0x213d: { - if(regs.latch_vcounter == 0) { - regs.ppu2_mdr = (regs.vcounter >> 0); + if(latch.vcounter == 0) { + ppu2.mdr = (r.vcounter >> 0); } else { - regs.ppu2_mdr &= 0xfe; - regs.ppu2_mdr |= (regs.vcounter >> 8) & 1; + ppu2.mdr &= 0xfe; + ppu2.mdr |= (r.vcounter >> 8) & 1; } - regs.latch_vcounter ^= 1; - return regs.ppu2_mdr; + latch.vcounter ^= 1; + return ppu2.mdr; } //STAT77 case 0x213e: { - regs.ppu1_mdr &= 0x10; - regs.ppu1_mdr |= sprite.regs.time_over << 7; - regs.ppu1_mdr |= sprite.regs.range_over << 6; - regs.ppu1_mdr |= ppu1_version & 0x0f; - return regs.ppu1_mdr; + ppu1.mdr &= 0x10; + ppu1.mdr |= oam.r.timeOver << 7; + ppu1.mdr |= oam.r.rangeOver << 6; + ppu1.mdr |= ppu1.version & 0x0f; + return ppu1.mdr; } //STAT78 case 0x213f: { - regs.latch_hcounter = 0; - regs.latch_vcounter = 0; + latch.hcounter = 0; + latch.vcounter = 0; - regs.ppu2_mdr &= 0x20; - regs.ppu2_mdr |= field() << 7; + ppu2.mdr &= 0x20; + ppu2.mdr |= field() << 7; if((cpu.pio() & 0x80) == 0) { - regs.ppu2_mdr |= 0x40; - } else if(regs.counters_latched) { - regs.ppu2_mdr |= 0x40; - regs.counters_latched = false; + ppu2.mdr |= 0x40; + } else if(latch.counters) { + ppu2.mdr |= 0x40; + latch.counters = false; } - regs.ppu2_mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4; - regs.ppu2_mdr |= ppu2_version & 0x0f; - return regs.ppu2_mdr; + ppu2.mdr |= (system.region() == System::Region::NTSC ? 0 : 1) << 4; + ppu2.mdr |= ppu2.version & 0x0f; + return ppu2.mdr; } } @@ -152,462 +152,462 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 { auto PPU::write(uint24 addr, uint8 data) -> void { cpu.synchronizePPU(); - switch(addr & 0xffff) { + switch((uint16)addr) { //INIDISP case 0x2100: { - if(regs.display_disable && vcounter() == vdisp()) sprite.address_reset(); - regs.display_disable = data & 0x80; - regs.display_brightness = data & 0x0f; + if(r.displayDisable && vcounter() == vdisp()) oam.addressReset(); + r.displayBrightness = data.bits(0,3); + r.displayDisable = data.bit (7); return; } //OBSEL case 0x2101: { - sprite.regs.base_size = (data >> 5) & 7; - sprite.regs.nameselect = (data >> 3) & 3; - sprite.regs.tiledata_addr = (data & 3) << 14; + oam.r.tiledataAddress = data.bits(0,1) << 14; + oam.r.nameSelect = data.bits(3,4); + oam.r.baseSize = data.bits(5,7); return; } //OAMADDL case 0x2102: { - regs.oam_baseaddr = (regs.oam_baseaddr & 0x0200) | (data << 1); - sprite.address_reset(); + r.oamBaseAddress = (r.oamBaseAddress & 0x0200) | (data << 1); + oam.addressReset(); return; } //OAMADDH case 0x2103: { - regs.oam_priority = data & 0x80; - regs.oam_baseaddr = ((data & 0x01) << 9) | (regs.oam_baseaddr & 0x01fe); - sprite.address_reset(); + r.oamPriority = data & 0x80; + r.oamBaseAddress = ((data & 0x01) << 9) | (r.oamBaseAddress & 0x01fe); + oam.addressReset(); return; } //OAMDATA case 0x2104: { - bool latch = regs.oam_addr & 1; - uint10 addr = regs.oam_addr++; - if(!regs.display_disable && vcounter() < vdisp()) addr = regs.oam_iaddr; + bool l = r.oamAddress & 1; + uint10 addr = r.oamAddress++; + if(!r.displayDisable && vcounter() < vdisp()) addr = latch.oamAddress; if(addr & 0x0200) addr &= 0x021f; - if(latch == 0) regs.oam_latchdata = data; + if(l == 0) latch.oam = data; if(addr & 0x0200) { oamWrite(addr, data); - } else if(latch == 1) { - oamWrite((addr & ~1) + 0, regs.oam_latchdata); + } else if(l == 1) { + oamWrite((addr & ~1) + 0, latch.oam); oamWrite((addr & ~1) + 1, data); } - sprite.set_first_sprite(); + oam.setFirstSprite(); return; } //BGMODE case 0x2105: { - bg4.regs.tile_size = (data & 0x80); - bg3.regs.tile_size = (data & 0x40); - bg2.regs.tile_size = (data & 0x20); - bg1.regs.tile_size = (data & 0x10); - regs.bg3_priority = (data & 0x08); - regs.bgmode = (data & 0x07); + r.bgMode = data.bits(0,2); + r.bgPriority = data.bit (3); + bg1.r.tileSize = data.bit (4); + bg2.r.tileSize = data.bit (5); + bg3.r.tileSize = data.bit (6); + bg4.r.tileSize = data.bit (7); updateVideoMode(); return; } //MOSAIC case 0x2106: { - unsigned mosaic_size = (data >> 4) & 15; - bg4.regs.mosaic = (data & 0x08 ? mosaic_size : 0); - bg3.regs.mosaic = (data & 0x04 ? mosaic_size : 0); - bg2.regs.mosaic = (data & 0x02 ? mosaic_size : 0); - bg1.regs.mosaic = (data & 0x01 ? mosaic_size : 0); + uint mosaicSize = data.bits(4,7); + bg1.r.mosaic = data.bit(0) ? mosaicSize : 0; + bg2.r.mosaic = data.bit(1) ? mosaicSize : 0; + bg3.r.mosaic = data.bit(2) ? mosaicSize : 0; + bg4.r.mosaic = data.bit(3) ? mosaicSize : 0; return; } //BG1SC case 0x2107: { - bg1.regs.screen_addr = (data & 0x7c) << 9; - bg1.regs.screen_size = data & 3; + bg1.r.screenSize = data.bits(0,1); + bg1.r.screenAddress = data.bits(2,6) << 11; return; } //BG2SC case 0x2108: { - bg2.regs.screen_addr = (data & 0x7c) << 9; - bg2.regs.screen_size = data & 3; + bg2.r.screenSize = data.bits(0,1); + bg2.r.screenAddress = data.bits(2,6) << 11; return; } //BG3SC case 0x2109: { - bg3.regs.screen_addr = (data & 0x7c) << 9; - bg3.regs.screen_size = data & 3; + bg3.r.screenSize = data.bits(0,1); + bg3.r.screenAddress = data.bits(2,6) << 11; return; } //BG4SC case 0x210a: { - bg4.regs.screen_addr = (data & 0x7c) << 9; - bg4.regs.screen_size = data & 3; + bg4.r.screenSize = data.bits(0,1); + bg4.r.screenAddress = data.bits(2,6) << 11; return; } //BG12NBA case 0x210b: { - bg1.regs.tiledata_addr = (data & 0x07) << 13; - bg2.regs.tiledata_addr = (data & 0x70) << 9; + bg1.r.tiledataAddress = data.bits(0,2) << 13; + bg2.r.tiledataAddress = data.bits(4,6) << 13; return; } //BG34NBA case 0x210c: { - bg3.regs.tiledata_addr = (data & 0x07) << 13; - bg4.regs.tiledata_addr = (data & 0x70) << 9; + bg3.r.tiledataAddress = data.bits(0,2) << 13; + bg4.r.tiledataAddress = data.bits(4,6) << 13; return; } //BG1HOFS case 0x210d: { - regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.hoffsetMode7 = (data << 8) | latch.mode7; + latch.mode7 = data; - bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; + bg1.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg1.r.hoffset >> 8) & 7); + latch.bgofs = data; return; } //BG1VOFS case 0x210e: { - regs.mode7_voffset = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.voffsetMode7 = (data << 8) | latch.mode7; + latch.mode7 = data; - bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; + bg1.r.voffset = (data << 8) | latch.bgofs; + latch.bgofs = data; return; } //BG2HOFS case 0x210f: { - bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; + bg2.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg2.r.hoffset >> 8) & 7); + latch.bgofs = data; return; } //BG2VOFS case 0x2110: { - bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; + bg2.r.voffset = (data << 8) | latch.bgofs; + latch.bgofs = data; return; } //BG3HOFS case 0x2111: { - bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; + bg3.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg3.r.hoffset >> 8) & 7); + latch.bgofs = data; return; } //BG3VOFS case 0x2112: { - bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; + bg3.r.voffset = (data << 8) | latch.bgofs; + latch.bgofs = data; return; } //BG4HOFS case 0x2113: { - bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7); - regs.bgofs_latchdata = data; + bg4.r.hoffset = (data << 8) | (latch.bgofs & ~7) | ((bg4.r.hoffset >> 8) & 7); + latch.bgofs = data; return; } //BG4VOFS case 0x2114: { - bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata; - regs.bgofs_latchdata = data; + bg4.r.voffset = (data << 8) | latch.bgofs; + latch.bgofs = data; return; } //VMAIN case 0x2115: { - regs.vram_incmode = data & 0x80; - regs.vram_mapping = (data >> 2) & 3; + r.vramIncrementMode = data & 0x80; + r.vramMapping = (data >> 2) & 3; switch(data & 3) { - case 0: regs.vram_incsize = 1; break; - case 1: regs.vram_incsize = 32; break; - case 2: regs.vram_incsize = 128; break; - case 3: regs.vram_incsize = 128; break; + case 0: r.vramIncrementSize = 1; break; + case 1: r.vramIncrementSize = 32; break; + case 2: r.vramIncrementSize = 128; break; + case 3: r.vramIncrementSize = 128; break; } return; } //VMADDL case 0x2116: { - regs.vram_addr &= 0xff00; - regs.vram_addr |= (data << 0); - uint16 addr = getVramAddress(); - regs.vram_readbuffer = vramRead(addr + 0) << 0; - regs.vram_readbuffer |= vramRead(addr + 1) << 8; + r.vramAddress &= 0xff00; + r.vramAddress |= (data << 0); + uint16 address = getVramAddress(); + latch.vram.byte(0) = vramRead(address + 0); + latch.vram.byte(1) = vramRead(address + 1); return; } //VMADDH case 0x2117: { - regs.vram_addr &= 0x00ff; - regs.vram_addr |= (data << 8); - uint16 addr = getVramAddress(); - regs.vram_readbuffer = vramRead(addr + 0) << 0; - regs.vram_readbuffer |= vramRead(addr + 1) << 8; + r.vramAddress &= 0x00ff; + r.vramAddress |= (data << 8); + uint16 address = getVramAddress(); + latch.vram.byte(0) = vramRead(address + 0); + latch.vram.byte(1) = vramRead(address + 1); return; } //VMDATAL case 0x2118: { - uint16 addr = getVramAddress() + 0; - vramWrite(addr, data); - if(regs.vram_incmode == 0) regs.vram_addr += regs.vram_incsize; + uint16 address = getVramAddress() + 0; + vramWrite(address, data); + if(r.vramIncrementMode == 0) r.vramAddress += r.vramIncrementSize; return; } //VMDATAH case 0x2119: { - uint16 addr = getVramAddress() + 1; - vramWrite(addr, data); - if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize; + uint16 address = getVramAddress() + 1; + vramWrite(address, data); + if(r.vramIncrementMode == 1) r.vramAddress += r.vramIncrementSize; return; } //M7SEL case 0x211a: { - regs.mode7_repeat = (data >> 6) & 3; - regs.mode7_vflip = data & 0x02; - regs.mode7_hflip = data & 0x01; + r.hflipMode7 = data.bit (0); + r.vflipMode7 = data.bit (1); + r.repeatMode7 = data.bits(6,7); return; } //M7A case 0x211b: { - regs.m7a = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.m7a = data << 8 | latch.mode7; + latch.mode7 = data; return; } //M7B case 0x211c: { - regs.m7b = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.m7b = data << 8 | latch.mode7; + latch.mode7 = data; return; } //M7C case 0x211d: { - regs.m7c = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.m7c = data << 8 | latch.mode7; + latch.mode7 = data; return; } //M7D case 0x211e: { - regs.m7d = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.m7d = data << 8 | latch.mode7; + latch.mode7 = data; return; } //M7X case 0x211f: { - regs.m7x = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.m7x = data << 8 | latch.mode7; + latch.mode7 = data; return; } //M7Y case 0x2120: { - regs.m7y = (data << 8) | regs.mode7_latchdata; - regs.mode7_latchdata = data; + r.m7y = data << 8 | latch.mode7; + latch.mode7 = data; return; } //CGADD case 0x2121: { - regs.cgram_addr = data << 1; + r.cgramAddress = data << 1; return; } //CGDATA case 0x2122: { - bool latch = regs.cgram_addr & 1; - uint9 addr = regs.cgram_addr++; - if(!regs.display_disable + bool l = r.cgramAddress & 1; + uint9 address = r.cgramAddress++; + if(!r.displayDisable && vcounter() > 0 && vcounter() < vdisp() && hcounter() >= 88 && hcounter() < 1096 - ) addr = regs.cgram_iaddr; + ) address = latch.cgramAddress; - if(latch == 0) { - regs.cgram_latchdata = data; + if(l == 0) { + latch.cgram = data; } else { - cgramWrite((addr & ~1) + 0, regs.cgram_latchdata); - cgramWrite((addr & ~1) + 1, data & 0x7f); + cgramWrite((address & ~1) + 0, latch.cgram); + cgramWrite((address & ~1) + 1, data & 0x7f); } return; } //W12SEL case 0x2123: { - window.regs.bg2_two_enable = data & 0x80; - window.regs.bg2_two_invert = data & 0x40; - window.regs.bg2_one_enable = data & 0x20; - window.regs.bg2_one_invert = data & 0x10; - window.regs.bg1_two_enable = data & 0x08; - window.regs.bg1_two_invert = data & 0x04; - window.regs.bg1_one_enable = data & 0x02; - window.regs.bg1_one_invert = data & 0x01; + window.r.bg1.oneInvert = data.bit(0); + window.r.bg1.oneEnable = data.bit(1); + window.r.bg1.twoInvert = data.bit(2); + window.r.bg1.twoEnable = data.bit(3); + window.r.bg2.oneInvert = data.bit(4); + window.r.bg2.oneEnable = data.bit(5); + window.r.bg2.twoInvert = data.bit(6); + window.r.bg2.twoEnable = data.bit(7); return; } //W34SEL case 0x2124: { - window.regs.bg4_two_enable = data & 0x80; - window.regs.bg4_two_invert = data & 0x40; - window.regs.bg4_one_enable = data & 0x20; - window.regs.bg4_one_invert = data & 0x10; - window.regs.bg3_two_enable = data & 0x08; - window.regs.bg3_two_invert = data & 0x04; - window.regs.bg3_one_enable = data & 0x02; - window.regs.bg3_one_invert = data & 0x01; + window.r.bg3.oneInvert = data.bit(0); + window.r.bg3.oneEnable = data.bit(1); + window.r.bg3.twoInvert = data.bit(2); + window.r.bg3.twoEnable = data.bit(3); + window.r.bg4.oneInvert = data.bit(4); + window.r.bg4.oneEnable = data.bit(5); + window.r.bg4.twoInvert = data.bit(6); + window.r.bg4.twoEnable = data.bit(7); return; } //WOBJSEL case 0x2125: { - window.regs.col_two_enable = data & 0x80; - window.regs.col_two_invert = data & 0x40; - window.regs.col_one_enable = data & 0x20; - window.regs.col_one_invert = data & 0x10; - window.regs.oam_two_enable = data & 0x08; - window.regs.oam_two_invert = data & 0x04; - window.regs.oam_one_enable = data & 0x02; - window.regs.oam_one_invert = data & 0x01; + window.r.oam.oneInvert = data.bit(0); + window.r.oam.oneEnable = data.bit(1); + window.r.oam.twoInvert = data.bit(2); + window.r.oam.twoEnable = data.bit(3); + window.r.col.oneInvert = data.bit(4); + window.r.col.oneEnable = data.bit(5); + window.r.col.twoInvert = data.bit(6); + window.r.col.twoEnable = data.bit(7); return; } //WH0 case 0x2126: { - window.regs.one_left = data; + window.r.oneLeft = data; return; } //WH1 case 0x2127: { - window.regs.one_right = data; + window.r.oneRight = data; return; } //WH2 case 0x2128: { - window.regs.two_left = data; + window.r.twoLeft = data; return; } //WH3 case 0x2129: { - window.regs.two_right = data; + window.r.twoRight = data; return; } //WBGLOG case 0x212a: { - window.regs.bg4_mask = (data >> 6) & 3; - window.regs.bg3_mask = (data >> 4) & 3; - window.regs.bg2_mask = (data >> 2) & 3; - window.regs.bg1_mask = (data >> 0) & 3; + window.r.bg1.mask = data.bits(0,1); + window.r.bg2.mask = data.bits(2,3); + window.r.bg3.mask = data.bits(4,5); + window.r.bg4.mask = data.bits(6,7); return; } //WOBJLOG case 0x212b: { - window.regs.col_mask = (data >> 2) & 3; - window.regs.oam_mask = (data >> 0) & 3; + window.r.oam.mask = data.bits(0,1); + window.r.col.mask = data.bits(2,3); return; } //TM case 0x212c: { - sprite.regs.main_enable = data & 0x10; - bg4.regs.main_enable = data & 0x08; - bg3.regs.main_enable = data & 0x04; - bg2.regs.main_enable = data & 0x02; - bg1.regs.main_enable = data & 0x01; + bg1.r.aboveEnable = data.bit(0); + bg2.r.aboveEnable = data.bit(1); + bg3.r.aboveEnable = data.bit(2); + bg4.r.aboveEnable = data.bit(3); + oam.r.aboveEnable = data.bit(4); return; } //TS case 0x212d: { - sprite.regs.sub_enable = data & 0x10; - bg4.regs.sub_enable = data & 0x08; - bg3.regs.sub_enable = data & 0x04; - bg2.regs.sub_enable = data & 0x02; - bg1.regs.sub_enable = data & 0x01; + bg1.r.belowEnable = data.bit(0); + bg2.r.belowEnable = data.bit(1); + bg3.r.belowEnable = data.bit(2); + bg4.r.belowEnable = data.bit(3); + oam.r.belowEnable = data.bit(4); return; } //TMW case 0x212e: { - window.regs.oam_main_enable = data & 0x10; - window.regs.bg4_main_enable = data & 0x08; - window.regs.bg3_main_enable = data & 0x04; - window.regs.bg2_main_enable = data & 0x02; - window.regs.bg1_main_enable = data & 0x01; + window.r.bg1.aboveEnable = data.bit(0); + window.r.bg2.aboveEnable = data.bit(1); + window.r.bg3.aboveEnable = data.bit(2); + window.r.bg4.aboveEnable = data.bit(3); + window.r.oam.aboveEnable = data.bit(4); return; } //TSW case 0x212f: { - window.regs.oam_sub_enable = data & 0x10; - window.regs.bg4_sub_enable = data & 0x08; - window.regs.bg3_sub_enable = data & 0x04; - window.regs.bg2_sub_enable = data & 0x02; - window.regs.bg1_sub_enable = data & 0x01; + window.r.bg1.belowEnable = data.bit(0); + window.r.bg2.belowEnable = data.bit(1); + window.r.bg3.belowEnable = data.bit(2); + window.r.bg4.belowEnable = data.bit(3); + window.r.oam.belowEnable = data.bit(4); return; } //CGWSEL case 0x2130: { - window.regs.col_main_mask = (data >> 6) & 3; - window.regs.col_sub_mask = (data >> 4) & 3; - screen.regs.addsub_mode = data & 0x02; - screen.regs.direct_color = data & 0x01; + screen.r.directColor = data.bit (0); + screen.r.blendMode = data.bit (1); + window.r.col.belowMask = data.bits(4,5); + window.r.col.aboveMask = data.bits(6,7); return; } //CGADDSUB case 0x2131: { - screen.regs.color_mode = data & 0x80; - screen.regs.color_halve = data & 0x40; - screen.regs.back_color_enable = data & 0x20; - screen.regs.oam_color_enable = data & 0x10; - screen.regs.bg4_color_enable = data & 0x08; - screen.regs.bg3_color_enable = data & 0x04; - screen.regs.bg2_color_enable = data & 0x02; - screen.regs.bg1_color_enable = data & 0x01; + screen.r.bg1.colorEnable = data.bit(0); + screen.r.bg2.colorEnable = data.bit(1); + screen.r.bg3.colorEnable = data.bit(2); + screen.r.bg4.colorEnable = data.bit(3); + screen.r.oam.colorEnable = data.bit(4); + screen.r.back.colorEnable = data.bit(5); + screen.r.colorHalve = data.bit(6); + screen.r.colorMode = data.bit(7); return; } //COLDATA case 0x2132: { - if(data & 0x80) screen.regs.color_b = data & 0x1f; - if(data & 0x40) screen.regs.color_g = data & 0x1f; - if(data & 0x20) screen.regs.color_r = data & 0x1f; + if(data.bit(5)) screen.r.colorRed = data.bits(0,4); + if(data.bit(6)) screen.r.colorGreen = data.bits(0,4); + if(data.bit(7)) screen.r.colorBlue = data.bits(0,4); return; } //SETINI case 0x2133: { - regs.mode7_extbg = data & 0x40; - regs.pseudo_hires = data & 0x08; - regs.overscan = data & 0x04; - sprite.regs.interlace = data & 0x02; - regs.interlace = data & 0x01; + r.interlace = data.bit(0); + oam.r.interlace = data.bit(1); + r.overscan = data.bit(2); + r.pseudoHires = data.bit(3); + r.extbg = data.bit(6); updateVideoMode(); return; } @@ -617,104 +617,108 @@ auto PPU::write(uint24 addr, uint8 data) -> void { auto PPU::latchCounters() -> void { cpu.synchronizePPU(); - regs.hcounter = hdot(); - regs.vcounter = vcounter(); - regs.counters_latched = true; + r.hcounter = hdot(); + r.vcounter = vcounter(); + latch.counters = true; } auto PPU::updateVideoMode() -> void { - switch(regs.bgmode) { + switch(r.bgMode) { case 0: - bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11; - bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10; - bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5; - bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4; - sprite.regs.priority0 = 3; sprite.regs.priority1 = 6; sprite.regs.priority2 = 9; sprite.regs.priority3 = 12; + bg1.r.mode = Background::Mode::BPP2; + bg2.r.mode = Background::Mode::BPP2; + bg3.r.mode = Background::Mode::BPP2; + bg4.r.mode = Background::Mode::BPP2; + memory::assign(bg1.r.priority, 8, 11); + memory::assign(bg2.r.priority, 7, 10); + memory::assign(bg3.r.priority, 2, 5); + memory::assign(bg4.r.priority, 1, 4); + memory::assign(oam.r.priority, 3, 6, 9, 12); break; case 1: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::BPP4; - bg3.regs.mode = Background::Mode::BPP2; - bg4.regs.mode = Background::Mode::Inactive; - if(regs.bg3_priority) { - bg1.regs.priority0 = 5; bg1.regs.priority1 = 8; - bg2.regs.priority0 = 4; bg2.regs.priority1 = 7; - bg3.regs.priority0 = 1; bg3.regs.priority1 = 10; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 3; sprite.regs.priority2 = 6; sprite.regs.priority3 = 9; + bg1.r.mode = Background::Mode::BPP4; + bg2.r.mode = Background::Mode::BPP4; + bg3.r.mode = Background::Mode::BPP2; + bg4.r.mode = Background::Mode::Inactive; + if(r.bgPriority) { + memory::assign(bg1.r.priority, 5, 8); + memory::assign(bg2.r.priority, 4, 7); + memory::assign(bg3.r.priority, 1, 10); + memory::assign(oam.r.priority, 2, 3, 6, 9); } else { - bg1.regs.priority0 = 6; bg1.regs.priority1 = 9; - bg2.regs.priority0 = 5; bg2.regs.priority1 = 8; - bg3.regs.priority0 = 1; bg3.regs.priority1 = 3; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 7; sprite.regs.priority3 = 10; + memory::assign(bg1.r.priority, 6, 9); + memory::assign(bg2.r.priority, 5, 8); + memory::assign(bg3.r.priority, 1, 3); + memory::assign(oam.r.priority, 2, 4, 7, 10); } break; case 2: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::BPP4; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + bg1.r.mode = Background::Mode::BPP4; + bg2.r.mode = Background::Mode::BPP4; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 3, 7); + memory::assign(bg2.r.priority, 1, 5); + memory::assign(oam.r.priority, 2, 4, 6, 8); break; case 3: - bg1.regs.mode = Background::Mode::BPP8; - bg2.regs.mode = Background::Mode::BPP4; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + bg1.r.mode = Background::Mode::BPP8; + bg2.r.mode = Background::Mode::BPP4; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 3, 7); + memory::assign(bg2.r.priority, 1, 5); + memory::assign(oam.r.priority, 2, 4, 6, 8); break; case 4: - bg1.regs.mode = Background::Mode::BPP8; - bg2.regs.mode = Background::Mode::BPP2; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + bg1.r.mode = Background::Mode::BPP8; + bg2.r.mode = Background::Mode::BPP2; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 3, 7); + memory::assign(bg2.r.priority, 1, 5); + memory::assign(oam.r.priority, 2, 4, 6, 8); break; case 5: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::BPP2; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 7; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 8; + bg1.r.mode = Background::Mode::BPP4; + bg2.r.mode = Background::Mode::BPP2; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 3, 7); + memory::assign(bg2.r.priority, 1, 5); + memory::assign(oam.r.priority, 2, 4, 6, 8); break; case 6: - bg1.regs.mode = Background::Mode::BPP4; - bg2.regs.mode = Background::Mode::Inactive; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 2; bg1.regs.priority1 = 5; - sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 6; + bg1.r.mode = Background::Mode::BPP4; + bg2.r.mode = Background::Mode::Inactive; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 2, 5); + memory::assign(oam.r.priority, 1, 3, 4, 6); break; case 7: - if(regs.mode7_extbg == false) { - bg1.regs.mode = Background::Mode::Mode7; - bg2.regs.mode = Background::Mode::Inactive; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 2; bg1.regs.priority1 = 2; - sprite.regs.priority0 = 1; sprite.regs.priority1 = 3; sprite.regs.priority2 = 4; sprite.regs.priority3 = 5; + if(!r.extbg) { + bg1.r.mode = Background::Mode::Mode7; + bg2.r.mode = Background::Mode::Inactive; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 2); + memory::assign(oam.r.priority, 1, 3, 4, 5); } else { - bg1.regs.mode = Background::Mode::Mode7; - bg2.regs.mode = Background::Mode::Mode7; - bg3.regs.mode = Background::Mode::Inactive; - bg4.regs.mode = Background::Mode::Inactive; - bg1.regs.priority0 = 3; bg1.regs.priority1 = 3; - bg2.regs.priority0 = 1; bg2.regs.priority1 = 5; - sprite.regs.priority0 = 2; sprite.regs.priority1 = 4; sprite.regs.priority2 = 6; sprite.regs.priority3 = 7; + bg1.r.mode = Background::Mode::Mode7; + bg2.r.mode = Background::Mode::Mode7; + bg3.r.mode = Background::Mode::Inactive; + bg4.r.mode = Background::Mode::Inactive; + memory::assign(bg1.r.priority, 3); + memory::assign(bg2.r.priority, 1, 5); + memory::assign(oam.r.priority, 2, 4, 6, 7); } break; } diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index 8719ae58..8799e258 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -13,13 +13,13 @@ PPU ppu; #include "serialization.cpp" PPU::PPU() : -bg1(*this, Background::ID::BG1), -bg2(*this, Background::ID::BG2), -bg3(*this, Background::ID::BG3), -bg4(*this, Background::ID::BG4), -sprite(*this), -window(*this), -screen(*this) { +bg1(Background::ID::BG1), +bg2(Background::ID::BG2), +bg3(Background::ID::BG3), +bg4(Background::ID::BG4) { + ppu1.version = 1; //allowed values: 1 + ppu2.version = 3; //allowed values: 1, 2, 3 + output = new uint32[512 * 512]; output += 16 * 512; //overscan offset } @@ -62,7 +62,7 @@ auto PPU::main() -> void { bg3.run(0); bg4.run(0); if(pixel >= 0) { - sprite.run(); + oam.run(); window.run(); screen.run(); } @@ -70,7 +70,7 @@ auto PPU::main() -> void { } addClocks(14); - sprite.tilefetch(); + oam.tilefetch(); } else { addClocks(1052 + 14 + 136); } @@ -88,9 +88,9 @@ auto PPU::addClocks(uint clocks) -> void { } auto PPU::power() -> void { - for(auto& n : vram) n = random(0x00); - for(auto& n : oam) n = random(0x00); - for(auto& n : cgram) n = random(0x00); + for(auto& n : memory.vram) n = random(0x00); + for(auto& n : memory.oam) n = random(0x00); + for(auto& n : memory.cgram) n = random(0x00); } auto PPU::reset() -> void { @@ -102,93 +102,93 @@ auto PPU::reset() -> void { function void> writer{&PPU::write, this}; bus.map(reader, writer, "00-3f,80-bf:2100-213f"); - regs.ppu1_mdr = random(0xff); - regs.ppu2_mdr = random(0xff); + ppu1.mdr = random(0xff); + ppu2.mdr = random(0xff); - regs.vram_readbuffer = random(0x0000); - regs.oam_latchdata = random(0x00); - regs.cgram_latchdata = random(0x00); - regs.bgofs_latchdata = random(0x00); - regs.mode7_latchdata = random(0x00); - regs.counters_latched = false; - regs.latch_hcounter = 0; - regs.latch_vcounter = 0; + latch.vram = random(0x0000); + latch.oam = random(0x00); + latch.cgram = random(0x00); + latch.bgofs = random(0x00); + latch.mode7 = random(0x00); + latch.counters = false; + latch.hcounter = 0; + latch.vcounter = 0; - regs.oam_iaddr = 0x0000; - regs.cgram_iaddr = 0x00; + latch.oamAddress = 0x0000; + latch.cgramAddress = 0x00; //$2100 INIDISP - regs.display_disable = true; - regs.display_brightness = 0; + r.displayDisable = true; + r.displayBrightness = 0; //$2102 OAMADDL //$2103 OAMADDH - regs.oam_baseaddr = random(0x0000); - regs.oam_addr = random(0x0000); - regs.oam_priority = random(false); + r.oamBaseAddress = random(0x0000); + r.oamAddress = random(0x0000); + r.oamPriority = random(false); //$2105 BGMODE - regs.bg3_priority = false; - regs.bgmode = 0; + r.bgPriority = false; + r.bgMode = 0; //$210d BG1HOFS - regs.mode7_hoffset = random(0x0000); + r.hoffsetMode7 = random(0x0000); //$210e BG1VOFS - regs.mode7_voffset = random(0x0000); + r.voffsetMode7 = random(0x0000); //$2115 VMAIN - regs.vram_incmode = random(1); - regs.vram_mapping = random(0); - regs.vram_incsize = 1; + r.vramIncrementMode = random(1); + r.vramMapping = random(0); + r.vramIncrementSize = 1; //$2116 VMADDL //$2117 VMADDH - regs.vram_addr = random(0x0000); + r.vramAddress = random(0x0000); //$211a M7SEL - regs.mode7_repeat = random(0); - regs.mode7_vflip = random(false); - regs.mode7_hflip = random(false); + r.repeatMode7 = random(0); + r.vflipMode7 = random(false); + r.hflipMode7 = random(false); //$211b M7A - regs.m7a = random(0x0000); + r.m7a = random(0x0000); //$211c M7B - regs.m7b = random(0x0000); + r.m7b = random(0x0000); //$211d M7C - regs.m7c = random(0x0000); + r.m7c = random(0x0000); //$211e M7D - regs.m7d = random(0x0000); + r.m7d = random(0x0000); //$211f M7X - regs.m7x = random(0x0000); + r.m7x = random(0x0000); //$2120 M7Y - regs.m7y = random(0x0000); + r.m7y = random(0x0000); //$2121 CGADD - regs.cgram_addr = random(0x0000); + r.cgramAddress = random(0x0000); //$2133 SETINI - regs.mode7_extbg = random(false); - regs.pseudo_hires = random(false); - regs.overscan = false; - regs.interlace = false; + r.extbg = random(false); + r.pseudoHires = random(false); + r.overscan = false; + r.interlace = false; //$213c OPHCT - regs.hcounter = 0; + r.hcounter = 0; //$213d OPVCT - regs.vcounter = 0; + r.vcounter = 0; bg1.reset(); bg2.reset(); bg3.reset(); bg4.reset(); - sprite.reset(); + oam.reset(); window.reset(); screen.reset(); @@ -208,7 +208,7 @@ auto PPU::scanline() -> void { bg2.scanline(); bg3.scanline(); bg4.scanline(); - sprite.scanline(); + oam.scanline(); window.scanline(); screen.scanline(); @@ -218,10 +218,9 @@ auto PPU::scanline() -> void { } auto PPU::frame() -> void { - sprite.frame(); - - display.interlace = regs.interlace; - display.overscan = regs.overscan; + oam.frame(); + display.interlace = r.interlace; + display.overscan = r.overscan; } auto PPU::refresh() -> void { diff --git a/higan/sfc/ppu/ppu.hpp b/higan/sfc/ppu/ppu.hpp index 4bdaf20b..5378d2f1 100644 --- a/higan/sfc/ppu/ppu.hpp +++ b/higan/sfc/ppu/ppu.hpp @@ -1,7 +1,7 @@ struct PPU : Thread, PPUcounter { alwaysinline auto interlace() const -> bool { return display.interlace; } alwaysinline auto overscan() const -> bool { return display.overscan; } - alwaysinline auto vdisp() const -> uint { return !regs.overscan ? 225 : 240; } + alwaysinline auto vdisp() const -> uint { return r.overscan ? 240 : 225; } PPU(); ~PPU(); @@ -31,14 +31,13 @@ struct PPU : Thread, PPUcounter { auto latchCounters() -> void; auto updateVideoMode() -> void; - uint8 vram[64 * 1024]; - uint8 oam[544]; - uint8 cgram[512]; + struct { + uint8 vram[64 * 1024]; + uint8 oam[544]; + uint8 cgram[512]; + } memory; privileged: - uint ppu1_version = 1; //allowed: 1 - uint ppu2_version = 3; //allowed: 1, 2, 3 - uint32* output = nullptr; struct { @@ -52,55 +51,59 @@ privileged: auto frame() -> void; auto refresh() -> void; + struct { + uint version; + uint8 mdr; + } ppu1, ppu2; + + struct Latches { + uint16 vram; + uint8 oam; + uint8 cgram; + uint8 bgofs; + uint8 mode7; + bool counters; + bool hcounter; + bool vcounter; + + uint10 oamAddress; + uint9 cgramAddress; + } latch; + struct Registers { - uint8 ppu1_mdr; - uint8 ppu2_mdr; - - uint16 vram_readbuffer; - uint8 oam_latchdata; - uint8 cgram_latchdata; - uint8 bgofs_latchdata; - uint8 mode7_latchdata; - bool counters_latched; - bool latch_hcounter; - bool latch_vcounter; - - uint10 oam_iaddr; - uint9 cgram_iaddr; - //$2100 INIDISP - bool display_disable; - uint4 display_brightness; + bool displayDisable; + uint4 displayBrightness; //$2102 OAMADDL //$2103 OAMADDH - uint10 oam_baseaddr; - uint10 oam_addr; - bool oam_priority; + uint10 oamBaseAddress; + uint10 oamAddress; + bool oamPriority; //$2105 BGMODE - bool bg3_priority; - uint8 bgmode; + bool bgPriority; + uint8 bgMode; //$210d BG1HOFS - uint16 mode7_hoffset; + uint16 hoffsetMode7; //$210e BG1VOFS - uint16 mode7_voffset; + uint16 voffsetMode7; //$2115 VMAIN - bool vram_incmode; - uint2 vram_mapping; - uint8 vram_incsize; + bool vramIncrementMode; + uint2 vramMapping; + uint8 vramIncrementSize; //$2116 VMADDL //$2117 VMADDH - uint16 vram_addr; + uint16 vramAddress; //$211a M7SEL - uint2 mode7_repeat; - bool mode7_vflip; - bool mode7_hflip; + uint2 repeatMode7; + bool vflipMode7; + bool hflipMode7; //$211b M7A uint16 m7a; @@ -121,11 +124,11 @@ privileged: uint16 m7y; //$2121 CGADD - uint9 cgram_addr; + uint9 cgramAddress; //$2133 SETINI - bool mode7_extbg; - bool pseudo_hires; + bool extbg; + bool pseudoHires; bool overscan; bool interlace; @@ -134,7 +137,7 @@ privileged: //$213d OPVCT uint16 vcounter; - } regs; + } r; #include "background/background.hpp" #include "screen/screen.hpp" @@ -145,23 +148,23 @@ privileged: Background bg2; Background bg3; Background bg4; - Sprite sprite; + OAM oam; Window window; Screen screen; friend class PPU::Background; - friend class PPU::Sprite; + friend class PPU::OAM; friend class PPU::Window; friend class PPU::Screen; friend class Scheduler; struct Debugger { - hook void> vram_read; - hook void> oam_read; - hook void> cgram_read; - hook void> vram_write; - hook void> oam_write; - hook void> cgram_write; + hook void> vramRead; + hook void> oamRead; + hook void> cgramRead; + hook void> vramWrite; + hook void> oamWrite; + hook void> cgramWrite; } debugger; }; diff --git a/higan/sfc/ppu/screen/screen.cpp b/higan/sfc/ppu/screen/screen.cpp index b063c66a..6a299e82 100644 --- a/higan/sfc/ppu/screen/screen.cpp +++ b/higan/sfc/ppu/screen/screen.cpp @@ -1,133 +1,130 @@ -PPU::Screen::Screen(PPU& self) : self(self) { -} - auto PPU::Screen::scanline() -> void { - lineA = self.output + self.vcounter() * 1024; - lineB = lineA + (self.display.interlace ? 0 : 512); - if(self.display.interlace && self.field()) lineA += 512, lineB += 512; + lineA = ppu.output + ppu.vcounter() * 1024; + lineB = lineA + (ppu.display.interlace ? 0 : 512); + if(ppu.display.interlace && ppu.field()) lineA += 512, lineB += 512; //the first hires pixel of each scanline is transparent //note: exact value initializations are not confirmed on hardware - math.main.color = get_color(0); - math.sub.color = math.main.color; + math.above.color = paletteColor(0); + math.below.color = math.above.color; - math.main.color_enable = !(self.window.regs.col_main_mask & 1); - math.sub.color_enable = !(self.window.regs.col_sub_mask & 1) && regs.back_color_enable; + math.above.colorEnable = !(ppu.window.r.col.aboveMask & 1); + math.below.colorEnable = !(ppu.window.r.col.belowMask & 1) && r.back.colorEnable; math.transparent = true; - math.addsub_mode = false; - math.color_halve = regs.color_halve && !regs.addsub_mode && math.main.color_enable; + math.blendMode = false; + math.colorHalve = r.colorHalve && !r.blendMode && math.above.colorEnable; } auto PPU::Screen::run() -> void { - if(self.vcounter() == 0) return; + if(ppu.vcounter() == 0) return; - bool hires = self.regs.pseudo_hires || self.regs.bgmode == 5 || self.regs.bgmode == 6; - auto sscolor = get_pixel_sub(hires); - auto mscolor = get_pixel_main(); + bool hires = ppu.r.pseudoHires || ppu.r.bgMode == 5 || ppu.r.bgMode == 6; + auto belowColor = below(hires); + auto aboveColor = above(); - *lineA++ = *lineB++ = (self.regs.display_brightness << 15) | (hires ? sscolor : mscolor); - *lineA++ = *lineB++ = (self.regs.display_brightness << 15) | (mscolor); + *lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (hires ? belowColor : aboveColor); + *lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (aboveColor); } -auto PPU::Screen::get_pixel_sub(bool hires) -> uint16 { - if(self.regs.display_disable || (!self.regs.overscan && self.vcounter() >= 225)) return 0; +auto PPU::Screen::below(bool hires) -> uint16 { + if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0; uint priority = 0; - if(self.bg1.output.sub.priority) { - priority = self.bg1.output.sub.priority; - if(regs.direct_color && (self.regs.bgmode == 3 || self.regs.bgmode == 4 || self.regs.bgmode == 7)) { - math.sub.color = get_direct_color(self.bg1.output.sub.palette, self.bg1.output.sub.tile); + if(ppu.bg1.output.below.priority) { + priority = ppu.bg1.output.below.priority; + if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) { + math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.tile); } else { - math.sub.color = get_color(self.bg1.output.sub.palette); + math.below.color = paletteColor(ppu.bg1.output.below.palette); } } - if(self.bg2.output.sub.priority > priority) { - priority = self.bg2.output.sub.priority; - math.sub.color = get_color(self.bg2.output.sub.palette); + if(ppu.bg2.output.below.priority > priority) { + priority = ppu.bg2.output.below.priority; + math.below.color = paletteColor(ppu.bg2.output.below.palette); } - if(self.bg3.output.sub.priority > priority) { - priority = self.bg3.output.sub.priority; - math.sub.color = get_color(self.bg3.output.sub.palette); + if(ppu.bg3.output.below.priority > priority) { + priority = ppu.bg3.output.below.priority; + math.below.color = paletteColor(ppu.bg3.output.below.palette); } - if(self.bg4.output.sub.priority > priority) { - priority = self.bg4.output.sub.priority; - math.sub.color = get_color(self.bg4.output.sub.palette); + if(ppu.bg4.output.below.priority > priority) { + priority = ppu.bg4.output.below.priority; + math.below.color = paletteColor(ppu.bg4.output.below.palette); } - if(self.sprite.output.sub.priority > priority) { - priority = self.sprite.output.sub.priority; - math.sub.color = get_color(self.sprite.output.sub.palette); + if(ppu.oam.output.below.priority > priority) { + priority = ppu.oam.output.below.priority; + math.below.color = paletteColor(ppu.oam.output.below.palette); } - if(math.transparent = (priority == 0)) math.sub.color = get_color(0); + if(math.transparent = (priority == 0)) math.below.color = paletteColor(0); if(!hires) return 0; - if(!math.sub.color_enable) return math.main.color_enable ? math.sub.color : (uint16)0; + if(!math.below.colorEnable) return math.above.colorEnable ? math.below.color : (uint16)0; - return addsub( - math.main.color_enable ? math.sub.color : (uint16)0, - math.addsub_mode ? math.main.color : fixed_color() + return blend( + math.above.colorEnable ? math.below.color : (uint16)0, + math.blendMode ? math.above.color : fixedColor() ); } -auto PPU::Screen::get_pixel_main() -> uint16 { - if(self.regs.display_disable || (!self.regs.overscan && self.vcounter() >= 225)) return 0; +auto PPU::Screen::above() -> uint16 { + if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0; uint priority = 0; - if(self.bg1.output.main.priority) { - priority = self.bg1.output.main.priority; - if(regs.direct_color && (self.regs.bgmode == 3 || self.regs.bgmode == 4 || self.regs.bgmode == 7)) { - math.main.color = get_direct_color(self.bg1.output.main.palette, self.bg1.output.main.tile); + if(ppu.bg1.output.above.priority) { + priority = ppu.bg1.output.above.priority; + if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) { + math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.tile); } else { - math.main.color = get_color(self.bg1.output.main.palette); + math.above.color = paletteColor(ppu.bg1.output.above.palette); } - math.sub.color_enable = regs.bg1_color_enable; + math.below.colorEnable = r.bg1.colorEnable; } - if(self.bg2.output.main.priority > priority) { - priority = self.bg2.output.main.priority; - math.main.color = get_color(self.bg2.output.main.palette); - math.sub.color_enable = regs.bg2_color_enable; + if(ppu.bg2.output.above.priority > priority) { + priority = ppu.bg2.output.above.priority; + math.above.color = paletteColor(ppu.bg2.output.above.palette); + math.below.colorEnable = r.bg2.colorEnable; } - if(self.bg3.output.main.priority > priority) { - priority = self.bg3.output.main.priority; - math.main.color = get_color(self.bg3.output.main.palette); - math.sub.color_enable = regs.bg3_color_enable; + if(ppu.bg3.output.above.priority > priority) { + priority = ppu.bg3.output.above.priority; + math.above.color = paletteColor(ppu.bg3.output.above.palette); + math.below.colorEnable = r.bg3.colorEnable; } - if(self.bg4.output.main.priority > priority) { - priority = self.bg4.output.main.priority; - math.main.color = get_color(self.bg4.output.main.palette); - math.sub.color_enable = regs.bg4_color_enable; + if(ppu.bg4.output.above.priority > priority) { + priority = ppu.bg4.output.above.priority; + math.above.color = paletteColor(ppu.bg4.output.above.palette); + math.below.colorEnable = r.bg4.colorEnable; } - if(self.sprite.output.main.priority > priority) { - priority = self.sprite.output.main.priority; - math.main.color = get_color(self.sprite.output.main.palette); - math.sub.color_enable = regs.oam_color_enable && self.sprite.output.main.palette >= 192; + if(ppu.oam.output.above.priority > priority) { + priority = ppu.oam.output.above.priority; + math.above.color = paletteColor(ppu.oam.output.above.palette); + math.below.colorEnable = r.oam.colorEnable && ppu.oam.output.above.palette >= 192; } if(priority == 0) { - math.main.color = get_color(0); - math.sub.color_enable = regs.back_color_enable; + math.above.color = paletteColor(0); + math.below.colorEnable = r.back.colorEnable; } - if(!self.window.output.sub.color_enable) math.sub.color_enable = false; - math.main.color_enable = self.window.output.main.color_enable; - if(!math.sub.color_enable) return math.main.color_enable ? math.main.color : (uint16)0; + if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false; + math.above.colorEnable = ppu.window.output.above.colorEnable; + if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint16)0; - if(regs.addsub_mode && math.transparent) { - math.addsub_mode = false; - math.color_halve = false; + if(r.blendMode && math.transparent) { + math.blendMode = false; + math.colorHalve = false; } else { - math.addsub_mode = regs.addsub_mode; - math.color_halve = regs.color_halve && math.main.color_enable; + math.blendMode = r.blendMode; + math.colorHalve = r.colorHalve && math.above.colorEnable; } - return addsub( - math.main.color_enable ? math.main.color : (uint16)0, - math.addsub_mode ? math.sub.color : fixed_color() + return blend( + math.above.colorEnable ? math.above.color : (uint16)0, + math.blendMode ? math.below.color : fixedColor() ); } -auto PPU::Screen::addsub(uint x, uint y) -> uint16 { - if(!regs.color_mode) { - if(!math.color_halve) { +auto PPU::Screen::blend(uint x, uint y) const -> uint16 { + if(!r.colorMode) { + if(!math.colorHalve) { uint sum = x + y; uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; return (sum - carry) | (carry - (carry >> 5)); @@ -137,7 +134,7 @@ auto PPU::Screen::addsub(uint x, uint y) -> uint16 { } else { uint diff = x - y + 0x8420; uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; - if(!math.color_halve) { + if(!math.colorHalve) { return (diff - borrow) & (borrow - (borrow >> 5)); } else { return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1; @@ -145,13 +142,13 @@ auto PPU::Screen::addsub(uint x, uint y) -> uint16 { } } -auto PPU::Screen::get_color(uint palette) -> uint16 { +auto PPU::Screen::paletteColor(uint palette) const -> uint16 { palette <<= 1; - self.regs.cgram_iaddr = palette; - return ppu.cgram[palette + 0] + (ppu.cgram[palette + 1] << 8); + ppu.latch.cgramAddress = palette; + return ppu.memory.cgram[palette + 0] + (ppu.memory.cgram[palette + 1] << 8); } -auto PPU::Screen::get_direct_color(uint palette, uint tile) -> uint16 { +auto PPU::Screen::directColor(uint palette, uint tile) const -> uint16 { //palette = -------- BBGGGRRR //tile = ---bgr-- -------- //output = 0BBb00GG Gg0RRRr0 @@ -160,22 +157,22 @@ auto PPU::Screen::get_direct_color(uint palette, uint tile) -> uint16 { + ((palette << 2) & 0x001c) + ((tile >> 9) & 0x0002); } -auto PPU::Screen::fixed_color() const -> uint16 { - return (regs.color_b << 10) | (regs.color_g << 5) | (regs.color_r << 0); +auto PPU::Screen::fixedColor() const -> uint16 { + return r.colorBlue << 10 | r.colorGreen << 5 | r.colorRed << 0; } auto PPU::Screen::reset() -> void { - regs.addsub_mode = random(false); - regs.direct_color = random(false); - regs.color_mode = random(false); - regs.color_halve = random(false); - regs.bg1_color_enable = random(false); - regs.bg2_color_enable = random(false); - regs.bg3_color_enable = random(false); - regs.bg4_color_enable = random(false); - regs.oam_color_enable = random(false); - regs.back_color_enable = random(false); - regs.color_r = random(0); - regs.color_g = random(0); - regs.color_b = random(0); + r.blendMode = random(false); + r.directColor = random(false); + r.colorMode = random(false); + r.colorHalve = random(false); + r.bg1.colorEnable = random(false); + r.bg2.colorEnable = random(false); + r.bg3.colorEnable = random(false); + r.bg4.colorEnable = random(false); + r.oam.colorEnable = random(false); + r.back.colorEnable = random(false); + r.colorBlue = random(0); + r.colorGreen = random(0); + r.colorRed = random(0); } diff --git a/higan/sfc/ppu/screen/screen.hpp b/higan/sfc/ppu/screen/screen.hpp index a771a9e3..e7a29830 100644 --- a/higan/sfc/ppu/screen/screen.hpp +++ b/higan/sfc/ppu/screen/screen.hpp @@ -1,50 +1,45 @@ struct Screen { - uint32* lineA; - uint32* lineB; - - struct Regs { - bool addsub_mode; - bool direct_color; - - bool color_mode; - bool color_halve; - bool bg1_color_enable; - bool bg2_color_enable; - bool bg3_color_enable; - bool bg4_color_enable; - bool oam_color_enable; - bool back_color_enable; - - uint5 color_b; - uint5 color_g; - uint5 color_r; - } regs; - - struct Math { - struct Layer { - uint16 color; - bool color_enable; - } main, sub; - bool transparent; - bool addsub_mode; - bool color_halve; - } math; - - Screen(PPU& self); - auto scanline() -> void; alwaysinline auto run() -> void; auto reset() -> void; - auto get_pixel_sub(bool hires) -> uint16; - auto get_pixel_main() -> uint16; - auto addsub(uint x, uint y) -> uint16; - alwaysinline auto get_color(uint palette) -> uint16; - alwaysinline auto get_direct_color(uint palette, uint tile) -> uint16; - alwaysinline auto fixed_color() const -> uint16; + auto below(bool hires) -> uint16; + auto above() -> uint16; + + auto blend(uint x, uint y) const -> uint16; + alwaysinline auto paletteColor(uint palette) const -> uint16; + alwaysinline auto directColor(uint palette, uint tile) const -> uint16; + alwaysinline auto fixedColor() const -> uint16; auto serialize(serializer&) -> void; - PPU& self; + uint32* lineA; + uint32* lineB; + + struct Registers { + bool blendMode; + bool directColor; + + bool colorMode; + bool colorHalve; + struct Layer { + bool colorEnable; + } bg1, bg2, bg3, bg4, oam, back; + + uint5 colorBlue; + uint5 colorGreen; + uint5 colorRed; + } r; + + struct Math { + struct Screen { + uint16 color; + bool colorEnable; + } above, below; + bool transparent; + bool blendMode; + bool colorHalve; + } math; + friend class PPU; }; diff --git a/higan/sfc/ppu/serialization.cpp b/higan/sfc/ppu/serialization.cpp index f8bddf62..1dc3fe22 100644 --- a/higan/sfc/ppu/serialization.cpp +++ b/higan/sfc/ppu/serialization.cpp @@ -14,107 +14,106 @@ auto PPU::serialize(serializer& s) -> void { Thread::serialize(s); PPUcounter::serialize(s); - s.array(vram); - s.array(oam); - s.array(cgram); + s.array(memory.vram); + s.array(memory.oam); + s.array(memory.cgram); - s.integer(ppu1_version); - s.integer(ppu2_version); + s.integer(ppu1.version); + s.integer(ppu1.mdr); + + s.integer(ppu2.version); + s.integer(ppu2.mdr); s.integer(display.interlace); s.integer(display.overscan); - s.integer(regs.ppu1_mdr); - s.integer(regs.ppu2_mdr); + s.integer(latch.vram); + s.integer(latch.oam); + s.integer(latch.cgram); + s.integer(latch.bgofs); + s.integer(latch.mode7); + s.integer(latch.counters); + s.integer(latch.hcounter); + s.integer(latch.vcounter); - s.integer(regs.vram_readbuffer); - s.integer(regs.oam_latchdata); - s.integer(regs.cgram_latchdata); - s.integer(regs.bgofs_latchdata); - s.integer(regs.mode7_latchdata); - s.integer(regs.counters_latched); - s.integer(regs.latch_hcounter); - s.integer(regs.latch_vcounter); + s.integer(latch.oamAddress); + s.integer(latch.cgramAddress); - s.integer(regs.oam_iaddr); - s.integer(regs.cgram_iaddr); + s.integer(r.displayDisable); + s.integer(r.displayBrightness); - s.integer(regs.display_disable); - s.integer(regs.display_brightness); + s.integer(r.oamBaseAddress); + s.integer(r.oamAddress); + s.integer(r.oamPriority); - s.integer(regs.oam_baseaddr); - s.integer(regs.oam_addr); - s.integer(regs.oam_priority); + s.integer(r.bgPriority); + s.integer(r.bgMode); - s.integer(regs.bg3_priority); - s.integer(regs.bgmode); + s.integer(r.hoffsetMode7); + s.integer(r.voffsetMode7); - s.integer(regs.mode7_hoffset); - s.integer(regs.mode7_voffset); + s.integer(r.vramIncrementMode); + s.integer(r.vramMapping); + s.integer(r.vramIncrementSize); - s.integer(regs.vram_incmode); - s.integer(regs.vram_mapping); - s.integer(regs.vram_incsize); + s.integer(r.vramAddress); - s.integer(regs.vram_addr); + s.integer(r.repeatMode7); + s.integer(r.vflipMode7); + s.integer(r.hflipMode7); - s.integer(regs.mode7_repeat); - s.integer(regs.mode7_vflip); - s.integer(regs.mode7_hflip); + s.integer(r.m7a); + s.integer(r.m7b); + s.integer(r.m7c); + s.integer(r.m7d); + s.integer(r.m7x); + s.integer(r.m7y); - s.integer(regs.m7a); - s.integer(regs.m7b); - s.integer(regs.m7c); - s.integer(regs.m7d); - s.integer(regs.m7x); - s.integer(regs.m7y); + s.integer(r.cgramAddress); - s.integer(regs.cgram_addr); + s.integer(r.extbg); + s.integer(r.pseudoHires); + s.integer(r.overscan); + s.integer(r.interlace); - s.integer(regs.mode7_extbg); - s.integer(regs.pseudo_hires); - s.integer(regs.overscan); - s.integer(regs.interlace); - - s.integer(regs.hcounter); - s.integer(regs.vcounter); + s.integer(r.hcounter); + s.integer(r.vcounter); bg1.serialize(s); bg2.serialize(s); bg3.serialize(s); bg4.serialize(s); - sprite.serialize(s); + oam.serialize(s); window.serialize(s); screen.serialize(s); } auto PPU::Background::serialize(serializer& s) -> void { - s.integer(regs.tiledata_addr); - s.integer(regs.screen_addr); - s.integer(regs.screen_size); - s.integer(regs.mosaic); - s.integer(regs.tile_size); + s.integer(r.tiledataAddress); + s.integer(r.screenAddress); + s.integer(r.screenSize); + s.integer(r.mosaic); + s.integer(r.tileSize); - s.integer(regs.mode); - s.integer(regs.priority0); - s.integer(regs.priority1); + s.integer(r.mode); + s.array(r.priority); - s.integer(regs.main_enable); - s.integer(regs.sub_enable); + s.integer(r.aboveEnable); + s.integer(r.belowEnable); - s.integer(regs.hoffset); - s.integer(regs.voffset); + s.integer(r.hoffset); + s.integer(r.voffset); - s.integer(cache.hoffset); - s.integer(cache.voffset); + s.integer(latch.hoffset); + s.integer(latch.voffset); - s.integer(output.main.priority); - s.integer(output.main.palette); - s.integer(output.main.tile); + s.integer(output.above.priority); + s.integer(output.above.palette); + s.integer(output.above.tile); - s.integer(output.sub.priority); - s.integer(output.sub.palette); - s.integer(output.sub.tile); + s.integer(output.below.priority); + s.integer(output.below.palette); + s.integer(output.below.tile); s.integer(x); s.integer(y); @@ -128,32 +127,34 @@ auto PPU::Background::serialize(serializer& s) -> void { s.integer(mosaic.hcounter); s.integer(mosaic.hoffset); - s.integer(tile_counter); + s.integer(tileCounter); s.integer(tile); s.integer(priority); - s.integer(palette_number); - s.integer(palette_index); + s.integer(paletteNumber); + s.integer(paletteIndex); s.array(data); } -auto PPU::Sprite::serialize(serializer& s) -> void { - for(auto n : range(128)) { - s.integer(list[n].x); - s.integer(list[n].y); - s.integer(list[n].character); - s.integer(list[n].nameselect); - s.integer(list[n].vflip); - s.integer(list[n].hflip); - s.integer(list[n].priority); - s.integer(list[n].palette); - s.integer(list[n].size); - } +auto PPU::OAM::serialize(serializer& s) -> void { + s.integer(r.aboveEnable); + s.integer(r.belowEnable); + s.integer(r.interlace); + + s.integer(r.baseSize); + s.integer(r.nameSelect); + s.integer(r.tiledataAddress); + s.integer(r.firstSprite); + + s.array(r.priority); + + s.integer(r.timeOver); + s.integer(r.rangeOver); s.integer(t.x); s.integer(t.y); - s.integer(t.item_count); - s.integer(t.tile_count); + s.integer(t.itemCount); + s.integer(t.tileCount); s.integer(t.active); for(auto p : range(2)) { @@ -167,124 +168,111 @@ auto PPU::Sprite::serialize(serializer& s) -> void { s.integer(t.tile[p][n].priority); s.integer(t.tile[p][n].palette); s.integer(t.tile[p][n].hflip); - s.integer(t.tile[p][n].d0); - s.integer(t.tile[p][n].d1); - s.integer(t.tile[p][n].d2); - s.integer(t.tile[p][n].d3); + s.integer(t.tile[p][n].data); } } - s.integer(regs.main_enable); - s.integer(regs.sub_enable); - s.integer(regs.interlace); + s.integer(output.above.priority); + s.integer(output.above.palette); - s.integer(regs.base_size); - s.integer(regs.nameselect); - s.integer(regs.tiledata_addr); - s.integer(regs.first_sprite); + s.integer(output.below.priority); + s.integer(output.below.palette); - s.integer(regs.priority0); - s.integer(regs.priority1); - s.integer(regs.priority2); - s.integer(regs.priority3); - - s.integer(regs.time_over); - s.integer(regs.range_over); - - s.integer(output.main.priority); - s.integer(output.main.palette); - - s.integer(output.sub.priority); - s.integer(output.sub.palette); + for(auto n : range(128)) { + s.integer(list[n].x); + s.integer(list[n].y); + s.integer(list[n].character); + s.integer(list[n].nameSelect); + s.integer(list[n].vflip); + s.integer(list[n].hflip); + s.integer(list[n].priority); + s.integer(list[n].palette); + s.integer(list[n].size); + } } auto PPU::Window::serialize(serializer& s) -> void { - s.integer(regs.bg1_one_enable); - s.integer(regs.bg1_one_invert); - s.integer(regs.bg1_two_enable); - s.integer(regs.bg1_two_invert); + s.integer(r.bg1.oneEnable); + s.integer(r.bg1.oneInvert); + s.integer(r.bg1.twoEnable); + s.integer(r.bg1.twoInvert); + s.integer(r.bg1.mask); + s.integer(r.bg1.aboveEnable); + s.integer(r.bg1.belowEnable); - s.integer(regs.bg2_one_enable); - s.integer(regs.bg2_one_invert); - s.integer(regs.bg2_two_enable); - s.integer(regs.bg2_two_invert); + s.integer(r.bg2.oneEnable); + s.integer(r.bg2.oneInvert); + s.integer(r.bg2.twoEnable); + s.integer(r.bg2.twoInvert); + s.integer(r.bg2.mask); + s.integer(r.bg2.aboveEnable); + s.integer(r.bg2.belowEnable); - s.integer(regs.bg3_one_enable); - s.integer(regs.bg3_one_invert); - s.integer(regs.bg3_two_enable); - s.integer(regs.bg3_two_invert); + s.integer(r.bg3.oneEnable); + s.integer(r.bg3.oneInvert); + s.integer(r.bg3.twoEnable); + s.integer(r.bg3.twoInvert); + s.integer(r.bg3.mask); + s.integer(r.bg3.aboveEnable); + s.integer(r.bg3.belowEnable); - s.integer(regs.bg4_one_enable); - s.integer(regs.bg4_one_invert); - s.integer(regs.bg4_two_enable); - s.integer(regs.bg4_two_invert); + s.integer(r.bg4.oneEnable); + s.integer(r.bg4.oneInvert); + s.integer(r.bg4.twoEnable); + s.integer(r.bg4.twoInvert); + s.integer(r.bg4.mask); + s.integer(r.bg4.aboveEnable); + s.integer(r.bg4.belowEnable); - s.integer(regs.oam_one_enable); - s.integer(regs.oam_one_invert); - s.integer(regs.oam_two_enable); - s.integer(regs.oam_two_invert); + s.integer(r.oam.oneEnable); + s.integer(r.oam.oneInvert); + s.integer(r.oam.twoEnable); + s.integer(r.oam.twoInvert); + s.integer(r.oam.mask); + s.integer(r.oam.aboveEnable); + s.integer(r.oam.belowEnable); - s.integer(regs.col_one_enable); - s.integer(regs.col_one_invert); - s.integer(regs.col_two_enable); - s.integer(regs.col_two_invert); + s.integer(r.col.oneEnable); + s.integer(r.col.oneInvert); + s.integer(r.col.twoEnable); + s.integer(r.col.twoInvert); + s.integer(r.col.mask); + s.integer(r.col.aboveMask); + s.integer(r.col.belowMask); - s.integer(regs.one_left); - s.integer(regs.one_right); - s.integer(regs.two_left); - s.integer(regs.two_right); + s.integer(r.oneLeft); + s.integer(r.oneRight); + s.integer(r.twoLeft); + s.integer(r.twoRight); - s.integer(regs.bg1_mask); - s.integer(regs.bg2_mask); - s.integer(regs.bg3_mask); - s.integer(regs.bg4_mask); - s.integer(regs.oam_mask); - s.integer(regs.col_mask); - - s.integer(regs.bg1_main_enable); - s.integer(regs.bg1_sub_enable); - s.integer(regs.bg2_main_enable); - s.integer(regs.bg2_sub_enable); - s.integer(regs.bg3_main_enable); - s.integer(regs.bg3_sub_enable); - s.integer(regs.bg4_main_enable); - s.integer(regs.bg4_sub_enable); - s.integer(regs.oam_main_enable); - s.integer(regs.oam_sub_enable); - - s.integer(regs.col_main_mask); - s.integer(regs.col_sub_mask); - - s.integer(output.main.color_enable); - s.integer(output.sub.color_enable); + s.integer(output.above.colorEnable); + s.integer(output.below.colorEnable); s.integer(x); - s.integer(one); - s.integer(two); } auto PPU::Screen::serialize(serializer& s) -> void { - s.integer(regs.addsub_mode); - s.integer(regs.direct_color); + s.integer(r.blendMode); + s.integer(r.directColor); - s.integer(regs.color_mode); - s.integer(regs.color_halve); - s.integer(regs.bg1_color_enable); - s.integer(regs.bg2_color_enable); - s.integer(regs.bg3_color_enable); - s.integer(regs.bg4_color_enable); - s.integer(regs.oam_color_enable); - s.integer(regs.back_color_enable); + s.integer(r.colorMode); + s.integer(r.colorHalve); + s.integer(r.bg1.colorEnable); + s.integer(r.bg2.colorEnable); + s.integer(r.bg3.colorEnable); + s.integer(r.bg4.colorEnable); + s.integer(r.oam.colorEnable); + s.integer(r.back.colorEnable); - s.integer(regs.color_b); - s.integer(regs.color_g); - s.integer(regs.color_r); + s.integer(r.colorBlue); + s.integer(r.colorGreen); + s.integer(r.colorRed); - s.integer(math.main.color); - s.integer(math.main.color_enable); - s.integer(math.sub.color); - s.integer(math.sub.color_enable); + s.integer(math.above.color); + s.integer(math.above.colorEnable); + s.integer(math.below.color); + s.integer(math.below.colorEnable); s.integer(math.transparent); - s.integer(math.addsub_mode); - s.integer(math.color_halve); + s.integer(math.blendMode); + s.integer(math.colorHalve); } diff --git a/higan/sfc/ppu/sprite/list.cpp b/higan/sfc/ppu/sprite/list.cpp index f4451e5e..a0b56938 100644 --- a/higan/sfc/ppu/sprite/list.cpp +++ b/higan/sfc/ppu/sprite/list.cpp @@ -1,4 +1,4 @@ -auto PPU::Sprite::update(uint10 addr, uint8 data) -> void { +auto PPU::OAM::update(uint10 addr, uint8 data) -> void { if(!addr.bit(9)) { uint n = addr >> 2; //sprite# addr &= 3; @@ -9,11 +9,11 @@ auto PPU::Sprite::update(uint10 addr, uint8 data) -> void { } else if(addr == 2) { list[n].character = data; } else { //(addr == 3) - list[n].vflip = data.bit (7); + list[n].nameSelect = data.bit (0); + list[n].palette = data.bits(1,3); + list[n].priority = data.bits(4,5); list[n].hflip = data.bit (6); - list[n].priority = data.bits(5,4); - list[n].palette = data.bits(3,1); - list[n].nameselect = data.bit (0); + list[n].vflip = data.bit (7); } } else { uint n = (addr & 0x1f) << 2; //sprite# @@ -28,27 +28,27 @@ auto PPU::Sprite::update(uint10 addr, uint8 data) -> void { } } -auto PPU::Sprite::synchronize() -> void { - for(auto n : range(544)) update(n, ppu.oam[n]); +auto PPU::OAM::synchronize() -> void { + for(auto n : range(544)) update(n, ppu.memory.oam[n]); } -auto PPU::Sprite::Object::width() const -> uint{ +auto PPU::OAM::Object::width() const -> uint{ if(size == 0) { - static uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16}; - return width[ppu.sprite.regs.base_size]; + static const uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16}; + return width[ppu.oam.r.baseSize]; } else { - static uint width[] = {16, 32, 64, 32, 64, 64, 32, 32}; - return width[ppu.sprite.regs.base_size]; + static const uint width[] = {16, 32, 64, 32, 64, 64, 32, 32}; + return width[ppu.oam.r.baseSize]; } } -auto PPU::Sprite::Object::height() const -> uint { +auto PPU::OAM::Object::height() const -> uint { if(size == 0) { - if(ppu.sprite.regs.interlace && ppu.sprite.regs.base_size >= 6) return 16; - static uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32}; - return height[ppu.sprite.regs.base_size]; + if(ppu.oam.r.interlace && ppu.oam.r.baseSize >= 6) return 16; //hardware quirk + static const uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32}; + return height[ppu.oam.r.baseSize]; } else { - static uint height[] = {16, 32, 64, 32, 64, 64, 64, 32}; - return height[ppu.sprite.regs.base_size]; + static const uint height[] = {16, 32, 64, 32, 64, 64, 64, 32}; + return height[ppu.oam.r.baseSize]; } } diff --git a/higan/sfc/ppu/sprite/sprite.cpp b/higan/sfc/ppu/sprite/sprite.cpp index 3bcd27d4..905b800a 100644 --- a/higan/sfc/ppu/sprite/sprite.cpp +++ b/higan/sfc/ppu/sprite/sprite.cpp @@ -1,107 +1,102 @@ #include "list.cpp" -PPU::Sprite::Sprite(PPU& self) : self(self) { +auto PPU::OAM::addressReset() -> void { + ppu.r.oamAddress = ppu.r.oamBaseAddress; + setFirstSprite(); } -auto PPU::Sprite::address_reset() -> void { - self.regs.oam_addr = self.regs.oam_baseaddr; - set_first_sprite(); +auto PPU::OAM::setFirstSprite() -> void { + r.firstSprite = !ppu.r.oamPriority ? 0 : ppu.r.oamAddress >> 2; } -auto PPU::Sprite::set_first_sprite() -> void { - regs.first_sprite = !self.regs.oam_priority ? 0 : self.regs.oam_addr >> 2; +auto PPU::OAM::frame() -> void { + r.timeOver = false; + r.rangeOver = false; } -auto PPU::Sprite::frame() -> void { - regs.time_over = false; - regs.range_over = false; -} - -auto PPU::Sprite::scanline() -> void { +auto PPU::OAM::scanline() -> void { t.x = 0; - t.y = self.vcounter(); + t.y = ppu.vcounter(); - t.item_count = 0; - t.tile_count = 0; + t.itemCount = 0; + t.tileCount = 0; t.active = !t.active; - auto oam_item = t.item[t.active]; - auto oam_tile = t.tile[t.active]; + auto oamItem = t.item[t.active]; + auto oamTile = t.tile[t.active]; - if(t.y == self.vdisp() && !self.regs.display_disable) address_reset(); - if(t.y >= self.vdisp() - 1) return; + if(t.y == ppu.vdisp() && !ppu.r.displayDisable) addressReset(); + if(t.y >= ppu.vdisp() - 1) return; - for(auto n : range(32)) oam_item[n].valid = false; //default to invalid - for(auto n : range(34)) oam_tile[n].valid = false; //default to invalid + for(auto n : range(32)) oamItem[n].valid = false; //default to invalid + for(auto n : range(34)) oamTile[n].valid = false; //default to invalid for(auto n : range(128)) { - uint7 sprite = regs.first_sprite + n; - if(!on_scanline(list[sprite])) continue; - if(t.item_count++ >= 32) break; - oam_item[t.item_count - 1] = {true, sprite}; + uint7 sprite = r.firstSprite + n; + if(!onScanline(list[sprite])) continue; + if(t.itemCount++ >= 32) break; + oamItem[t.itemCount - 1] = {true, sprite}; } - if(t.item_count > 0 && oam_item[t.item_count - 1].valid) { - ppu.regs.oam_iaddr = 0x0200 + (oam_item[t.item_count - 1].index >> 2); + if(t.itemCount > 0 && oamItem[t.itemCount - 1].valid) { + ppu.latch.oamAddress = 0x0200 + (oamItem[t.itemCount - 1].index >> 2); } } -auto PPU::Sprite::on_scanline(Object& sprite) -> bool { +auto PPU::OAM::onScanline(Object& sprite) -> bool { if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false; - int height = sprite.height() >> regs.interlace; + int height = sprite.height() >> r.interlace; if(t.y >= sprite.y && t.y < (sprite.y + height)) return true; if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true; return false; } -auto PPU::Sprite::run() -> void { - output.main.priority = 0; - output.sub.priority = 0; +auto PPU::OAM::run() -> void { + output.above.priority = 0; + output.below.priority = 0; - auto oam_tile = t.tile[!t.active]; - uint priority_table[] = {regs.priority0, regs.priority1, regs.priority2, regs.priority3}; + auto oamTile = t.tile[!t.active]; uint x = t.x++; for(auto n : range(34)) { - auto tile = oam_tile[n]; + const auto& tile = oamTile[n]; if(!tile.valid) break; - int px = x - sclip<9>(tile.x); + int px = x - (int9)tile.x; if(px & ~7) continue; - uint mask = 0x80 >> (!tile.hflip ? px : 7 - px); - uint color; - color = ((bool)(tile.d0 & mask)) << 0; - color |= ((bool)(tile.d1 & mask)) << 1; - color |= ((bool)(tile.d2 & mask)) << 2; - color |= ((bool)(tile.d3 & mask)) << 3; + uint color = 0, shift = tile.hflip ? px : 7 - px; + color += tile.data >> (shift + 0) & 1; + color += tile.data >> (shift + 7) & 2; + color += tile.data >> (shift + 14) & 4; + color += tile.data >> (shift + 21) & 8; if(color) { - if(regs.main_enable) { - output.main.palette = tile.palette + color; - output.main.priority = priority_table[tile.priority]; + if(r.aboveEnable) { + output.above.palette = tile.palette + color; + output.above.priority = r.priority[tile.priority]; } - if(regs.sub_enable) { - output.sub.palette = tile.palette + color; - output.sub.priority = priority_table[tile.priority]; + if(r.belowEnable) { + output.below.palette = tile.palette + color; + output.below.priority = r.priority[tile.priority]; } } } } -auto PPU::Sprite::tilefetch() -> void { - auto oam_item = t.item[t.active]; - auto oam_tile = t.tile[t.active]; +auto PPU::OAM::tilefetch() -> void { + auto oamItem = t.item[t.active]; + auto oamTile = t.tile[t.active]; for(int i = 31; i >= 0; i--) { - if(!oam_item[i].valid) continue; - auto sprite = list[oam_item[i].index]; + if(!oamItem[i].valid) continue; + const auto& sprite = list[oamItem[i].index]; - uint tile_width = sprite.width() >> 3; + uint tileWidth = sprite.width() >> 3; int x = sprite.x; int y = (t.y - sprite.y) & 0xff; - if(regs.interlace) y <<= 1; + if(r.interlace) y <<= 1; if(sprite.vflip) { if(sprite.width() == sprite.height()) { @@ -113,60 +108,60 @@ auto PPU::Sprite::tilefetch() -> void { } } - if(regs.interlace) { - y = !sprite.vflip ? y + self.field() : y - self.field(); + if(r.interlace) { + y = !sprite.vflip ? y + ppu.field() : y - ppu.field(); } x &= 511; y &= 255; - uint16 tiledata_addr = regs.tiledata_addr; + uint16 tiledataAddress = r.tiledataAddress; uint16 chrx = (sprite.character >> 0) & 15; uint16 chry = (sprite.character >> 4) & 15; - if(sprite.nameselect) { - tiledata_addr += (256 * 32) + (regs.nameselect << 13); + if(sprite.nameSelect) { + tiledataAddress += (256 * 32) + (r.nameSelect << 13); } chry += (y >> 3); chry &= 15; chry <<= 4; - for(uint tx = 0; tx < tile_width; tx++) { + for(uint tx : range(tileWidth)) { uint sx = (x + (tx << 3)) & 511; if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; - if(t.tile_count++ >= 34) break; + if(t.tileCount++ >= 34) break; - uint n = t.tile_count - 1; - oam_tile[n].valid = true; - oam_tile[n].x = sx; - oam_tile[n].priority = sprite.priority; - oam_tile[n].palette = 128 + (sprite.palette << 4); - oam_tile[n].hflip = sprite.hflip; + uint n = t.tileCount - 1; + oamTile[n].valid = true; + oamTile[n].x = sx; + oamTile[n].priority = sprite.priority; + oamTile[n].palette = 128 + (sprite.palette << 4); + oamTile[n].hflip = sprite.hflip; - uint mx = !sprite.hflip ? tx : (tile_width - 1) - tx; - uint pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5); + uint mx = !sprite.hflip ? tx : (tileWidth - 1) - tx; + uint pos = tiledataAddress + ((chry + ((chrx + mx) & 15)) << 5); uint16 addr = (pos & 0xffe0) + ((y & 7) * 2); - oam_tile[n].d0 = ppu.vram[addr + 0]; - oam_tile[n].d1 = ppu.vram[addr + 1]; - self.addClocks(2); + oamTile[n].data.byte(0) = ppu.memory.vram[addr + 0]; + oamTile[n].data.byte(1) = ppu.memory.vram[addr + 1]; + ppu.addClocks(2); - oam_tile[n].d2 = ppu.vram[addr + 16]; - oam_tile[n].d3 = ppu.vram[addr + 17]; - self.addClocks(2); + oamTile[n].data.byte(2) = ppu.memory.vram[addr + 16]; + oamTile[n].data.byte(3) = ppu.memory.vram[addr + 17]; + ppu.addClocks(2); } } - if(t.tile_count < 34) self.addClocks((34 - t.tile_count) * 4); - regs.time_over |= (t.tile_count > 34); - regs.range_over |= (t.item_count > 32); + if(t.tileCount < 34) ppu.addClocks((34 - t.tileCount) * 4); + r.timeOver |= (t.tileCount > 34); + r.rangeOver |= (t.itemCount > 32); } -auto PPU::Sprite::reset() -> void { +auto PPU::OAM::reset() -> void { for(auto n : range(128)) { list[n].x = 0; list[n].y = 0; list[n].character = 0; - list[n].nameselect = 0; + list[n].nameSelect = 0; list[n].vflip = 0; list[n].hflip = 0; list[n].priority = 0; @@ -178,8 +173,8 @@ auto PPU::Sprite::reset() -> void { t.x = 0; t.y = 0; - t.item_count = 0; - t.tile_count = 0; + t.itemCount = 0; + t.tileCount = 0; t.active = 0; for(auto p : range(2)) { @@ -193,32 +188,26 @@ auto PPU::Sprite::reset() -> void { t.tile[p][n].priority = 0; t.tile[p][n].palette = 0; t.tile[p][n].hflip = 0; - t.tile[p][n].d0 = 0; - t.tile[p][n].d1 = 0; - t.tile[p][n].d2 = 0; - t.tile[p][n].d3 = 0; + t.tile[p][n].data = 0; } } - regs.main_enable = random(false); - regs.sub_enable = random(false); - regs.interlace = random(false); + r.aboveEnable = random(false); + r.belowEnable = random(false); + r.interlace = random(false); - regs.base_size = random(0); - regs.nameselect = random(0); - regs.tiledata_addr = (random(0x0000) & 3) << 14; - regs.first_sprite = 0; + r.baseSize = random(0); + r.nameSelect = random(0); + r.tiledataAddress = (random(0x0000) & 3) << 14; + r.firstSprite = 0; - regs.priority0 = 0; - regs.priority1 = 0; - regs.priority2 = 0; - regs.priority3 = 0; + for(auto& p : r.priority) p = 0; - regs.time_over = false; - regs.range_over = false; + r.timeOver = false; + r.rangeOver = false; - output.main.palette = 0; - output.main.priority = 0; - output.sub.palette = 0; - output.sub.priority = 0; + output.above.palette = 0; + output.above.priority = 0; + output.below.palette = 0; + output.below.priority = 0; } diff --git a/higan/sfc/ppu/sprite/sprite.hpp b/higan/sfc/ppu/sprite/sprite.hpp index f60c6327..04e48c98 100644 --- a/higan/sfc/ppu/sprite/sprite.hpp +++ b/higan/sfc/ppu/sprite/sprite.hpp @@ -1,17 +1,36 @@ -struct Sprite { - struct Object { - uint9 x; - uint8 y; - uint8 character; - uint1 nameselect; - uint1 vflip; - uint1 hflip; - uint2 priority; - uint3 palette; - uint1 size; - alwaysinline auto width() const -> uint; - alwaysinline auto height() const -> uint; - } list[128]; +struct OAM { + alwaysinline auto addressReset() -> void; + alwaysinline auto setFirstSprite() -> void; + auto frame() -> void; + auto scanline() -> void; + auto run() -> void; + auto tilefetch() -> void; + auto reset() -> void; + + struct Object; + auto onScanline(Object&) -> bool; + + //list.cpp + auto update(uint10 addr, uint8 data) -> void; + auto synchronize() -> void; + + auto serialize(serializer&) -> void; + + struct Registers { + bool aboveEnable; + bool belowEnable; + bool interlace; + + uint3 baseSize; + uint2 nameSelect; + uint16 tiledataAddress; + uint7 firstSprite; + + uint priority[4]; + + bool timeOver; + bool rangeOver; + } r; struct Item { bool valid; @@ -19,71 +38,47 @@ struct Sprite { }; struct Tile { - bool valid; - uint9 x; - uint2 priority; - uint8 palette; - uint1 hflip; - uint8 d0, d1, d2, d3; + bool valid; + uint9 x; + uint2 priority; + uint8 palette; + uint1 hflip; + uint32 data; }; struct State { uint x; uint y; - uint item_count; - uint tile_count; + uint itemCount; + uint tileCount; bool active; Item item[2][32]; Tile tile[2][34]; } t; - struct Regs { - bool main_enable; - bool sub_enable; - bool interlace; - - uint3 base_size; - uint2 nameselect; - uint16 tiledata_addr; - uint7 first_sprite; - - uint priority0; - uint priority1; - uint priority2; - uint priority3; - - bool time_over; - bool range_over; - } regs; - struct Output { struct Pixel { uint priority; //0 = none (transparent) uint8 palette; - } main, sub; + } above, below; } output; - Sprite(PPU& self); + struct Object { + alwaysinline auto width() const -> uint; + alwaysinline auto height() const -> uint; - //list.cpp - auto update(uint10 addr, uint8 data) -> void; - auto synchronize() -> void; + uint9 x; + uint8 y; + uint8 character; + uint1 nameSelect; + uint1 vflip; + uint1 hflip; + uint2 priority; + uint3 palette; + uint1 size; + } list[128]; - //sprite.cpp - alwaysinline auto address_reset() -> void; - alwaysinline auto set_first_sprite() -> void; - auto frame() -> void; - auto scanline() -> void; - auto run() -> void; - auto tilefetch() -> void; - auto reset() -> void; - - auto on_scanline(Object&) -> bool; - - auto serialize(serializer&) -> void; - - PPU& self; friend class PPU; }; diff --git a/higan/sfc/ppu/window/window.cpp b/higan/sfc/ppu/window/window.cpp index 0356d118..ae000159 100644 --- a/higan/sfc/ppu/window/window.cpp +++ b/higan/sfc/ppu/window/window.cpp @@ -1,167 +1,107 @@ -PPU::Window::Window(PPU& self) : self(self) { -} - auto PPU::Window::scanline() -> void { x = 0; } auto PPU::Window::run() -> void { - bool main, sub; - one = (x >= regs.one_left && x <= regs.one_right); - two = (x >= regs.two_left && x <= regs.two_right); + bool one = (x >= r.oneLeft && x <= r.oneRight); + bool two = (x >= r.twoLeft && x <= r.twoRight); x++; - test( - main, sub, - regs.bg1_one_enable, regs.bg1_one_invert, - regs.bg1_two_enable, regs.bg1_two_invert, - regs.bg1_mask, regs.bg1_main_enable, regs.bg1_sub_enable - ); - if(main) self.bg1.output.main.priority = 0; - if(sub) self.bg1.output.sub.priority = 0; - - test( - main, sub, - regs.bg2_one_enable, regs.bg2_one_invert, - regs.bg2_two_enable, regs.bg2_two_invert, - regs.bg2_mask, regs.bg2_main_enable, regs.bg2_sub_enable - ); - if(main) self.bg2.output.main.priority = 0; - if(sub) self.bg2.output.sub.priority = 0; - - test( - main, sub, - regs.bg3_one_enable, regs.bg3_one_invert, - regs.bg3_two_enable, regs.bg3_two_invert, - regs.bg3_mask, regs.bg3_main_enable, regs.bg3_sub_enable - ); - if(main) self.bg3.output.main.priority = 0; - if(sub) self.bg3.output.sub.priority = 0; - - test( - main, sub, - regs.bg4_one_enable, regs.bg4_one_invert, - regs.bg4_two_enable, regs.bg4_two_invert, - regs.bg4_mask, regs.bg4_main_enable, regs.bg4_sub_enable - ); - if(main) self.bg4.output.main.priority = 0; - if(sub) self.bg4.output.sub.priority = 0; - - test( - main, sub, - regs.oam_one_enable, regs.oam_one_invert, - regs.oam_two_enable, regs.oam_two_invert, - regs.oam_mask, regs.oam_main_enable, regs.oam_sub_enable - ); - if(main) self.sprite.output.main.priority = 0; - if(sub) self.sprite.output.sub.priority = 0; - - test( - main, sub, - regs.col_one_enable, regs.col_one_invert, - regs.col_two_enable, regs.col_two_invert, - regs.col_mask, true, true - ); - - switch(regs.col_main_mask) { - case 0: main = true; break; - case 1: break; - case 2: main = !main; break; - case 3: main = false; break; + if(test(r.bg1.oneEnable, one ^ r.bg1.oneInvert, r.bg1.twoEnable, two ^ r.bg1.twoInvert, r.bg1.mask)) { + if(r.bg1.aboveEnable) ppu.bg1.output.above.priority = 0; + if(r.bg1.belowEnable) ppu.bg1.output.below.priority = 0; } - switch(regs.col_sub_mask) { - case 0: sub = true; break; - case 1: break; - case 2: sub = !sub; break; - case 3: sub = false; break; + if(test(r.bg2.oneEnable, one ^ r.bg2.oneInvert, r.bg2.twoEnable, two ^ r.bg2.twoInvert, r.bg2.mask)) { + if(r.bg2.aboveEnable) ppu.bg2.output.above.priority = 0; + if(r.bg2.belowEnable) ppu.bg2.output.below.priority = 0; } - output.main.color_enable = main; - output.sub.color_enable = sub; + if(test(r.bg3.oneEnable, one ^ r.bg3.oneInvert, r.bg3.twoEnable, two ^ r.bg3.twoInvert, r.bg3.mask)) { + if(r.bg3.aboveEnable) ppu.bg3.output.above.priority = 0; + if(r.bg3.belowEnable) ppu.bg3.output.below.priority = 0; + } + + if(test(r.bg4.oneEnable, one ^ r.bg4.oneInvert, r.bg4.twoEnable, two ^ r.bg4.twoInvert, r.bg4.mask)) { + if(r.bg4.aboveEnable) ppu.bg4.output.above.priority = 0; + if(r.bg4.belowEnable) ppu.bg4.output.below.priority = 0; + } + + if(test(r.oam.oneEnable, one ^ r.oam.oneInvert, r.oam.twoEnable, two ^ r.oam.twoInvert, r.oam.mask)) { + if(r.oam.aboveEnable) ppu.oam.output.above.priority = 0; + if(r.oam.belowEnable) ppu.oam.output.below.priority = 0; + } + + bool value = test(r.col.oneEnable, one ^ r.col.oneInvert, r.col.twoEnable, two ^ r.col.twoInvert, r.col.mask); + bool array[] = {true, value, !value, false}; + output.above.colorEnable = array[r.col.aboveMask]; + output.below.colorEnable = array[r.col.belowMask]; } -auto PPU::Window::test( - bool& main, bool& sub, - bool one_enable, bool one_invert, - bool two_enable, bool two_invert, - uint8 mask, bool main_enable, bool sub_enable -) -> void { - bool one = Window::one ^ one_invert; - bool two = Window::two ^ two_invert; - bool output; - - if(one_enable == false && two_enable == false) { - output = false; - } else if(one_enable == true && two_enable == false) { - output = one; - } else if(one_enable == false && two_enable == true) { - output = two; - } else { - switch(mask) { - case 0: output = (one | two) == 1; break; - case 1: output = (one & two) == 1; break; - case 2: output = (one ^ two) == 1; break; - case 3: output = (one ^ two) == 0; break; - } - } - - main = main_enable ? output : false; - sub = sub_enable ? output : false; +auto PPU::Window::test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool { + if(!oneEnable) return two && twoEnable; + if(!twoEnable) return one; + if(mask == 0) return (one | two); + if(mask == 1) return (one & two); + return (one ^ two) == 3 - mask; } auto PPU::Window::reset() -> void { - regs.bg1_one_enable = random(false); - regs.bg1_one_invert = random(false); - regs.bg1_two_enable = random(false); - regs.bg1_two_invert = random(false); - regs.bg2_one_enable = random(false); - regs.bg2_one_invert = random(false); - regs.bg2_two_enable = random(false); - regs.bg2_two_invert = random(false); - regs.bg3_one_enable = random(false); - regs.bg3_one_invert = random(false); - regs.bg3_two_enable = random(false); - regs.bg3_two_invert = random(false); - regs.bg4_one_enable = random(false); - regs.bg4_one_invert = random(false); - regs.bg4_two_enable = random(false); - regs.bg4_two_invert = random(false); - regs.oam_one_enable = random(false); - regs.oam_one_invert = random(false); - regs.oam_two_enable = random(false); - regs.oam_two_invert = random(false); - regs.col_one_enable = random(false); - regs.col_one_invert = random(false); - regs.col_two_enable = random(false); - regs.col_two_invert = random(false); - regs.one_left = random(0x00); - regs.one_right = random(0x00); - regs.two_left = random(0x00); - regs.two_right = random(0x00); - regs.bg1_mask = random(0); - regs.bg2_mask = random(0); - regs.bg3_mask = random(0); - regs.bg4_mask = random(0); - regs.oam_mask = random(0); - regs.col_mask = random(0); - regs.bg1_main_enable = random(false); - regs.bg1_sub_enable = random(false); - regs.bg2_main_enable = random(false); - regs.bg2_sub_enable = random(false); - regs.bg3_main_enable = random(false); - regs.bg3_sub_enable = random(false); - regs.bg4_main_enable = random(false); - regs.bg4_sub_enable = random(false); - regs.oam_main_enable = random(false); - regs.oam_sub_enable = random(false); - regs.col_main_mask = random(0); - regs.col_sub_mask = random(0); + r.bg1.oneEnable = random(false); + r.bg1.oneInvert = random(false); + r.bg1.twoEnable = random(false); + r.bg1.twoInvert = random(false); + r.bg1.mask = random(0); + r.bg1.aboveEnable = random(false); + r.bg1.belowEnable = random(false); - output.main.color_enable = 0; - output.sub.color_enable = 0; + r.bg2.oneEnable = random(false); + r.bg2.oneInvert = random(false); + r.bg2.twoEnable = random(false); + r.bg2.twoInvert = random(false); + r.bg2.mask = random(0); + r.bg2.aboveEnable = random(false); + r.bg2.belowEnable = random(false); + + r.bg3.oneEnable = random(false); + r.bg3.oneInvert = random(false); + r.bg3.twoEnable = random(false); + r.bg3.twoInvert = random(false); + r.bg3.mask = random(0); + r.bg3.aboveEnable = random(false); + r.bg3.belowEnable = random(false); + + r.bg4.oneEnable = random(false); + r.bg4.oneInvert = random(false); + r.bg4.twoEnable = random(false); + r.bg4.twoInvert = random(false); + r.bg4.mask = random(0); + r.bg4.aboveEnable = random(false); + r.bg4.belowEnable = random(false); + + r.oam.oneEnable = random(false); + r.oam.oneInvert = random(false); + r.oam.twoEnable = random(false); + r.oam.twoInvert = random(false); + r.oam.mask = random(0); + r.oam.aboveEnable = random(false); + r.oam.belowEnable = random(false); + + r.col.oneEnable = random(false); + r.col.oneInvert = random(false); + r.col.twoEnable = random(false); + r.col.twoInvert = random(false); + r.col.mask = random(0); + r.col.aboveMask = random(0); + r.col.belowMask = random(0); + + r.oneLeft = random(0x00); + r.oneRight = random(0x00); + r.twoLeft = random(0x00); + r.twoRight = random(0x00); + + output.above.colorEnable = 0; + output.below.colorEnable = 0; x = 0; - one = 0; - two = 0; } diff --git a/higan/sfc/ppu/window/window.hpp b/higan/sfc/ppu/window/window.hpp index 27985570..b43f7994 100644 --- a/higan/sfc/ppu/window/window.hpp +++ b/higan/sfc/ppu/window/window.hpp @@ -1,89 +1,47 @@ struct Window { - struct { - bool bg1_one_enable; - bool bg1_one_invert; - bool bg1_two_enable; - bool bg1_two_invert; + auto scanline() -> void; + auto run() -> void; + auto test(bool oneEnable, bool one, bool twoEnable, bool two, uint mask) -> bool; + auto reset() -> void; - bool bg2_one_enable; - bool bg2_one_invert; - bool bg2_two_enable; - bool bg2_two_invert; + auto serialize(serializer&) -> void; - bool bg3_one_enable; - bool bg3_one_invert; - bool bg3_two_enable; - bool bg3_two_invert; + struct Registers { + struct Layer { + bool oneEnable; + bool oneInvert; + bool twoEnable; + bool twoInvert; + uint2 mask; + bool aboveEnable; + bool belowEnable; + } bg1, bg2, bg3, bg4, oam; - bool bg4_one_enable; - bool bg4_one_invert; - bool bg4_two_enable; - bool bg4_two_invert; + struct Color { + bool oneEnable; + bool oneInvert; + bool twoEnable; + bool twoInvert; + uint2 mask; + uint2 aboveMask; + uint2 belowMask; + } col; - bool oam_one_enable; - bool oam_one_invert; - bool oam_two_enable; - bool oam_two_invert; - - bool col_one_enable; - bool col_one_invert; - bool col_two_enable; - bool col_two_invert; - - uint8 one_left; - uint8 one_right; - uint8 two_left; - uint8 two_right; - - uint2 bg1_mask; - uint2 bg2_mask; - uint2 bg3_mask; - uint2 bg4_mask; - uint2 oam_mask; - uint2 col_mask; - - bool bg1_main_enable; - bool bg1_sub_enable; - bool bg2_main_enable; - bool bg2_sub_enable; - bool bg3_main_enable; - bool bg3_sub_enable; - bool bg4_main_enable; - bool bg4_sub_enable; - bool oam_main_enable; - bool oam_sub_enable; - - uint2 col_main_mask; - uint2 col_sub_mask; - } regs; + uint8 oneLeft; + uint8 oneRight; + uint8 twoLeft; + uint8 twoRight; + } r; struct Output { struct Pixel { - bool color_enable; - } main, sub; + bool colorEnable; + } above, below; } output; struct { uint x; - bool one; - bool two; }; - Window(PPU& self); - - auto scanline() -> void; - auto run() -> void; - auto reset() -> void; - - auto test( - bool& main, bool& sub, - bool one_enable, bool one_invert, - bool two_enable, bool two_invert, - uint8 mask, bool main_enable, bool sub_enable - ) -> void; - - auto serialize(serializer&) -> void; - - PPU& self; friend class PPU; }; diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 01467661..0571d22d 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -9,11 +9,6 @@ System system; #include "random.cpp" #include "serialization.cpp" -auto System::loaded() const -> bool { return _loaded; } -auto System::region() const -> Region { return _region; } -auto System::cpuFrequency() const -> uint { return _cpuFrequency; } -auto System::apuFrequency() const -> uint { return _apuFrequency; } - auto System::run() -> void { scheduler.enter(); } diff --git a/higan/sfc/system/system.hpp b/higan/sfc/system/system.hpp index cbb79bdf..bc9ce36c 100644 --- a/higan/sfc/system/system.hpp +++ b/higan/sfc/system/system.hpp @@ -5,10 +5,10 @@ struct Interface; struct System { enum class Region : bool { NTSC = 0, PAL = 1 }; - auto loaded() const -> bool; - auto region() const -> Region; - auto cpuFrequency() const -> uint; - auto apuFrequency() const -> uint; + inline auto loaded() const -> bool { return _loaded; } + inline auto region() const -> Region { return _region; } + inline auto cpuFrequency() const -> uint { return _cpuFrequency; } + inline auto apuFrequency() const -> uint { return _apuFrequency; } auto run() -> void; auto runToSave() -> void; diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index 69a619ae..8830677e 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -72,7 +72,7 @@ Presentation::Presentation() { settings["Video/ColorEmulation"].setValue(colorEmulation.checked()); if(emulator) emulator->set("Color Emulation", colorEmulation.checked()); }); - scanlineEmulation.setText("Scanlines").setChecked(settings["Video/ScanlineEmulation"].boolean()).onToggle([&] { + scanlineEmulation.setVisible(false).setText("Scanlines").setChecked(settings["Video/ScanlineEmulation"].boolean()).onToggle([&] { settings["Video/ScanlineEmulation"].setValue(scanlineEmulation.checked()); if(emulator) emulator->set("Scanline Emulation", scanlineEmulation.checked()); }); diff --git a/nall/memory.hpp b/nall/memory.hpp index 3e997183..d56101f6 100644 --- a/nall/memory.hpp +++ b/nall/memory.hpp @@ -1,7 +1,133 @@ #pragma once -#include - -#include +#include #include -#include + +namespace nall { namespace memory { + inline auto allocate(uint size) -> void*; + inline auto allocate(uint size, uint8_t data) -> void*; + + inline auto resize(void* target, uint size) -> void*; + + inline auto free(void* target) -> void; + + inline auto compare(const void* target, uint capacity, const void* source, uint size) -> int; + inline auto compare(const void* target, const void* source, uint size) -> int; + + inline auto icompare(const void* target, uint capacity, const void* source, uint size) -> int; + inline auto icompare(const void* target, const void* source, uint size) -> int; + + inline auto copy(void* target, uint capacity, const void* source, uint size) -> void*; + inline auto copy(void* target, const void* source, uint size) -> void*; + + inline auto move(void* target, uint capacity, const void* source, uint size) -> void*; + inline auto move(void* target, const void* source, uint size) -> void*; + + inline auto fill(void* target, uint capacity, uint8_t data = 0x00) -> void*; + + template inline auto assign(T* target) -> void {} + template inline auto assign(T* target, const U& value, P&&... p) -> void; +}} + +namespace nall { + +//implementation notes: +//memcmp, memcpy, memmove have terrible performance on small block sizes (FreeBSD 10.0-amd64) +//as this library is used extensively by nall/string, and most strings tend to be small, +//this library hand-codes these functions instead. surprisingly, it's a substantial speedup + +auto memory::allocate(uint size) -> void* { + return malloc(size); +} + +auto memory::allocate(uint size, uint8_t data) -> void* { + auto result = malloc(size); + if(result) fill(result, size, data); + return result; +} + +auto memory::resize(void* target, uint size) -> void* { + return realloc(target, size); +} + +auto memory::free(void* target) -> void { + ::free(target); +} + +auto memory::compare(const void* target, uint capacity, const void* source, uint size) -> int { + auto t = (int8_t*)target; + auto s = (int8_t*)source; + auto l = min(capacity, size); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x != y) return x - y; + } + return 0; +} + +auto memory::compare(const void* target, const void* source, uint size) -> int { + return compare(target, size, source, size); +} + +auto memory::icompare(const void* target, uint capacity, const void* source, uint size) -> int { + auto t = (int8_t*)target; + auto s = (int8_t*)source; + auto l = min(capacity, size); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x - 'A' < 26) x += 32; + if(y - 'A' < 26) y += 32; + if(x != y) return x - y; + } + return 0; +} + +auto memory::icompare(const void* target, const void* source, uint size) -> int { + return icompare(target, size, source, size); +} + +auto memory::copy(void* target, uint capacity, const void* source, uint size) -> void* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size); + while(l--) *t++ = *s++; + return target; +} + +auto memory::copy(void* target, const void* source, uint size) -> void* { + return copy(target, size, source, size); +} + +auto memory::move(void* target, uint capacity, const void* source, uint size) -> void* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size); + if(t < s) { + while(l--) *t++ = *s++; + } else { + t += l; + s += l; + while(l--) *--t = *--s; + } + return target; +} + +auto memory::move(void* target, const void* source, uint size) -> void* { + return move(target, size, source, size); +} + +auto memory::fill(void* target, uint capacity, uint8_t data) -> void* { + auto t = (uint8_t*)target; + while(capacity--) *t++ = data; + return target; +} + +template +auto memory::assign(T* target, const U& value, P&&... p) -> void { + *target++ = value; + assign(target, forward

(p)...); +} + +} diff --git a/nall/memory/memory.hpp b/nall/memory/memory.hpp deleted file mode 100644 index f73297db..00000000 --- a/nall/memory/memory.hpp +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include - -namespace nall { - -namespace memory { - inline auto allocate(unsigned size) -> void*; - inline auto allocate(unsigned size, uint8_t data) -> void*; - - inline auto resize(void* target, unsigned size) -> void*; - - inline auto free(void* target) -> void; - - inline auto compare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed; - inline auto compare(const void* target, const void* source, unsigned size) -> signed; - - inline auto icompare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed; - inline auto icompare(const void* target, const void* source, unsigned size) -> signed; - - inline auto copy(void* target, unsigned capacity, const void* source, unsigned size) -> void*; - inline auto copy(void* target, const void* source, unsigned size) -> void*; - - inline auto move(void* target, unsigned capacity, const void* source, unsigned size) -> void*; - inline auto move(void* target, const void* source, unsigned size) -> void*; - - inline auto fill(void* target, unsigned capacity, uint8_t data = 0x00) -> void*; -} - -} - -#include - -namespace nall { - -//implementation notes: -//memcmp, memcpy, memmove have terrible performance on small block sizes (FreeBSD 10.0-amd64) -//as this library is used extensively by nall/string, and most strings tend to be small, -//this library hand-codes these functions instead. surprisingly, it's a substantial speedup - -auto memory::allocate(unsigned size) -> void* { - return malloc(size); -} - -auto memory::allocate(unsigned size, uint8_t data) -> void* { - auto result = malloc(size); - if(result) fill(result, size, data); - return result; -} - -auto memory::resize(void* target, unsigned size) -> void* { - return realloc(target, size); -} - -auto memory::free(void* target) -> void { - ::free(target); -} - -auto memory::compare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed { - auto t = (int8_t*)target; - auto s = (int8_t*)source; - auto l = min(capacity, size); - while(l--) { - auto x = *t++; - auto y = *s++; - if(x != y) return x - y; - } - return 0; -} - -auto memory::compare(const void* target, const void* source, unsigned size) -> signed { - return compare(target, size, source, size); -} - -auto memory::icompare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed { - auto t = (int8_t*)target; - auto s = (int8_t*)source; - auto l = min(capacity, size); - while(l--) { - auto x = *t++; - auto y = *s++; - if(x - 'A' < 26) x += 32; - if(y - 'A' < 26) y += 32; - if(x != y) return x - y; - } - return 0; -} - -auto memory::icompare(const void* target, const void* source, unsigned size) -> signed { - return icompare(target, size, source, size); -} - -auto memory::copy(void* target, unsigned capacity, const void* source, unsigned size) -> void* { - auto t = (uint8_t*)target; - auto s = (uint8_t*)source; - auto l = min(capacity, size); - while(l--) *t++ = *s++; - return target; -} - -auto memory::copy(void* target, const void* source, unsigned size) -> void* { - return copy(target, size, source, size); -} - -auto memory::move(void* target, unsigned capacity, const void* source, unsigned size) -> void* { - auto t = (uint8_t*)target; - auto s = (uint8_t*)source; - auto l = min(capacity, size); - if(t < s) { - while(l--) *t++ = *s++; - } else { - t += l; - s += l; - while(l--) *--t = *--s; - } - return target; -} - -auto memory::move(void* target, const void* source, unsigned size) -> void* { - return move(target, size, source, size); -} - -auto memory::fill(void* target, unsigned capacity, uint8_t data) -> void* { - auto t = (uint8_t*)target; - while(capacity--) *t++ = data; - return target; -} - -} diff --git a/nall/memory/pool.hpp b/nall/memory/pool.hpp deleted file mode 100644 index 17d11f74..00000000 --- a/nall/memory/pool.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -namespace nall { -namespace memory { - -template -struct pool_spsc { - signed* list = nullptr; - uint8_t* data = nullptr; - unsigned slot = 0; - - pool_spsc() { - list = (signed*)memory::allocate(Capacity * sizeof(signed)); - data = (uint8_t*)memory::allocate(Capacity * Size); - for(unsigned n = 0; n < Capacity; n++) list[n] = n; - } - - ~pool_spsc() { - memory::free(list); - memory::free(data); - } - - auto allocate(unsigned size) -> void* { - if(size == 0) return nullptr; - if(size > Size) return memory::allocate(size); - signed offset = list[slot]; - if(offset < 0) return memory::allocate(size); - list[slot] = -1; - slot = (slot + 1) % Capacity; - return (void*)(data + offset * Size); - } - - auto allocate(unsigned size, uint8_t data) -> void* { - auto result = allocate(size); - memset(result, data, size); - return result; - } - - auto resize(void* target, unsigned size) -> void* { - if(target == nullptr) return allocate(size); - signed offset = ((uint8_t*)target - data) / Size; - if(offset < 0 || offset >= Capacity) return memory::resize(target, size); - if(size <= Size) return target; - slot = (slot - 1) % Capacity; - list[slot] = offset; - return memory::allocate(size); - } - - auto free(void* target) -> void { - if(target == nullptr) return; - signed offset = ((uint8_t*)target - data) / Size; - if(offset < 0 || offset >= Capacity) return memory::free(target); - slot = (slot - 1) % Capacity; - list[slot] = offset; - } - - pool_spsc(const pool_spsc&) = delete; - pool_spsc& operator=(const pool_spsc&) = delete; -}; - -} -}