Update to v101r34 release.

byuu says:

Changelog:

  - PCE: emulated gamepad polling
  - PCE: emulated CPU interrupt sources
  - PCE: emulated timer
  - PCE: smarter emulation of ST0,ST1,ST2 instructions
  - PCE: better structuring of CPU, VDP IO registers
  - PCE: connected palette generation to the interface
  - PCE: emulated basic VDC timing
  - PCE: emulated VDC Vblank, Coincidence, and DMA completion IRQs
  - PCE: emulated VRAM, SATB DMA transfers
  - PCE: emulated VDC I/O registers

Everything I've implemented today likely has lots of bugs, and is
untested for obvious reasons.

So basically, after I fix many horrendous bugs, it should now be
possible to implement the VDC and start getting graphical output.
This commit is contained in:
Tim Allen 2017-01-17 08:02:56 +11:00
parent 8499c64756
commit f500426158
19 changed files with 834 additions and 39 deletions

View File

@ -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 = "101.33"; static const string Version = "101.34";
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/";

View File

@ -5,7 +5,8 @@ struct Controller : Thread {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
virtual auto readData() -> uint8 { return 0x00; } virtual auto readData() -> uint4 { return 0; }
virtual auto writeData(uint2) -> void {}
}; };
#include "gamepad/gamepad.hpp" #include "gamepad/gamepad.hpp"

View File

@ -1,6 +1,29 @@
Gamepad::Gamepad() { Gamepad::Gamepad() {
} }
auto Gamepad::readData() -> uint8 { auto Gamepad::readData() -> uint4 {
return 0x00; if(clr) return 0;
uint4 data;
if(sel) {
data.bit(0) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Up);
data.bit(1) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Down);
data.bit(2) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Right);
data.bit(3) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Left);
if(data.bits(0,1) == 0) data.bits(0,1) = 3; //disallow up+down at the same time
if(data.bits(2,3) == 0) data.bits(2,3) = 3; //disallow left+right at the same time
} else {
data.bit(0) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, One);
data.bit(1) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Two);
data.bit(2) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Select);
data.bit(3) = !platform->inputPoll(ID::Port::Controller, ID::Device::Gamepad, Run);
}
return data;
}
auto Gamepad::writeData(uint2 data) -> void {
sel = data.bit(0);
clr = data.bit(1);
} }

View File

@ -5,5 +5,9 @@ struct Gamepad : Controller {
Gamepad(); Gamepad();
auto readData() -> uint8 override; auto readData() -> uint4 override;
auto writeData(uint2 data) -> void override;
bool sel;
bool clr;
}; };

View File

