diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 22629d61..a1b8676e 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -6,7 +6,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "097.19"; + static const string Version = "097.20"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/v30mz/modrm.cpp b/higan/processor/v30mz/modrm.cpp index 06b3bb3b..9e825b04 100644 --- a/higan/processor/v30mz/modrm.cpp +++ b/higan/processor/v30mz/modrm.cpp @@ -1,19 +1,14 @@ -//ModRM functions -//d7-d6 => mod -//d5-d3 => reg -//d2-d0 => mem - auto V30MZ::modRM() -> void { - auto byte = fetch(); - modrm.mod = byte >> 6; - modrm.reg = byte >> 3; - modrm.mem = byte >> 0; + auto data = fetch(); + modrm.mem = data.bits(0,2); + modrm.reg = data.bits(3,5); + modrm.mod = data.bits(6,7); if(modrm.mod == 0 && modrm.mem == 6) { modrm.segment = segment(r.ds); modrm.address = fetch(Word); } else { - switch(modrm.reg) { + switch(modrm.mem) { case 0: modrm.segment = segment(r.ds); modrm.address = r.bx + r.si; break; case 1: modrm.segment = segment(r.ds); modrm.address = r.bx + r.di; break; case 2: modrm.segment = segment(r.ss); modrm.address = r.bp + r.si; break; diff --git a/higan/ws/cpu/interrupt.cpp b/higan/ws/cpu/interrupt.cpp index a5db055e..d0cc3b61 100644 --- a/higan/ws/cpu/interrupt.cpp +++ b/higan/ws/cpu/interrupt.cpp @@ -3,9 +3,10 @@ auto CPU::poll() -> void { state.halt = false; if(!V30MZ::r.f.i) return; + //find and execute first pending interrupt in order of priority (7-0) for(int n = 7; n >= 0; n--) { if(r.interruptStatus & r.interruptEnable & (1 << n)) { - interrupt(r.interruptBase + n); + return interrupt(r.interruptBase + n); } } } diff --git a/higan/ws/memory/memory.cpp b/higan/ws/memory/memory.cpp index cd2ad309..271ca68d 100644 --- a/higan/ws/memory/memory.cpp +++ b/higan/ws/memory/memory.cpp @@ -12,12 +12,12 @@ auto IO::power() -> void { } auto IO::portRead(uint16 addr) -> uint8 { - print("[", hex(addr, 4L), "]: port unmapped\n"); +//print("[", hex(addr, 4L), "]: port unmapped\n"); return 0x00; } auto IO::portWrite(uint16 addr, uint8 data) -> void { - print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n"); +//print("[", hex(addr, 4L), "] = ", hex(data, 2L), ": port unmapped\n"); } auto Bus::read(uint20 addr) -> uint8 { diff --git a/higan/ws/ppu/io.cpp b/higan/ws/ppu/io.cpp index a0262e21..5be47943 100644 --- a/higan/ws/ppu/io.cpp +++ b/higan/ws/ppu/io.cpp @@ -3,7 +3,7 @@ auto PPU::portRead(uint16 addr) -> uint8 { if(addr == 0x0000) { return ( r.screenTwoWindowEnable << 5 - | r.screenTwoWindowMode << 4 + | r.screenTwoWindowInvert << 4 | r.spriteWindowEnable << 3 | r.spriteEnable << 2 | r.screenTwoEnable << 1 @@ -122,7 +122,7 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void { //DISP_CTRL if(addr == 0x0000) { r.screenTwoWindowEnable = data.bit(5); - r.screenTwoWindowMode = data.bit(4); + r.screenTwoWindowInvert = data.bit(4); r.spriteWindowEnable = data.bit(3); r.spriteEnable = data.bit(2); r.screenTwoEnable = data.bit(1); @@ -292,8 +292,8 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void { //PALMONO if(addr >= 0x0020 && addr <= 0x003f) { - r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 1] = data.bits(6,4); - r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0); + r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 1] = data.bits(6,4); + r.palette[addr.bits(4,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0); return; } diff --git a/higan/ws/ppu/ppu.cpp b/higan/ws/ppu/ppu.cpp index 7c92aad7..8edb79eb 100644 --- a/higan/ws/ppu/ppu.cpp +++ b/higan/ws/ppu/ppu.cpp @@ -4,6 +4,7 @@ namespace WonderSwan { PPU ppu; #include "io.cpp" +#include "render.cpp" #include "video.cpp" auto PPU::Enter() -> void { @@ -11,7 +12,21 @@ auto PPU::Enter() -> void { } auto PPU::main() -> void { - step(256); + if(status.vclk < 144) { + for(uint x = 0; x < 224; x++) { + pixel = {Pixel::Source::None, 0xfff}; + renderScreenOne(); + renderScreenTwo(); + renderSprite(); + output[status.vclk * 224 + status.hclk] = pixel.color; + step(1); + } + for(uint x = 224; x < 256; x++) { + step(1); + } + } else { + step(256); + } scanline(); } diff --git a/higan/ws/ppu/ppu.hpp b/higan/ws/ppu/ppu.hpp index 5dd77eb2..fe63c058 100644 --- a/higan/ws/ppu/ppu.hpp +++ b/higan/ws/ppu/ppu.hpp @@ -8,20 +8,33 @@ struct PPU : Thread, IO { auto step(uint clocks) -> void; auto power() -> void; + //io.cpp auto portRead(uint16 addr) -> uint8 override; auto portWrite(uint16 addr, uint8 data) -> void override; - uint16 output[224 * 144]; + //render.cpp + auto renderScreenOne() -> void; + auto renderScreenTwo() -> void; + auto renderSprite() -> void; + + //state + uint12 output[224 * 144]; struct Status { uint vclk; uint hclk; } status; + struct Pixel { + enum class Source : uint { None, ScreenOne, ScreenTwo, Sprite }; + Source source; + uint12 color; + } pixel; + struct Registers { //$0000 DISP_CTRL bool screenTwoWindowEnable; - bool screenTwoWindowMode; + bool screenTwoWindowInvert; bool spriteWindowEnable; bool spriteEnable; bool screenTwoEnable; diff --git a/higan/ws/ppu/render.cpp b/higan/ws/ppu/render.cpp new file mode 100644 index 00000000..24c57182 --- /dev/null +++ b/higan/ws/ppu/render.cpp @@ -0,0 +1,121 @@ +auto PPU::renderScreenOne() -> void { + if(!r.screenOneEnable) return; + + uint8 scrollX = status.hclk + r.scrollOneX; + uint8 scrollY = status.vclk + r.scrollOneY; + + uint14 tilemapOffset = r.screenOneMapBase << 11; + tilemapOffset += (scrollY >> 3) << 6; + tilemapOffset += (scrollX >> 3) << 1; + + uint16 tile; + tile.byte(0) = iram[tilemapOffset++]; + tile.byte(1) = iram[tilemapOffset++]; + + uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); + + uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1); + uint8 d0 = iram[tileOffset++]; + uint8 d1 = iram[tileOffset++]; + + uint8 tileMask = 0x80 >> tileX; + uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0); + + uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor]; + uint4 poolColor = 15 - r.pool[paletteColor]; + + pixel = {Pixel::Source::ScreenOne, poolColor << 0 | poolColor << 4 | poolColor << 8}; +} + +auto PPU::renderScreenTwo() -> void { + if(!r.screenTwoEnable) return; + + bool windowInside = ( + status.hclk >= r.screenTwoWindowX0 + && status.hclk <= r.screenTwoWindowX1 + && status.vclk >= r.screenTwoWindowY0 + && status.vclk <= r.screenTwoWindowY1 + ); + windowInside ^= r.screenTwoWindowInvert; + if(r.screenTwoWindowEnable && !windowInside) return; + + uint8 scrollX = status.hclk + r.scrollTwoX; + uint8 scrollY = status.vclk + r.scrollTwoY; + + uint14 tilemapOffset = r.screenTwoMapBase << 11; + tilemapOffset += (scrollY >> 3) << 6; + tilemapOffset += (scrollX >> 3) << 1; + + uint16 tile; + tile.byte(0) = iram[tilemapOffset++]; + tile.byte(1) = iram[tilemapOffset++]; + + uint3 tileX = (scrollX & 7) ^ (tile.bit(14) ? 7 : 0); + uint3 tileY = (scrollY & 7) ^ (tile.bit(15) ? 7 : 0); + + uint14 tileOffset = 0x2000 + (tile.bits(0,8) << 4) + (tileY << 1); + uint8 d0 = iram[tileOffset++]; + uint8 d1 = iram[tileOffset++]; + + uint8 tileMask = 0x80 >> tileX; + uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0); + + if(tile.bit(11) && tileColor == 0) return; + uint3 paletteColor = r.palette[tile.bits(9,12)].color[tileColor]; + uint4 poolColor = 15 - r.pool[paletteColor]; + + pixel = {Pixel::Source::ScreenTwo, poolColor << 0 | poolColor << 4 | poolColor << 8}; +} + +auto PPU::renderSprite() -> void { + if(!r.spriteEnable) return; + + bool windowInside = ( + status.hclk >= r.spriteWindowX0 + && status.hclk <= r.spriteWindowX1 + && status.vclk >= r.spriteWindowY0 + && status.vclk <= r.spriteWindowY1 + ); + + uint14 spriteBase = r.spriteBase << 9; + + uint7 spriteIndex = r.spriteFirst; + uint8 spriteCount = max(128, (uint)r.spriteCount); + while(spriteCount--) { + uint32 sprite; + sprite.byte(0) = iram[spriteBase + (spriteIndex << 2) + 0]; + sprite.byte(1) = iram[spriteBase + (spriteIndex << 2) + 1]; + sprite.byte(2) = iram[spriteBase + (spriteIndex << 2) + 2]; + sprite.byte(3) = iram[spriteBase + (spriteIndex << 2) + 3]; + spriteIndex++; + + if(r.spriteWindowEnable && sprite.bit(12) && !windowInside) continue; + if(pixel.source == Pixel::Source::ScreenTwo && !sprite.bit(13)) continue; + + uint8 spriteY = sprite.bits(16,23); + uint8 spriteX = sprite.bits(24,31); + + if(status.hclk < spriteX) continue; + if(status.hclk > (uint8)(spriteX + 7)) continue; + if(status.vclk < spriteY) continue; + if(status.vclk > (uint8)(spriteY + 7)) continue; + + uint3 tileX = (uint8)(status.hclk - spriteX) ^ (sprite.bit(14) ? 7 : 0); + uint3 tileY = (uint8)(status.vclk - spriteY) ^ (sprite.bit(15) ? 7 : 0); + + uint14 tileOffset = 0x2000 + (sprite.bits(0,8) << 4) + (tileY << 1); + uint8 d0 = iram[tileOffset++]; + uint8 d1 = iram[tileOffset++]; + + uint8 tileMask = 0x80 >> tileX; + uint2 tileColor = (d0 & tileMask ? 1 : 0) | (d1 & tileMask ? 2 : 0); + + if(sprite.bit(11) && tileColor == 0) continue; + uint3 paletteColor = r.palette[8 + sprite.bits(9,11)].color[tileColor]; + uint4 poolColor = 15 - r.pool[paletteColor]; + + pixel = {Pixel::Source::Sprite, poolColor << 0 | poolColor << 4 | poolColor << 8}; + return; + } +} diff --git a/higan/ws/ppu/video.cpp b/higan/ws/ppu/video.cpp index eb9f530d..e0c7e7be 100644 --- a/higan/ws/ppu/video.cpp +++ b/higan/ws/ppu/video.cpp @@ -9,12 +9,12 @@ Video::Video() { auto Video::power() -> void { memory::fill(output(), 224 * 224 * sizeof(uint32)); - for(auto color : range(1 << 12)) { + for(uint12 color : range(1 << 12)) { paletteLiteral[color] = color; - uint R = (uint4)(color >> 8); - uint G = (uint4)(color >> 4); - uint B = (uint4)(color >> 0); + uint B = color.bits(0, 3); + uint G = color.bits(4, 7); + uint R = color.bits(8,11); R = image::normalize(R, 4, 16); G = image::normalize(G, 4, 16); @@ -26,10 +26,10 @@ auto Video::power() -> void { auto Video::refresh() -> void { for(uint y = 0; y < 144; y++) { auto source = ppu.output + y * 224; - auto target = output() + y * 224; for(uint x = 0; x < 224; x++) { auto color = paletteStandard[*source++]; - *target++ = color; + //*(output() + y * 224 + x) = color; + *(output() + (223 - x) * 224 + 40 + y) = color; } }