diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 445f56d4..d859cd3d 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "102"; + static const string Version = "102.01"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/controller/controller.cpp b/higan/md/controller/controller.cpp index 96195fb6..d4572a4f 100644 --- a/higan/md/controller/controller.cpp +++ b/higan/md/controller/controller.cpp @@ -9,6 +9,7 @@ Controller::Controller(uint port) : port(port) { } Controller::~Controller() { + scheduler.remove(*this); } auto Controller::Enter() -> void { diff --git a/higan/ms/controller/controller.cpp b/higan/ms/controller/controller.cpp index 4ead2bae..12c279cf 100644 --- a/higan/ms/controller/controller.cpp +++ b/higan/ms/controller/controller.cpp @@ -9,6 +9,7 @@ Controller::Controller(uint port) : port(port) { } Controller::~Controller() { + scheduler.remove(*this); } auto Controller::Enter() -> void { diff --git a/higan/pce/controller/controller.cpp b/higan/pce/controller/controller.cpp index 9adb25ec..63e0c0f3 100644 --- a/higan/pce/controller/controller.cpp +++ b/higan/pce/controller/controller.cpp @@ -9,6 +9,7 @@ Controller::Controller() { } Controller::~Controller() { + scheduler.remove(*this); } auto Controller::Enter() -> void { diff --git a/higan/pce/controller/controller.hpp b/higan/pce/controller/controller.hpp index 1684eeb9..6fc3e5c5 100644 --- a/higan/pce/controller/controller.hpp +++ b/higan/pce/controller/controller.hpp @@ -5,7 +5,7 @@ struct Controller : Thread { static auto Enter() -> void; auto main() -> void; - virtual auto readData() -> uint4 { return 0; } + virtual auto readData() -> uint4 { return 0x0f; } virtual auto writeData(uint2) -> void {} }; diff --git a/higan/pce/cpu/cpu.cpp b/higan/pce/cpu/cpu.cpp index a84e827a..e1ec3d6b 100644 --- a/higan/pce/cpu/cpu.cpp +++ b/higan/pce/cpu/cpu.cpp @@ -33,6 +33,7 @@ auto CPU::power() -> void { memory::fill(&irq, sizeof(IRQ)); memory::fill(&timer, sizeof(Timer)); + memory::fill(&io, sizeof(IO)); } auto CPU::lastCycle() -> void { diff --git a/higan/pce/cpu/cpu.hpp b/higan/pce/cpu/cpu.hpp index 2f58befa..6b62dacd 100644 --- a/higan/pce/cpu/cpu.hpp +++ b/higan/pce/cpu/cpu.hpp @@ -55,6 +55,10 @@ struct CPU : Processor::HuC6280, Thread { friend class CPU; } timer; + struct IO { + uint8 mdr; + } io; + private: uint8 ram[0x2000]; }; diff --git a/higan/pce/cpu/io.cpp b/higan/pce/cpu/io.cpp index 2d543f8c..8873d031 100644 --- a/higan/pce/cpu/io.cpp +++ b/higan/pce/cpu/io.cpp @@ -22,12 +22,12 @@ auto CPU::read(uint21 addr) -> uint8 { //$0800-0bff PSG if((addr & 0x1c00) == 0x0800) { - return 0x00; + return io.mdr; } //$0c00-0fff Timer if((addr & 0x1c00) == 0x0c00) { - return timer.value; + return (io.mdr & 0x80) | timer.value; } //$1000-13ff I/O @@ -43,11 +43,20 @@ auto CPU::read(uint21 addr) -> uint8 { //$1400-17ff IRQ if((addr & 0x1c00) == 0x1400) { + if(addr.bits(0,1) == 0) { + return io.mdr; + } + + if(addr.bits(0,1) == 1) { + return io.mdr; + } + if(addr.bits(0,1) == 2) { return ( irq.disableExternal << 0 | irq.disableVDC << 1 | irq.disableTimer << 2 + | (io.mdr & 0xf8) ); } @@ -56,6 +65,7 @@ auto CPU::read(uint21 addr) -> uint8 { irq.pendingExternal << 0 | irq.pendingVDC << 1 | irq.pendingTimer << 2 + | (io.mdr & 0xf8) ); } } @@ -71,7 +81,7 @@ auto CPU::read(uint21 addr) -> uint8 { } } - return 0x00; + return 0xff; } auto CPU::write(uint21 addr, uint8 data) -> void { @@ -99,11 +109,13 @@ auto CPU::write(uint21 addr, uint8 data) -> void { //$0800-0bff PSG if((addr & 0x1c00) == 0x0800) { + io.mdr = data; return; } //$0c00-0fff Timer if((addr & 0x1c00) == 0x0c00) { + io.mdr = data; if(!addr.bit(0)) { timer.latch = data.bits(0,6); } else { @@ -115,12 +127,14 @@ auto CPU::write(uint21 addr, uint8 data) -> void { //$1000-13ff I/O if((addr & 0x1c00) == 0x1000) { + io.mdr = data; PCEngine::peripherals.controllerPort->writeData(data.bits(0,1)); return; } //$1400-17ff IRQ if((addr & 0x1c00) == 0x1400) { + io.mdr = data; if(addr.bits(0,1) == 2) { irq.disableExternal = data.bit(0); irq.disableVDC = data.bit(1); diff --git a/higan/pce/interface/interface.cpp b/higan/pce/interface/interface.cpp index 4b4f2a88..9b1f4150 100644 --- a/higan/pce/interface/interface.cpp +++ b/higan/pce/interface/interface.cpp @@ -45,13 +45,13 @@ auto Interface::title() -> string { } auto Interface::videoSize() -> VideoSize { - return {256, 240}; + return {1140, 242}; } auto Interface::videoSize(uint width, uint height, bool arc) -> VideoSize { auto a = arc ? 8.0 / 7.0 : 1.0; - uint w = 256; - uint h = 240; + uint w = 285; + uint h = 242; uint m = min(width / (w * a), height / h); return {uint(w * a * m), uint(h * m)}; } diff --git a/higan/pce/vdc/background.cpp b/higan/pce/vdc/background.cpp index 1cf35491..36fe7409 100644 --- a/higan/pce/vdc/background.cpp +++ b/higan/pce/vdc/background.cpp @@ -1,10 +1,11 @@ auto VDC::Background::scanline(uint y) -> void { - hoffset = hscroll; if(y == 0) { - voffset = vscroll; + vcounter = vscroll; } else { - voffset++; + vcounter++; } + hoffset = hscroll; + voffset = vcounter; } auto VDC::Background::run(uint x, uint y) -> void { @@ -15,13 +16,13 @@ auto VDC::Background::run(uint x, uint y) -> void { batAddress *= width; batAddress += (hoffset >> 3) & (width - 1); - uint16 tiledata = vdc.vramRead(batAddress); + uint16 tiledata = vdc.vram.read(batAddress); uint16 patternAddress = tiledata.bits(0,11) << 4; patternAddress += (voffset & 7); uint4 palette = tiledata.bits(12,15); - uint16 d0 = vdc.vramRead(patternAddress + 0); - uint16 d1 = vdc.vramRead(patternAddress + 8); + uint16 d0 = vdc.vram.read(patternAddress + 0); + uint16 d1 = vdc.vram.read(patternAddress + 8); uint3 index = 7 - (hoffset & 7); uint4 output; @@ -30,6 +31,6 @@ auto VDC::Background::run(uint x, uint y) -> void { output.bit(2) = d1.bit(0 + index); output.bit(3) = d1.bit(8 + index); - if(enable && output) color = vdc.cram[palette << 4 | output]; + if(enable && output) color = vdc.cram.read(palette << 4 | output); hoffset++; } diff --git a/higan/pce/vdc/dma.cpp b/higan/pce/vdc/dma.cpp index dc49c168..82b36b8e 100644 --- a/higan/pce/vdc/dma.cpp +++ b/higan/pce/vdc/dma.cpp @@ -1,8 +1,8 @@ auto VDC::DMA::step(uint clocks) -> void { while(clocks--) { if(vramActive) { - uint16 data = vdc.vramRead(source); - vdc.vramWrite(target, data); + uint16 data = vdc.vram.read(source); + vdc.vram.write(target, data); sourceIncrementMode == 0 ? source++ : source--; targetIncrementMode == 0 ? target++ : target--; if(!--length) { @@ -12,8 +12,8 @@ auto VDC::DMA::step(uint clocks) -> void { } if(satbActive) { - uint16 data = vdc.vramRead(satbSource + satbOffset); - vdc.satb[satbOffset] = data; + uint16 data = vdc.vram.read(satbSource + satbOffset); + vdc.satb.write(satbOffset, data); if(++satbOffset == 256) { satbActive = false; satbOffset = 0; diff --git a/higan/pce/vdc/io.cpp b/higan/pce/vdc/io.cpp index 9b779acb..548cec8e 100644 --- a/higan/pce/vdc/io.cpp +++ b/higan/pce/vdc/io.cpp @@ -1,17 +1,6 @@ -auto VDC::vramRead(uint16 addr) -> uint16 { - if(addr.bit(15)) return 0x00; - return vram[addr]; -} - -auto VDC::vramWrite(uint16 addr, uint16 data) -> void { - if(addr.bit(15)) return; - vram[addr] = data; -} - auto VDC::read(uint11 addr) -> uint8 { bool a0 = addr.bit(0); if(!addr.bit(10)) { - //VDC if(addr.bit(1) == 0) { //SR if(a0) return 0x00; @@ -29,26 +18,25 @@ auto VDC::read(uint11 addr) -> uint8 { if(addr.bit(1) == 1) { if(io.address == 0x02) { //VRR - uint8 data = io.vramDataRead.byte(a0); + uint8 data = vram.dataRead.byte(a0); if(a0) { - io.vramAddressRead += io.vramAddressIncrement; - io.vramDataRead = vramRead(io.vramAddressRead); + vram.addressRead += vram.addressIncrement; + vram.dataRead = vram.read(vram.addressRead); } return data; } } } else { - //VCE if(addr.bits(0,2) == 0x04) { //CTR - uint8 data = cram[io.colorAddress].bits(0,7); + uint8 data = cram.read(cram.address).bits(0,7); return data; } if(addr.bits(0,2) == 0x05) { //CTR - uint8 data = cram[io.colorAddress].bit(0); - io.colorAddress++; + uint8 data = 0xfe | cram.read(cram.address).bit(0); + cram.address++; return data; } } @@ -59,7 +47,6 @@ auto VDC::read(uint11 addr) -> uint8 { auto VDC::write(uint11 addr, uint8 data) -> void { bool a0 = addr.bit(0); if(!addr.bit(10)) { - //VDC if(addr.bit(1) == 0) { //AR if(a0) return; @@ -70,23 +57,23 @@ auto VDC::write(uint11 addr, uint8 data) -> void { if(addr.bit(1) == 1) { if(io.address == 0x00) { //MAWR - io.vramAddressWrite.byte(a0) = data; + vram.addressWrite.byte(a0) = data; return; } if(io.address == 0x01) { //MARR - io.vramAddressRead.byte(a0) = data; - io.vramDataRead = vramRead(io.vramAddressRead); + vram.addressRead.byte(a0) = data; + vram.dataRead = vram.read(vram.addressRead); return; } if(io.address == 0x02) { //VWR - io.vramDataWrite.byte(a0) = data; + vram.dataWrite.byte(a0) = data; if(a0) { - vramWrite(io.vramAddressWrite, io.vramDataWrite); - io.vramAddressWrite += io.vramAddressIncrement; + vram.write(vram.addressWrite, vram.dataWrite); + vram.addressWrite += vram.addressIncrement; } return; } @@ -104,10 +91,10 @@ auto VDC::write(uint11 addr, uint8 data) -> void { } else { io.displayOutput = data.bits(0,1); io.dramRefresh = data.bit(2); - if(data.bits(3,4) == 0) io.vramAddressIncrement = 0x01; - if(data.bits(3,4) == 1) io.vramAddressIncrement = 0x20; - if(data.bits(3,4) == 2) io.vramAddressIncrement = 0x40; - if(data.bits(3,4) == 3) io.vramAddressIncrement = 0x80; + if(data.bits(3,4) == 0) vram.addressIncrement = 0x01; + if(data.bits(3,4) == 1) vram.addressIncrement = 0x20; + if(data.bits(3,4) == 2) vram.addressIncrement = 0x40; + if(data.bits(3,4) == 3) vram.addressIncrement = 0x80; } return; } @@ -127,7 +114,7 @@ auto VDC::write(uint11 addr, uint8 data) -> void { if(io.address == 0x08) { //BYR background.vscroll.byte(a0) = data; - background.voffset = background.vscroll; + background.vcounter = background.vscroll; return; } @@ -149,9 +136,9 @@ auto VDC::write(uint11 addr, uint8 data) -> void { if(io.address == 0x0a) { //HSR if(!a0) { - io.horizontalSyncWidth = data.bits(0,4); + vce.horizontalSyncWidth = data.bits(0,4); } else { - io.horizontalDisplayStart = data.bits(0,6); + vce.horizontalDisplayStart = data.bits(0,6); } return; } @@ -159,9 +146,9 @@ auto VDC::write(uint11 addr, uint8 data) -> void { if(io.address == 0x0b) { //HDR if(!a0) { - io.horizontalDisplayWidth = data.bits(0,6); + vce.horizontalDisplayLength = data.bits(0,6); } else { - io.horizontalDisplayEnd = data.bits(0,6); + vce.horizontalDisplayEnd = data.bits(0,6); } return; } @@ -169,23 +156,27 @@ auto VDC::write(uint11 addr, uint8 data) -> void { if(io.address == 0x0c) { //VPR if(!a0) { - io.verticalSyncWidth = data.bits(0,4); + vce.verticalSyncWidth = data.bits(0,4); } else { - io.verticalDisplayStart = data.bits(0,7); + vce.verticalDisplayStart = data.bits(0,7); } return; } if(io.address == 0x0d) { //VDR - io.verticalDisplayWidth.byte(a0) = data; + if(!a0) { + vce.verticalDisplayLength.bits(0,7) = data.bits(0,7); + } else { + vce.verticalDisplayLength.bit(8) = data.bit(0); + } return; } if(io.address == 0x0e) { //VCR if(a0) return; - io.verticalDisplayEnd = data.bits(0,7); + vce.verticalDisplayEnd = data.bits(0,7); return; } @@ -227,10 +218,12 @@ auto VDC::write(uint11 addr, uint8 data) -> void { } } } else { - //VCE if(addr.bits(0,2) == 0x00) { //CR - io.divisionRatio = data.bits(0,1); + if(data.bits(0,1) == 0) vce.clock = 4; + if(data.bits(0,1) == 1) vce.clock = 3; + if(data.bits(0,1) == 2) vce.clock = 2; + if(data.bits(0,1) == 3) vce.clock = 2; io.colorBlur = data.bit(2); io.grayscale = data.bit(7); return; @@ -238,26 +231,26 @@ auto VDC::write(uint11 addr, uint8 data) -> void { if(addr.bits(0,2) == 0x02) { //CTA - io.colorAddress.bits(0,7) = data.bits(0,7); + cram.address.bits(0,7) = data.bits(0,7); return; } if(addr.bits(0,2) == 0x03) { //CTA - io.colorAddress.bit(8) = data.bit(0); + cram.address.bit(8) = data.bit(0); return; } if(addr.bits(0,2) == 0x04) { //CTW - cram[io.colorAddress].bits(0,7) = data.bits(0,7); + cram.write(cram.address, 0, data.bits(0,7)); return; } if(addr.bits(0,2) == 0x05) { //CTW - cram[io.colorAddress].bit(8) = data.bit(0); - io.colorAddress++; + cram.write(cram.address, 1, data.bit(0)); + cram.address++; return; } } diff --git a/higan/pce/vdc/memory.cpp b/higan/pce/vdc/memory.cpp new file mode 100644 index 00000000..7d9b464c --- /dev/null +++ b/higan/pce/vdc/memory.cpp @@ -0,0 +1,29 @@ +auto VDC::VRAM::read(uint16 addr) -> uint16 { + if(addr.bit(15)) return 0x0000; //todo: random data? + return data[addr]; +} + +auto VDC::VRAM::write(uint16 addr, uint16 value) -> void { + if(addr.bit(15)) return; + data[addr] = value; +} + +auto VDC::SATB::read(uint8 addr) -> uint16 { + return data[addr]; +} + +auto VDC::SATB::write(uint8 addr, uint16 value) -> void { + data[addr] = value; +} + +auto VDC::CRAM::read(uint9 addr) -> uint9 { + return data[addr]; +} + +auto VDC::CRAM::write(uint9 addr, bool a0, uint8 value) -> void { + if(!a0) { + data[addr].bits(0,7) = value.bits(0,7); + } else { + data[addr].bit(8) = value.bit(0); + } +} diff --git a/higan/pce/vdc/sprite.cpp b/higan/pce/vdc/sprite.cpp index 000c6463..eb9d670d 100644 --- a/higan/pce/vdc/sprite.cpp +++ b/higan/pce/vdc/sprite.cpp @@ -2,19 +2,19 @@ auto VDC::Sprite::scanline(uint y) -> void { y += 64; objects.reset(); - static const uint width[] = {15, 31}; - static const uint height[] = {15, 31, 63, 63}; + static const uint widths[] = {15, 31}; + static const uint heights[] = {15, 31, 63, 63}; uint count = 0; for(uint index : range(64)) { - uint16 d0 = vdc.satb[index << 2 | 0]; - uint16 d1 = vdc.satb[index << 2 | 1]; - uint16 d2 = vdc.satb[index << 2 | 2]; - uint16 d3 = vdc.satb[index << 2 | 3]; + uint16 d0 = vdc.satb.read(index << 2 | 0); + uint16 d1 = vdc.satb.read(index << 2 | 1); + uint16 d2 = vdc.satb.read(index << 2 | 2); + uint16 d3 = vdc.satb.read(index << 2 | 3); Object object; object.y = d0.bits(0,9); - object.height = height[d3.bits(12,13)]; + object.height = heights[d3.bits(12,13)]; if(y < object.y) continue; if(y > object.y + object.height) continue; @@ -23,15 +23,29 @@ auto VDC::Sprite::scanline(uint y) -> void { object.pattern = d2.bits(1,10); object.palette = d3.bits(0,3); object.priority = d3.bit(7); - object.width = width[d3.bit(8)]; + object.width = widths[d3.bit(8)]; object.hflip = d3.bit(11); object.vflip = d3.bit(15); - objects.append(object); + object.first = index == 0; - count += 1 + d3.bit(8); //32-width sprites consume two slots - if(count >= 16) { - vdc.irq.raise(VDC::IRQ::Line::Overflow); - break; + if(object.width == 31) object.pattern.bit(0) = 0; + if(object.height == 31) object.pattern.bit(1) = 0; + if(object.height == 63) object.pattern.bits(1,2) = 0; + + if(object.width == 15) { + objects.append(object); + if(++count >= 16) return vdc.irq.raise(VDC::IRQ::Line::Overflow); + } else { + //32-width sprites count as two 16-width sprite slots + object.pattern ^= object.hflip; + object.width = 15; + objects.append(object); + if(++count >= 16) return vdc.irq.raise(VDC::IRQ::Line::Overflow); + + object.x += 16; + object.pattern ^= 1; + objects.append(object); + if(++count >= 16) return vdc.irq.raise(VDC::IRQ::Line::Overflow); } } } @@ -43,10 +57,8 @@ auto VDC::Sprite::run(uint x, uint y) -> void { color = nothing; if(!enable) return; - bool zero = 0; - uint index = 0; + bool first = false; for(auto& object : objects) { - uint id = index++; if(x < object.x) continue; if(x > object.x + object.width) continue; @@ -55,21 +67,16 @@ auto VDC::Sprite::run(uint x, uint y) -> void { if(object.hflip) hoffset ^= object.width; if(object.vflip) voffset ^= object.height; - uint10 pattern = object.pattern; - if(object.width == 31) pattern.bit(0) = 0; - if(object.height == 31) pattern.bit(1) = 0; - if(object.height == 63) pattern.bits(1,2) = 0; - - uint16 patternAddress = pattern; + uint16 patternAddress = object.pattern; patternAddress += (voffset >> 4) << 1; patternAddress += (hoffset >> 4); patternAddress <<= 6; patternAddress += (voffset & 15); - uint16 d0 = vdc.vramRead(patternAddress + 0); - uint16 d1 = vdc.vramRead(patternAddress + 16); - uint16 d2 = vdc.vramRead(patternAddress + 32); - uint16 d3 = vdc.vramRead(patternAddress + 48); + uint16 d0 = vdc.vram.read(patternAddress + 0); + uint16 d1 = vdc.vram.read(patternAddress + 16); + uint16 d2 = vdc.vram.read(patternAddress + 32); + uint16 d3 = vdc.vram.read(patternAddress + 48); uint4 index = 15 - (hoffset & 15); uint4 output; @@ -80,12 +87,12 @@ auto VDC::Sprite::run(uint x, uint y) -> void { if(output == 0) continue; if(color) { - if(zero) vdc.irq.raise(VDC::IRQ::Line::Collision); - break; + if(first) return vdc.irq.raise(VDC::IRQ::Line::Collision); + return; } - color = vdc.cram[1 << 8 | object.palette << 4 | output]; + color = vdc.cram.read(1 << 8 | object.palette << 4 | output); priority = object.priority; - if(id == 0) zero = 1; + if(object.first) first = true; } } diff --git a/higan/pce/vdc/vdc.cpp b/higan/pce/vdc/vdc.cpp index 6d6d52ef..cdf6c094 100644 --- a/higan/pce/vdc/vdc.cpp +++ b/higan/pce/vdc/vdc.cpp @@ -3,6 +3,7 @@ namespace PCEngine { VDC vdc; +#include "memory.cpp" #include "io.cpp" #include "irq.cpp" #include "dma.cpp" @@ -14,66 +15,108 @@ auto VDC::Enter() -> void { } auto VDC::main() -> void { - //1365 cycles/scanline - state.x = 0; - uint y = state.y; - auto output = buffer + y * 512; - background.scanline(y); - sprite.scanline(y); - for(uint x : range(256)) { - if(y < 240) { - background.run(x, y); - sprite.run(x, y); + auto output = buffer + 1140 * vce.vclock; + + //todo: if block breaks TV Sports Basketball + //if(vce.vclock >= vce.vstart && vce.voffset < vce.vlength) { + background.scanline(vce.voffset); + sprite.scanline(vce.voffset); + //} + + while(vce.hclock < 1140) { + uint9 color = 0; + + if(vce.vclock >= vce.vstart && vce.voffset < vce.vlength + && vce.hclock >= vce.hstart && vce.hoffset < vce.hlength + ) { + background.run(vce.hoffset, vce.voffset); + sprite.run(vce.hoffset, vce.voffset); + vce.hoffset++; if(sprite.color && sprite.priority) { - *output++ = sprite.color(); + color = sprite.color(); } else if(background.color) { - *output++ = background.color(); + color = background.color(); } else if(sprite.color) { - *output++ = sprite.color(); + color = sprite.color(); } else { - *output++ = cram[0]; + color = cram.read(0); } } - step(4); - } - step(341); - if(++state.y == 262) { - state.y = 0; + if(vce.clock >= 2) *output++ = color; + if(vce.clock >= 2) *output++ = color; + if(vce.clock >= 3) *output++ = color; + if(vce.clock >= 4) *output++ = color; + + step(vce.clock); } - if(state.y == (io.lineCoincidence - 64)) irq.raise(IRQ::Line::LineCoincidence); - if(state.y == 240) { + + if(vce.vclock == io.lineCoincidence - (66 - vce.vstart)) { + irq.raise(IRQ::Line::LineCoincidence); + } + + step(1365 - vce.hclock); + scanline(); +} + +auto VDC::scanline() -> void { + vce.hclock = 0; + vce.hoffset = 0; + vce.hstart = vce.horizontalDisplayStart * vce.clock; + vce.hlength = (vce.horizontalDisplayLength + 1) << 3; + if(vce.clock == 2) vce.hstart += 0; + if(vce.clock == 3) vce.hstart += 0; + if(vce.clock == 4) vce.hstart += 0; + + vce.vclock++; + if(vce.vclock >= vce.vstart) vce.voffset++; + + if(vce.vclock == 262) { + frame(); + } + + if(vce.vclock == vce.vstart + vce.vlength) { irq.raise(IRQ::Line::Vblank); dma.satbStart(); - scheduler.exit(Scheduler::Event::Frame); } } +auto VDC::frame() -> void { + scheduler.exit(Scheduler::Event::Frame); + + vce.vclock = 0; + vce.voffset = 0; + vce.vstart = vce.verticalDisplayStart - 2; + vce.vlength = min(242, vce.verticalDisplayLength + 1); +} + auto VDC::step(uint clocks) -> void { - state.x += clocks; + vce.hclock += clocks; Thread::step(clocks); dma.step(clocks); synchronize(cpu); } auto VDC::refresh() -> void { - Emulator::video.refresh(buffer, 512 * sizeof(uint32), 256, 240); + Emulator::video.refresh(buffer + 1140 * vce.vstart, 1140 * sizeof(uint32), 1140, 242); } auto VDC::power() -> void { create(VDC::Enter, system.colorburst() * 6.0); for(auto& pixel : buffer) pixel = 0; - for(auto& word : vram) word = 0x0000; - for(auto& word : satb) word = 0x0000; - for(auto& word : cram) word = 0x0000; - memory::fill(&state, sizeof(State)); + memory::fill(&vram, sizeof(VRAM)); + memory::fill(&satb, sizeof(SATB)); + memory::fill(&cram, sizeof(CRAM)); memory::fill(&irq, sizeof(IRQ)); memory::fill(&dma, sizeof(DMA)); + memory::fill(&vce, sizeof(VCE)); memory::fill(&io, sizeof(IO)); memory::fill(&background, sizeof(Background)); memory::fill(&sprite, sizeof(Sprite)); + + vce.clock = 4; } } diff --git a/higan/pce/vdc/vdc.hpp b/higan/pce/vdc/vdc.hpp index 703b44c9..979a3715 100644 --- a/higan/pce/vdc/vdc.hpp +++ b/higan/pce/vdc/vdc.hpp @@ -5,28 +5,54 @@ struct VDC : Thread { static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void; + auto scanline() -> void; + auto frame() -> void; auto refresh() -> void; auto power() -> void; //io.cpp - auto vramRead(uint16 addr) -> uint16; - auto vramWrite(uint16 addr, uint16 data) -> void; - auto read(uint11 addr) -> uint8; auto write(uint11 addr, uint8 data) -> void; private: - uint32 buffer[512 * 484]; + uint32 buffer[1140 * 512]; - uint16 vram[0x8000]; - uint16 satb[0x100]; - uint9 cram[0x200]; + struct VRAM { + //memory.cpp + auto read(uint16 addr) -> uint16; + auto write(uint16 addr, uint16 data) -> void; - struct State { - uint x; - uint y; - } state; + uint16 addressRead; + uint16 addressWrite; + uint16 addressIncrement; + + uint16 dataRead; + uint16 dataWrite; + + private: + uint16 data[0x8000]; + } vram; + + struct SATB { + //memory.cpp + auto read(uint8 addr) -> uint16; + auto write(uint8 addr, uint16 data) -> void; + + private: + uint16 data[0x100]; + } satb; + + struct CRAM { + //memory.cpp + auto read(uint9 addr) -> uint9; + auto write(uint9 addr, bool a0, uint8 data) -> void; + + uint9 address; + + private: + uint9 data[0x200]; + } cram; struct IRQ { enum class Line : uint { @@ -79,6 +105,32 @@ private: uint16 satbOffset; } dma; + struct VCE { + uint5 horizontalSyncWidth; + uint7 horizontalDisplayStart; + uint7 horizontalDisplayLength; + uint7 horizontalDisplayEnd; + + uint5 verticalSyncWidth; + uint8 verticalDisplayStart; + uint9 verticalDisplayLength; + uint8 verticalDisplayEnd; + + uint clock; + + uint hclock; + uint vclock; + + uint hoffset; + uint voffset; + + uint hstart; + uint vstart; + + uint hlength; + uint vlength; + } vce; + struct Background { //background.cpp auto scanline(uint y) -> void; @@ -87,6 +139,7 @@ private: bool enable; uint10 hscroll; uint9 vscroll; + uint9 vcounter; uint8 width; uint8 height; @@ -114,6 +167,7 @@ private: bool hflip; uint height; bool vflip; + bool first; }; array objects; @@ -124,60 +178,22 @@ private: struct IO { uint5 address; - //VDC - - //$00 MAWR (W) - uint16 vramAddressWrite; - - //$01 MARR (W) - uint16 vramAddressRead; - - //$02 VWR (W) - //$02 VRR (R) - uint16 vramDataWrite; - uint16 vramDataRead; - - //$05 CR (W) + //$0005 CR (W) uint2 externalSync; uint2 displayOutput; bool dramRefresh; - uint vramAddressIncrement; - //$06 RCR + //$0006 RCR uint10 lineCoincidence; - //$09 MWR + //$0009 MWR uint2 vramAccess; uint2 spriteAccess; bool cgMode; - //$0a HSR - uint5 horizontalSyncWidth; - uint7 horizontalDisplayStart; - - //$0b HDR - uint7 horizontalDisplayWidth; - uint7 horizontalDisplayEnd; - - //$0c VPR - uint5 verticalSyncWidth; - uint8 verticalDisplayStart; - - //$0d VDR - uint9 verticalDisplayWidth; - - //$0e VCR - uint8 verticalDisplayEnd; - - //VCE - - //$00 CR - uint2 divisionRatio; + //$0400 CR bool colorBlur; bool grayscale; - - //$02 CTA - uint9 colorAddress; } io; }; diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index 9021f447..ce4e5f6b 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -237,8 +237,8 @@ auto Presentation::resizeViewport() -> void { uint windowWidth = 0, windowHeight = 0; bool aspectCorrection = true; if(!fullScreen()) { - windowWidth = 320 * scale; - windowHeight = 240 * scale; + windowWidth = 326 * scale; + windowHeight = 242 * scale; aspectCorrection = settings["Video/AspectCorrection"].boolean(); } else { windowWidth = geometry().width(); diff --git a/nall/arithmetic/natural.hpp b/nall/arithmetic/natural.hpp index 8660a8fe..fb5fff4a 100644 --- a/nall/arithmetic/natural.hpp +++ b/nall/arithmetic/natural.hpp @@ -319,7 +319,7 @@ template<> struct stringify { do { Pair quotient, remainder; div(source, 10, quotient, remainder); - *p++ = '0' + remainder; + *p++ = remainder + '0'; source = quotient; } while(source); _size = p - _output;