@ -3,6 +3,9 @@
namespace PCEngine { namespace PCEngine {
CPU cpu; CPU cpu;
#include "io.cpp"
#include "irq.cpp"
#include "timer.cpp"
auto CPU::Enter() -> void { auto CPU::Enter() -> void {
while(true) scheduler.synchronize(), cpu.main(); while(true) scheduler.synchronize(), cpu.main();
@ -16,11 +19,13 @@ auto CPU::main() -> void {
} }
#endif #endif
if(irq.pending()) interrupt(irq.vector());
instruction(); instruction();
} }
auto CPU::step(uint clocks) -> void { auto CPU::step(uint clocks) -> void {
Thread::step(clocks); Thread::step(clocks);
timer.step(clocks);
synchronize(vdc); synchronize(vdc);
synchronize(psg); synchronize(psg);
for(auto peripheral : peripherals) synchronize(*peripheral); for(auto peripheral : peripherals) synchronize(*peripheral);
@ -28,33 +33,17 @@ auto CPU::step(uint clocks) -> void {
auto CPU::power() -> void { auto CPU::power() -> void {
HuC6280::power(); HuC6280::power();
create(CPU::Enter, system.colorburst() * 6.0); create(CPU::Enter, system.colorburst() * 2.0);
r.pc.byte(0) = read(0x1ffe); r.pc.byte(0) = read(0x1ffe);
r.pc.byte(1) = read(0x1fff); r.pc.byte(1) = read(0x1fff);
}
auto CPU::read(uint21 addr) -> uint8 { memory::fill(&irq, sizeof(IRQ));
if(!addr.bit(20)) return cartridge.read(addr); memory::fill(&timer, sizeof(Timer));
uint8 bank = addr.bits(13,20);
addr = addr.bits(0,12);
if(bank >= 0xf8 && bank <= 0xfb) return ram[addr];
if(bank == 0xff) return 0x00; //hardware
return 0xff;
}
auto CPU::write(uint21 addr, uint8 data) -> void {
if(!addr.bit(20)) return cartridge.write(addr, data);
uint8 bank = addr.bits(13,20);
addr = addr.bits(0,12);
if(bank >= 0xf8 && bank <= 0xfb) { ram[addr] = data; return; }
if(bank == 0xff) return; //hardware
}
auto CPU::st(uint2 addr, uint8 data) -> void {
} }
auto CPU::lastCycle() -> void { auto CPU::lastCycle() -> void {
irq.poll();
} }
} }

View File

@ -6,14 +6,55 @@ struct CPU : Processor::HuC6280, Thread {
auto step(uint clocks) -> void override; auto step(uint clocks) -> void override;
auto power() -> void; auto power() -> void;
auto read(uint21 addr) -> uint8 override;
auto write(uint21 addr, uint8 data) -> void override;
auto st(uint2 addr, uint8 data) -> void override;
auto lastCycle() -> void override; auto lastCycle() -> void override;
//io.cpp
auto read(uint21 addr) -> uint8 override;
auto write(uint21 addr, uint8 data) -> void override;
//timer.cpp
auto timerStep(uint clocks) -> void;
vector<Thread*> peripherals; vector<Thread*> peripherals;
struct IRQ {
enum class Line : uint { External, VDC, Timer };
//irq.cpp
auto pending() const -> bool;
auto vector() const -> uint16;
auto poll() -> void;
auto level(Line, bool = 1) -> void;
private:
bool disableExternal;
bool disableVDC;
bool disableTimer;
bool pendingExternal;
bool pendingVDC;
bool pendingTimer;
bool pendingIRQ;
uint16 pendingVector;
friend class CPU;
} irq;
struct Timer {
//timer.cpp
auto start() -> void;
auto step(uint clocks) -> void;
private:
bool enable;
uint7 latch;
uint7 value;
uint clock;
friend class CPU;
} timer;
private: private:
uint8 ram[0x2000]; uint8 ram[0x2000];
}; };

147
higan/pce/cpu/io.cpp Normal file
View File

@ -0,0 +1,147 @@
auto CPU::read(uint21 addr) -> uint8 {
//$000000-0fffff HuCard
if(!addr.bit(20)) {
return cartridge.read(addr);
}
uint8 bank = addr.bits(13,20);
addr = addr.bits(0,12);
//$1f8000-1fbfff RAM
if(bank >= 0xf8 && bank <= 0xfb) {
return ram[addr];
}
//$1fe000-$1fffff Hardware
if(bank == 0xff) {
//$0000-03ff VDC
//$0400-07ff VCE
if((addr & 0x1800) == 0x0000) {
return vdc.read(addr);
}
//$0800-0bff PSG
if((addr & 0x1c00) == 0x0800) {
return 0x00;
}
//$0c00-0fff Timer
if((addr & 0x1c00) == 0x0c00) {
return timer.value;
}
//$1000-13ff I/O
if((addr & 0x1c00) == 0x1000) {
return (
PCEngine::peripherals.controllerPort->readData() << 0
| 1 << 4
| 1 << 5
| 0 << 6 //device (0 = Turbografx-16; 1 = PC Engine)
| 1 << 7 //add-on (0 = CD-ROM; 1 = nothing)
);
}
//$1400-17ff IRQ
if((addr & 0x1c00) == 0x1400) {
if(addr.bits(0,1) == 2) {
return (
irq.disableExternal << 0
| irq.disableVDC << 1
| irq.disableTimer << 2
);
}
if(addr.bits(0,1) == 3) {
return (
irq.pendingExternal << 0
| irq.pendingVDC << 1
| irq.pendingTimer << 2
);
}
}
//$1800-1bff CD-ROM
if((addr & 0x1c00) == 0x1800) {
return 0xff;
}
//$1c00-1fff unmapped
if((addr & 0x1c00) == 0x1c00) {
return 0xff;
}
}
return 0x00;
}
auto CPU::write(uint21 addr, uint8 data) -> void {
//$000000-0fffff HuCard
if(!addr.bit(20)) {
return cartridge.write(addr, data);
}
uint8 bank = addr.bits(13,20);
addr = addr.bits(0,12);
//$1f8000-1fbfff RAM
if(bank >= 0xf8 && bank <= 0xfb) {
ram[addr] = data;
return;
}
//$1fe000-1fffff Hardware
if(bank == 0xff) {
//$0000-03ff VDC
//$0400-07ff VCE
if((addr & 0x1800) == 0x0000) {
return vdc.write(addr, data);
}
//$0800-0bff PSG
if((addr & 0x1c00) == 0x0800) {
return;
}
//$0c00-0fff Timer
if((addr & 0x1c00) == 0x0c00) {
if(!addr.bit(0)) {
timer.latch = data.bits(0,6);
} else {
timer.enable = data.bit(0);
if(timer.enable) timer.start();
}
return;
}
//$1000-13ff I/O
if((addr & 0x1c00) == 0x1000) {
PCEngine::peripherals.controllerPort->writeData(data.bits(0,1));
return;
}
//$1400-17ff IRQ
if((addr & 0x1c00) == 0x1400) {
if(addr.bits(0,1) == 2) {
irq.disableExternal = data.bit(0);
irq.disableVDC = data.bit(1);
irq.disableTimer = data.bit(2);
return;
}
if(addr.bits(0,1) == 3) {
irq.level(IRQ::Line::Timer, 0);
return;
}
}
//$1800-1bff CD-ROM
if((addr & 0x1c00) == 0x1800) {
return;
}
//$1c00-1fff unmapped
if((addr & 0x1c00) == 0x1c00) {
return;
}
}
}

37
higan/pce/cpu/irq.cpp Normal file
View File

@ -0,0 +1,37 @@
auto CPU::IRQ::pending() const -> bool {
return pendingIRQ;
}
auto CPU::IRQ::vector() const -> uint16 {
return pendingVector;
}
auto CPU::IRQ::poll() -> void {
pendingIRQ = false;
if(cpu.r.p.i) return;
if(!disableExternal && pendingExternal) {
pendingIRQ = true;
pendingVector = 0xfff6;
} else if(!disableVDC && pendingVDC) {
pendingIRQ = true;
pendingVector = 0xfff8;
} else if(!disableTimer && pendingTimer) {
pendingIRQ = true;
pendingVector = 0xfffa;
}
}
auto CPU::IRQ::level(Line line, bool level) -> void {
if(line == Line::External) {
pendingExternal = level;
}
if(line == Line::VDC) {
pendingVDC = level;
}
if(line == Line::Timer) {
pendingTimer = level;
}
}

16
higan/pce/cpu/timer.cpp Normal file
View File

@ -0,0 +1,16 @@
auto CPU::Timer::start() -> void {
value = latch;
clock = 0;
}
auto CPU::Timer::step(uint clocks) -> void {
if(!enable) return;
clock += clocks;
while(clock >= 1024) {
clock -= 1024;
if(!value--) {
value = latch;
cpu.irq.level(CPU::IRQ::Line::Timer, 1);
}
}
}

View File

@ -65,7 +65,15 @@ auto Interface::videoColors() -> uint32 {
} }
auto Interface::videoColor(uint32 color) -> uint64 { auto Interface::videoColor(uint32 color) -> uint64 {
return 0; uint3 B = color.bits(0,2);
uint3 G = color.bits(3,5);
uint3 R = color.bits(6,8);
uint64 r = image::normalize(R, 3, 16);
uint64 g = image::normalize(G, 3, 16);
uint64 b = image::normalize(B, 3, 16);
return r << 32 | g << 16 | b << 0;
} }
auto Interface::audioFrequency() -> double { auto Interface::audioFrequency() -> double {

38
higan/pce/vdc/dma.cpp Normal file
View File

@ -0,0 +1,38 @@
auto VDC::DMA::step(uint clocks) -> void {
while(clocks--) {
if(vramActive) {
uint16 data = vdc.vramRead(source);
vdc.vramWrite(target, data);
sourceIncrementMode == 0 ? source++ : source--;
targetIncrementMode == 0 ? target++ : target--;
if(!--length) {
vramActive = false;
vdc.irq.raise(VDC::IRQ::Line::TransferVRAM);
}
}
if(satbActive) {
uint16 data = vdc.vramRead(satbSource + satbTarget);
vdc.vramWrite(satbTarget++, data);
if(satbTarget == 256) {
satbActive = false;
satbPending = satbRepeat;
vdc.irq.raise(VDC::IRQ::Line::TransferSATB);
}
}
}
}
auto VDC::DMA::vramStart() -> void {
vramActive = true;
}
auto VDC::DMA::satbStart() -> void {
if(!satbPending) return;
satbActive = true;
satbTarget = 0;
}
auto VDC::DMA::satbQueue() -> void {
satbPending = true;
}

263
higan/pce/vdc/io.cpp Normal file
View File

@ -0,0 +1,263 @@
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;
uint8 data;
data.bit(0) = irq.pendingCollision;
data.bit(1) = irq.pendingOverflow;
data.bit(2) = irq.pendingLineCoincidence;
data.bit(3) = irq.pendingTransferSATB;
data.bit(4) = irq.pendingTransferVRAM;
data.bit(5) = irq.pendingVblank;
irq.lower();
return data;
}
if(addr.bit(1) == 1) {
if(io.address == 0x02) {
//VRR
uint8 data = io.vramDataRead.byte(a0);
if(a0) {
io.vramAddressRead += io.vramAddressIncrement;
io.vramDataRead = vramRead(io.vramAddressRead);
}
return data;
}
}
} else {
//VCE
if(addr.bits(0,2) == 0x04) {
//CTR
uint8 data = cram[io.colorAddress].bits(0,7);
return data;
}
if(addr.bits(0,2) == 0x05) {
//CTR
uint8 data = cram[io.colorAddress].bit(0);
io.colorAddress++;
return data;
}
}
return 0x00;
}
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;
io.address = data.bits(0,4);
return;
}
if(addr.bit(1) == 1) {
if(io.address == 0x00) {
//MAWR
io.vramAddressWrite.byte(a0) = data;
return;
}
if(io.address == 0x01) {
//MARR
io.vramAddressRead.byte(a0) = data;
io.vramDataRead = vramRead(io.vramAddressRead);
return;
}
if(io.address == 0x02) {
//VWR
io.vramDataWrite.byte(a0) = data;
if(a0) {
vramWrite(io.vramAddressWrite, io.vramDataWrite);
io.vramAddressWrite += io.vramAddressIncrement;
}
return;
}
if(io.address == 0x05) {
//CR
if(!a0) {
irq.enableCollision = data.bit(0);
irq.enableOverflow = data.bit(1);
irq.enableLineCoincidence = data.bit(2);
irq.enableVblank = data.bit(3);
io.externalSync = data.bits(4,5);
io.spriteBlank = data.bit(6);
io.backgroundBlank = data.bit(7);
} 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;
}
return;
}
if(io.address == 0x06) {
//RCR
io.lineCoincidence.byte(a0) = data;
return;
}
if(io.address == 0x07) {
//BXR
io.backgroundHscroll.byte(a0) = data;
return;
}
if(io.address == 0x08) {
//BYR
io.backgroundVscroll.byte(a0) = data;
return;
}
if(io.address == 0x09) {
//MWR
if(a0) return;
io.vramAccess = data.bits(0,1);
io.spriteAccess = data.bits(2,3);
if(data.bits(4,5) == 0) io.backgroundWidth = 32;
if(data.bits(4,5) == 1) io.backgroundWidth = 64;
if(data.bits(4,5) == 2) io.backgroundWidth = 128;
if(data.bits(4,5) == 3) io.backgroundWidth = 128;
if(data.bit(6) == 0) io.backgroundHeight = 32;
if(data.bit(6) == 1) io.backgroundHeight = 64;
io.cgMode = data.bit(7);
return;
}
if(io.address == 0x0a) {
//HSR
if(!a0) {
io.horizontalSyncWidth = data.bits(0,4);
} else {
io.horizontalDisplayStart = data.bits(0,6);
}
return;
}
if(io.address == 0x0b) {
//HDR
if(!a0) {
io.horizontalDisplayWidth = data.bits(0,6);
} else {
io.horizontalDisplayEnd = data.bits(0,6);
}
return;
}
if(io.address == 0x0c) {
//VPR
if(!a0) {
io.verticalSyncWidth = data.bits(0,4);
} else {
io.verticalDisplayStart = data.bits(0,7);
}
return;
}
if(io.address == 0x0d) {
//VDR
io.verticalDisplayWidth.byte(a0) = data;
return;
}
if(io.address == 0x0e) {
//VCR
if(a0) return;
io.verticalDisplayEnd = data.bits(0,7);
return;
}
if(io.address == 0x0f) {
//DCR
if(a0) return;
irq.enableTransferVRAM = data.bit(0);
irq.enableTransferSATB = data.bit(1);
dma.sourceIncrementMode = data.bit(2);
dma.targetIncrementMode = data.bit(3);
dma.satbRepeat = data.bit(4);
return;
}
if(io.address == 0x10) {
//SOUR
dma.source.byte(a0) = data;
return;
}
if(io.address == 0x11) {
//DESR
dma.target.byte(a0) = data;
return;
}
if(io.address == 0x12) {
//LENR
dma.length.byte(a0) = data;
if(a0) dma.vramStart();
return;
}
if(io.address == 0x13) {
//DVSSR
dma.satbSource.byte(a0) = data;
if(a0) dma.satbQueue();
return;
}
}
} else {
//VCE
if(addr.bits(0,2) == 0x00) {
//CR
io.divisionRatio = data.bits(0,1);
io.colorBlur = data.bit(2);
io.grayscale = data.bit(7);
return;
}
if(addr.bits(0,2) == 0x02) {
//CTA
io.colorAddress.bits(0,7) = data.bits(0,7);
return;
}
if(addr.bits(0,2) == 0x03) {
//CTA
io.colorAddress.bit(8) = data.bit(0);
return;
}
if(addr.bits(0,2) == 0x04) {
//CTW
cram[io.colorAddress].bits(0,7) = data.bits(0,7);
return;
}
if(addr.bits(0,2) == 0x05) {
//CTW
cram[io.colorAddress].bit(8) = data.bit(0);
io.colorAddress++;
return;
}
}
}

