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