Update to v102r01 release.

byuu says:

Changelog:

  - MS, MD, PCE: remove controllers from scheduler in destructor
    [hex_usr]
  - PCE: no controller should return all bits set (still causing errant
    key presses when swapping gamepads)
  - PCE: emulate MDR for hardware I/O $0800-$17ff
  - PCE: change video resolution to 1140x242
  - PCE: added tertiary background Vscroll register (secondary cache)
  - PCE: create classes out of VDC VRAM, SATB, CRAM for cleaner access
    and I/O registers
  - PCE: high bits of CRAM read should be set
  - PCE: partially emulated VCE display registers: color frequency, HDS,
    HDW, VDS, VDW
  - PCE: 32-width sprites now split to two 16-width sprites to handle
    overflow properly
  - PCE: hopefully emulated sprite zero hit correctly (it's not well
    documented, and not often used)
  - PCE: trigger line coincidence interrupts during the previous
    scanline's Hblank period
  - tomoko: raise viewport from 320x240 to 326x242 to accommodate PC
    Engine's max resolution
  - nall: workaround for Clang compilation bug that can't figure out
    that a char is an integral data type
This commit is contained in:
Tim Allen 2017-01-22 11:33:36 +11:00
parent ae5968cfeb
commit c40e9754bc
18 changed files with 289 additions and 178 deletions

View File

@ -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/";

View File

@ -9,6 +9,7 @@ Controller::Controller(uint port) : port(port) {
}
Controller::~Controller() {
scheduler.remove(*this);
}
auto Controller::Enter() -> void {

View File

@ -9,6 +9,7 @@ Controller::Controller(uint port) : port(port) {
}
Controller::~Controller() {
scheduler.remove(*this);
}
auto Controller::Enter() -> void {

View File

@ -9,6 +9,7 @@ Controller::Controller() {
}
Controller::~Controller() {
scheduler.remove(*this);
}
auto Controller::Enter() -> void {

View File

@ -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 {}
};

View File

@ -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 {

View File

@ -55,6 +55,10 @@ struct CPU : Processor::HuC6280, Thread {
friend class CPU;
} timer;
struct IO {
uint8 mdr;
} io;
private:
uint8 ram[0x2000];
};

View File

@ -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);

View File

@ -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)};
}

View File

@ -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++;
}

View File

@ -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;

View File

@ -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;
}
}

29
higan/pce/vdc/memory.cpp Normal file
View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<Object, 64> 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;
};

View File

@ -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();

View File

@ -319,7 +319,7 @@ template<> struct stringify<Pair> {
do {
Pair quotient, remainder;
div(source, 10, quotient, remainder);
*p++ = '0' + remainder;
*p++ = remainder + '0';
source = quotient;
} while(source);
_size = p - _output;