49
higan/pce/vdc/irq.cpp Normal file
View File

@ -0,0 +1,49 @@
auto VDC::IRQ::poll() -> void {
bool pending = false;
pending |= pendingCollision;
pending |= pendingOverflow;
pending |= pendingLineCoincidence;
pending |= pendingVblank;
pending |= pendingTransferVRAM;
pending |= pendingTransferSATB;
cpu.irq.level(CPU::IRQ::Line::VDC, pending);
}
auto VDC::IRQ::raise(Line line) -> void {
if(line == Line::Collision && enableCollision) {
pendingCollision = true;
}
if(line == Line::Overflow && enableOverflow) {
pendingOverflow = true;
}
if(line == Line::LineCoincidence && enableLineCoincidence) {
pendingLineCoincidence = true;
}
if(line == Line::Vblank && enableVblank) {
pendingVblank = true;
}
if(line == Line::TransferVRAM && enableTransferVRAM) {
pendingTransferVRAM = true;
}
if(line == Line::TransferSATB && enableTransferSATB) {
pendingTransferSATB = true;
}
poll();
}
auto VDC::IRQ::lower() -> void {
pendingCollision = false;
pendingOverflow = false;
pendingLineCoincidence = false;
pendingVblank = false;
pendingTransferVRAM = false;
pendingTransferSATB = false;
poll();
}

View File

@ -3,18 +3,40 @@
namespace PCEngine { namespace PCEngine {
VDC vdc; VDC vdc;
#include "io.cpp"
#include "irq.cpp"
#include "dma.cpp"
auto VDC::Enter() -> void { auto VDC::Enter() -> void {
while(true) scheduler.synchronize(), vdc.main(); while(true) scheduler.synchronize(), vdc.main();
} }
auto VDC::main() -> void { auto VDC::main() -> void {
step(system.colorburst() * 6.0 / 60.0); //1365 cycles/scanline
scheduler.exit(Scheduler::Event::Frame); for(uint x : range(256)) {
step(4);
}
step(341);
scanline();
}
auto VDC::scanline() -> void {
state.x = 0;
if(++state.y == 262) {
state.y = 0;
}
if(state.y == (io.lineCoincidence - 64)) irq.raise(IRQ::Line::LineCoincidence);
if(state.y == 240) {
irq.raise(IRQ::Line::Vblank);
dma.satbStart();
scheduler.exit(Scheduler::Event::Frame);
}
} }
auto VDC::step(uint clocks) -> void { auto VDC::step(uint clocks) -> void {
state.x += clocks;
Thread::step(clocks); Thread::step(clocks);
dma.step(clocks);
synchronize(cpu); synchronize(cpu);
} }
@ -24,7 +46,15 @@ auto VDC::refresh() -> void {
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;
for(auto& word : satb) word = 0x0000;
for(auto& word : cram) word = 0x0000;
memory::fill(&state, sizeof(State));
memory::fill(&irq, sizeof(IRQ));
memory::fill(&dma, sizeof(DMA));
memory::fill(&io, sizeof(IO));
} }
} }

View File

@ -4,13 +4,150 @@
struct VDC : Thread { struct VDC : Thread {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto scanline() -> void;
auto step(uint clocks) -> void; auto step(uint clocks) -> void;
auto refresh() -> void; auto refresh() -> void;
auto power() -> 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: private:
uint32 buffer[512 * 484]; uint32 buffer[512 * 484];
uint16 vram[0x8000];
uint16 satb[0x100];
uint9 cram[0x200];
struct State {
uint x;
uint y;
} state;
struct IRQ {
enum class Line : uint {
Collision,
Overflow,
LineCoincidence,
Vblank,
TransferVRAM,
TransferSATB,
};
//irq.cpp
auto poll() -> void;
auto raise(Line) -> void;
auto lower() -> void;
bool enableCollision;
bool enableOverflow;
bool enableLineCoincidence;
bool enableVblank;
bool enableTransferVRAM;
bool enableTransferSATB;
bool pendingCollision;
bool pendingOverflow;
bool pendingLineCoincidence;
bool pendingVblank;
bool pendingTransferVRAM;
bool pendingTransferSATB;
} irq;
struct DMA {
//dma.cpp
auto step(uint clocks) -> void;
auto vramStart() -> void;
auto satbStart() -> void;
auto satbQueue() -> void;
bool sourceIncrementMode;
bool targetIncrementMode;
bool satbRepeat;
uint16 source;
uint16 target;
uint16 length;
uint16 satbSource;
bool vramActive;
bool satbActive;
bool satbPending;
uint16 satbTarget;
} dma;
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)
uint2 externalSync;
bool spriteBlank;
bool backgroundBlank;
uint2 displayOutput;
bool dramRefresh;
uint vramAddressIncrement;
//$06 RCR
uint10 lineCoincidence;
//$07 BXR
uint10 backgroundHscroll;
//$08 BYR
uint9 backgroundVscroll;
//$09 MWR
uint2 vramAccess;
uint2 spriteAccess;
uint backgroundWidth;
uint backgroundHeight;
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;
bool colorBlur;
bool grayscale;
//$02 CTA
uint9 colorAddress;
} io;
}; };
extern VDC vdc; extern VDC vdc;

View File

@ -62,7 +62,7 @@ auto HuC6280::power() -> void {
r.mpr[7] = 0x00; r.mpr[7] = 0x00;
r.mdr = 0x00; r.mdr = 0x00;
r.p = 0x04; r.p = 0x04;
r.cs = 3; r.cs = 1;
} }
} }

View File

@ -8,7 +8,6 @@ struct HuC6280 {
virtual auto step(uint clocks) -> void = 0; virtual auto step(uint clocks) -> void = 0;
virtual auto read(uint21 addr) -> uint8 = 0; virtual auto read(uint21 addr) -> uint8 = 0;
virtual auto write(uint21 addr, uint8 data) -> void = 0; virtual auto write(uint21 addr, uint8 data) -> void = 0;
virtual auto st(uint2, uint8) -> void = 0;
virtual auto lastCycle() -> void = 0; virtual auto lastCycle() -> void = 0;
auto power() -> void; auto power() -> void;
@ -26,6 +25,7 @@ struct HuC6280 {
auto pull() -> uint8; auto pull() -> uint8;
//instruction.cpp //instruction.cpp
auto interrupt(uint16 vector) -> void;
auto instruction() -> void; auto instruction() -> void;
//instructions.cpp //instructions.cpp

View File

@ -1,6 +1,18 @@
#define op(id, name, ...) case id: instruction_##name(__VA_ARGS__); return; #define op(id, name, ...) case id: instruction_##name(__VA_ARGS__); return;
#define fp(name) &HuC6280::name #define fp(name) &HuC6280::name
auto HuC6280::interrupt(uint16 vector) -> void {
io();
io();
push(PC >> 8);
push(PC >> 0);
push(P);
PC.byte(0) = load(vector + 0);
PC.byte(1) = load(vector + 1);
D = 0;
I = 1;
}
auto HuC6280::instruction() -> void { auto HuC6280::instruction() -> void {
auto code = opcode(); auto code = opcode();
@ -35,7 +47,7 @@ U op(0x0b, NOP)
op(0x10, branch, N == 0) op(0x10, branch, N == 0)
op(0x11, indirectYLoad, fp(ORA), A) op(0x11, indirectYLoad, fp(ORA), A)
op(0x12, indirectLoad, fp(ORA), A) op(0x12, indirectLoad, fp(ORA), A)
op(0x13, ST, 1) op(0x13, ST, 2)
op(0x14, zeropageModify, fp(TRB)) op(0x14, zeropageModify, fp(TRB))
op(0x15, zeropageLoad, fp(ORA), A, X) op(0x15, zeropageLoad, fp(ORA), A, X)
op(0x16, zeropageModify, fp(ASL), X) op(0x16, zeropageModify, fp(ASL), X)
@ -51,7 +63,7 @@ U op(0x1b, NOP)
op(0x20, JSR) op(0x20, JSR)
op(0x21, indirectLoad, fp(AND), A, X) op(0x21, indirectLoad, fp(AND), A, X)
op(0x22, swap, A, X) op(0x22, swap, A, X)
op(0x23, ST, 2) op(0x23, ST, 3)
op(0x24, zeropageLoad, fp(BIT), A) op(0x24, zeropageLoad, fp(BIT), A)
op(0x25, zeropageLoad, fp(AND), A) op(0x25, zeropageLoad, fp(AND), A)
op(0x26, zeropageModify, fp(ROL)) op(0x26, zeropageModify, fp(ROL))

View File

@ -375,12 +375,12 @@ L push((PC - 1) >> 0);
} }
auto HuC6280::instruction_CSL() -> void { auto HuC6280::instruction_CSL() -> void {
r.cs = 12; r.cs = 4;
L io(); L io();
} }
auto HuC6280::instruction_CSH() -> void { auto HuC6280::instruction_CSH() -> void {
r.cs = 3; r.cs = 1;
L io(); L io();
} }
@ -457,7 +457,7 @@ auto HuC6280::instruction_ST(uint2 index) -> void {
auto data = operand(); auto data = operand();
io(); io();
L io(); L io();
st(index, data); write(0x1fe000 + index, data);
} }
auto HuC6280::instruction_TAM() -> void { auto HuC6280::instruction_TAM() -> void {