mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r32 release.
byuu says: Changelog: - SMS: fixed controller connection bug - SMS: fixed Z80 reset bug - PCE: emulated HuC6280 MMU - PCE: emulated HuC6280 RAM - PCE: emulated HuCard ROM reading - PCE: implemented 178 instructions - tomoko: removed "soft reset" functionality - tomoko: moved "power cycle" to just above "unload" option I'm not sure of the exact number of HuC6280 instructions, but it's less than 260. Many of the ones I skipped are HuC6280-originals that I don't know how to emulate just yet. I'm also really unsure about the zero page stuff. I believe we should be adding 0x2000 to the addresses to hit page 1, which is supposed to be mapped to the zero page (RAM). But when I look at turboEMU's source, I have no clue how the hell it could possibly be doing that. It looks to be reading from page 0, which is almost always ROM, which would be ... really weird. I also don't know if I've emulated the T mode opcodes correctly or not. The documentation on them is really confusing.
This commit is contained in:
parent
21ee597aae
commit
26bd7590ad
|
@ -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.31";
|
static const string Version = "101.32";
|
||||||
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/";
|
||||||
|
|
|
@ -20,10 +20,6 @@ auto APU::step(uint clocks) -> void {
|
||||||
auto APU::power() -> void {
|
auto APU::power() -> void {
|
||||||
Z80::bus = &busAPU;
|
Z80::bus = &busAPU;
|
||||||
Z80::power();
|
Z80::power();
|
||||||
}
|
|
||||||
|
|
||||||
auto APU::reset() -> void {
|
|
||||||
Z80::reset();
|
|
||||||
create(APU::Enter, system.colorburst());
|
create(APU::Enter, system.colorburst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ struct APU : Processor::Z80, Thread {
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern APU apu;
|
extern APU apu;
|
||||||
|
|
|
@ -55,7 +55,7 @@ auto System::reset() -> void {
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
cartridge.reset();
|
cartridge.reset();
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
apu.reset();
|
apu.power();
|
||||||
vdp.reset();
|
vdp.reset();
|
||||||
psg.reset();
|
psg.reset();
|
||||||
ym2612.reset();
|
ym2612.reset();
|
||||||
|
|
|
@ -20,8 +20,8 @@ auto Bus::in(uint8 addr) -> uint8 {
|
||||||
|
|
||||||
case 0: {
|
case 0: {
|
||||||
if(system.model() == Model::GameGear) {
|
if(system.model() == Model::GameGear) {
|
||||||
auto hardware = peripherals.hardware->readData();
|
bool start = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 6);
|
||||||
return hardware.bit(6) << 7 | 0x7f;
|
return start << 7 | 0x7f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
||||||
|
@ -37,19 +37,26 @@ auto Bus::in(uint8 addr) -> uint8 {
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
if(system.model() == Model::MasterSystem) {
|
if(system.model() == Model::MasterSystem) {
|
||||||
auto hardware = peripherals.hardware->readData();
|
bool reset = !platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 0);
|
||||||
auto port1 = peripherals.controllerPort1->readData();
|
auto port1 = peripherals.controllerPort1->readData();
|
||||||
auto port2 = peripherals.controllerPort2->readData();
|
auto port2 = peripherals.controllerPort2->readData();
|
||||||
if(addr.bit(0) == 0) {
|
if(addr.bit(0) == 0) {
|
||||||
return port1.bits(0,5) << 0 | port2.bits(0,1) << 6;
|
return port1.bits(0,5) << 0 | port2.bits(0,1) << 6;
|
||||||
} else {
|
} else {
|
||||||
return port2.bits(2,5) << 0 | hardware.bit(0) << 4 | 1 << 5 | port1.bit(6) << 6 | port2.bit(6) << 7;
|
return port2.bits(2,5) << 0 | reset << 4 | 1 << 5 | port1.bit(6) << 6 | port2.bit(6) << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(system.model() == Model::GameGear) {
|
if(system.model() == Model::GameGear) {
|
||||||
auto hardware = peripherals.hardware->readData();
|
bool up = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 0);
|
||||||
|
bool down = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 1);
|
||||||
|
bool left = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 2);
|
||||||
|
bool right = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 3);
|
||||||
|
bool one = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 4);
|
||||||
|
bool two = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 5);
|
||||||
|
if(!up && !down) up = 1, down = 1;
|
||||||
|
if(!left && !right) left = 1, right = 1;
|
||||||
if(addr.bit(0) == 0) {
|
if(addr.bit(0) == 0) {
|
||||||
return hardware.bits(0,5) << 0 | 0xc0;
|
return up << 0 | down << 1 | left << 2 | right << 3 | one << 4 | two << 5 | 1 << 6 | 1 << 7;
|
||||||
} else {
|
} else {
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace MasterSystem {
|
namespace MasterSystem {
|
||||||
|
|
||||||
#include "mastersystem/mastersystem.cpp"
|
|
||||||
#include "gamegear/gamegear.cpp"
|
|
||||||
#include "gamepad/gamepad.cpp"
|
#include "gamepad/gamepad.cpp"
|
||||||
|
|
||||||
Controller::Controller(uint port) : port(port) {
|
Controller::Controller(uint port) : port(port) {
|
||||||
|
@ -16,7 +14,6 @@ Controller::~Controller() {
|
||||||
auto Controller::Enter() -> void {
|
auto Controller::Enter() -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
scheduler.synchronize();
|
scheduler.synchronize();
|
||||||
if(auto device = peripherals.hardware) if(device->active()) device->main();
|
|
||||||
if(auto device = peripherals.controllerPort1) if(device->active()) device->main();
|
if(auto device = peripherals.controllerPort1) if(device->active()) device->main();
|
||||||
if(auto device = peripherals.controllerPort2) if(device->active()) device->main();
|
if(auto device = peripherals.controllerPort2) if(device->active()) device->main();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,9 @@ struct Controller : Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
|
|
||||||
virtual auto readData() -> uint8 { return 0xff; }
|
virtual auto readData() -> uint7 { return 0x7f; }
|
||||||
|
|
||||||
const uint port;
|
const uint port;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "mastersystem/mastersystem.hpp"
|
|
||||||
#include "gamegear/gamegear.hpp"
|
|
||||||
#include "gamepad/gamepad.hpp"
|
#include "gamepad/gamepad.hpp"
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
GameGearControls::GameGearControls(uint port) : Controller(port) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto GameGearControls::readData() -> uint8 {
|
|
||||||
uint8 data = 0xff;
|
|
||||||
data.bit(0) = !platform->inputPoll(port, ID::Device::GameGearControls, Up);
|
|
||||||
data.bit(1) = !platform->inputPoll(port, ID::Device::GameGearControls, Down);
|
|
||||||
data.bit(2) = !platform->inputPoll(port, ID::Device::GameGearControls, Left);
|
|
||||||
data.bit(3) = !platform->inputPoll(port, ID::Device::GameGearControls, Right);
|
|
||||||
data.bit(4) = !platform->inputPoll(port, ID::Device::GameGearControls, One);
|
|
||||||
data.bit(5) = !platform->inputPoll(port, ID::Device::GameGearControls, Two);
|
|
||||||
data.bit(6) = !platform->inputPoll(port, ID::Device::GameGearControls, Start);
|
|
||||||
return data;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
struct GameGearControls : Controller {
|
|
||||||
enum : uint {
|
|
||||||
Up, Down, Left, Right, One, Two, Start,
|
|
||||||
};
|
|
||||||
|
|
||||||
GameGearControls(uint port);
|
|
||||||
|
|
||||||
auto readData() -> uint8 override;
|
|
||||||
};
|
|
|
@ -1,8 +1,8 @@
|
||||||
Gamepad::Gamepad(uint port) : Controller(port) {
|
Gamepad::Gamepad(uint port) : Controller(port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Gamepad::readData() -> uint8 {
|
auto Gamepad::readData() -> uint7 {
|
||||||
uint8 data = 0xff;
|
uint7 data = 0x7f;
|
||||||
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||||
|
|
|
@ -5,5 +5,5 @@ struct Gamepad : Controller {
|
||||||
|
|
||||||
Gamepad(uint port);
|
Gamepad(uint port);
|
||||||
|
|
||||||
auto readData() -> uint8 override;
|
auto readData() -> uint7 override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
MasterSystemControls::MasterSystemControls(uint port) : Controller(port) {
|
|
||||||
}
|
|
||||||
|
|
||||||
auto MasterSystemControls::readData() -> uint8 {
|
|
||||||
uint8 data = 0xff;
|
|
||||||
data.bit(0) = !platform->inputPoll(port, ID::Device::MasterSystemControls, Reset);
|
|
||||||
return data;
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
struct MasterSystemControls : Controller {
|
|
||||||
enum : uint {
|
|
||||||
Reset,
|
|
||||||
};
|
|
||||||
|
|
||||||
MasterSystemControls(uint port);
|
|
||||||
|
|
||||||
auto readData() -> uint8 override;
|
|
||||||
};
|
|
|
@ -9,8 +9,6 @@ auto CPU::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
//note: SMS1 extbus value is random; SMS2+ is pulled high ($ff)
|
|
||||||
|
|
||||||
if(state.nmiLine) {
|
if(state.nmiLine) {
|
||||||
state.nmiLine = 0; //edge-sensitive
|
state.nmiLine = 0; //edge-sensitive
|
||||||
irq(0, 0x0066, 0xff);
|
irq(0, 0x0066, 0xff);
|
||||||
|
@ -31,6 +29,16 @@ auto CPU::step(uint clocks) -> void {
|
||||||
for(auto peripheral : peripherals) synchronize(*peripheral);
|
for(auto peripheral : peripherals) synchronize(*peripheral);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//called once per frame
|
||||||
|
auto CPU::pollPause() -> void {
|
||||||
|
if(system.model() == Model::MasterSystem) {
|
||||||
|
static bool pause = 0;
|
||||||
|
bool state = platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 1);
|
||||||
|
if(!pause && state) setNMI(1);
|
||||||
|
pause = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto CPU::setNMI(bool value) -> void {
|
auto CPU::setNMI(bool value) -> void {
|
||||||
state.nmiLine = value;
|
state.nmiLine = value;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +52,8 @@ auto CPU::power() -> void {
|
||||||
Z80::power();
|
Z80::power();
|
||||||
create(CPU::Enter, system.colorburst());
|
create(CPU::Enter, system.colorburst());
|
||||||
|
|
||||||
|
r.pc = 0x0000; //reset vector address
|
||||||
|
|
||||||
memory::fill(&state, sizeof(State));
|
memory::fill(&state, sizeof(State));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ struct CPU : Processor::Z80, Thread {
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
|
auto pollPause() -> void;
|
||||||
auto setNMI(bool value) -> void;
|
auto setNMI(bool value) -> void;
|
||||||
auto setINT(bool value) -> void;
|
auto setINT(bool value) -> void;
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,6 @@ struct GameGearInterface : Emulator::Interface {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
uint hardware = 0;
|
|
||||||
uint controllerPort1 = 0;
|
uint controllerPort1 = 0;
|
||||||
uint controllerPort2 = 0;
|
uint controllerPort2 = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,7 @@ MasterSystemInterface::MasterSystemInterface() {
|
||||||
|
|
||||||
{ Device device{ID::Device::MasterSystemControls, "Controls"};
|
{ Device device{ID::Device::MasterSystemControls, "Controls"};
|
||||||
device.inputs.append({0, "Reset"});
|
device.inputs.append({0, "Reset"});
|
||||||
|
device.inputs.append({0, "Pause"});
|
||||||
hardware.devices.append(device);
|
hardware.devices.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
Peripherals peripherals;
|
Peripherals peripherals;
|
||||||
|
|
||||||
auto Peripherals::unload() -> void {
|
auto Peripherals::unload() -> void {
|
||||||
delete hardware;
|
|
||||||
delete controllerPort1;
|
delete controllerPort1;
|
||||||
delete controllerPort2;
|
delete controllerPort2;
|
||||||
hardware = nullptr;
|
|
||||||
controllerPort1 = nullptr;
|
controllerPort1 = nullptr;
|
||||||
controllerPort2 = nullptr;
|
controllerPort2 = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Peripherals::reset() -> void {
|
auto Peripherals::reset() -> void {
|
||||||
connect(ID::Port::Hardware, settings.hardware);
|
|
||||||
connect(ID::Port::Controller1, settings.controllerPort1);
|
connect(ID::Port::Controller1, settings.controllerPort1);
|
||||||
connect(ID::Port::Controller2, settings.controllerPort2);
|
connect(ID::Port::Controller2, settings.controllerPort2);
|
||||||
}
|
}
|
||||||
|
@ -19,14 +16,6 @@ auto Peripherals::connect(uint port, uint device) -> void {
|
||||||
cpu.peripherals.reset();
|
cpu.peripherals.reset();
|
||||||
|
|
||||||
if(system.model() == Model::MasterSystem) {
|
if(system.model() == Model::MasterSystem) {
|
||||||
if(port == ID::Port::Hardware) {
|
|
||||||
settings.hardware = device;
|
|
||||||
if(!system.loaded()) return;
|
|
||||||
|
|
||||||
delete hardware;
|
|
||||||
hardware = new MasterSystemControls(ID::Port::Hardware);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(port == ID::Port::Controller1) {
|
if(port == ID::Port::Controller1) {
|
||||||
settings.controllerPort1 = device;
|
settings.controllerPort1 = device;
|
||||||
if(!system.loaded()) return;
|
if(!system.loaded()) return;
|
||||||
|
@ -49,20 +38,7 @@ auto Peripherals::connect(uint port, uint device) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu.peripherals.append(hardware);
|
|
||||||
cpu.peripherals.append(controllerPort1);
|
cpu.peripherals.append(controllerPort1);
|
||||||
cpu.peripherals.append(controllerPort2);
|
cpu.peripherals.append(controllerPort2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(system.model() == Model::GameGear) {
|
|
||||||
if(port == ID::Port::Hardware) {
|
|
||||||
settings.hardware = device;
|
|
||||||
if(!system.loaded()) return;
|
|
||||||
|
|
||||||
delete hardware;
|
|
||||||
hardware = new GameGearControls(ID::Port::Hardware);
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu.peripherals.append(hardware);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,10 @@ System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
|
|
||||||
auto System::run() -> void {
|
auto System::run() -> void {
|
||||||
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
if(scheduler.enter() == Scheduler::Event::Frame) {
|
||||||
|
cpu.pollPause();
|
||||||
|
vdp.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
||||||
|
|
|
@ -27,7 +27,6 @@ struct Peripherals {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto connect(uint port, uint device) -> void;
|
auto connect(uint port, uint device) -> void;
|
||||||
|
|
||||||
Controller* hardware = nullptr;
|
|
||||||
Controller* controllerPort1 = nullptr;
|
Controller* controllerPort1 = nullptr;
|
||||||
Controller* controllerPort2 = nullptr;
|
Controller* controllerPort2 = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,20 +30,26 @@ auto VDP::main() -> void {
|
||||||
|
|
||||||
//684 clocks/scanline
|
//684 clocks/scanline
|
||||||
uint y = io.vcounter;
|
uint y = io.vcounter;
|
||||||
for(uint x : range(256)) {
|
if(y < vlines()) {
|
||||||
background.run();
|
uint32* screen = buffer + (24 + y) * 256;
|
||||||
sprite.run();
|
for(uint x : range(256)) {
|
||||||
step(2);
|
background.run();
|
||||||
|
sprite.run();
|
||||||
|
step(2);
|
||||||
|
|
||||||
uint12 color = palette(io.backdropColor);
|
uint12 color = palette(io.backdropColor);
|
||||||
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
||||||
color = palette(background.output.palette << 4 | background.output.color);
|
color = palette(background.output.palette << 4 | background.output.color);
|
||||||
} else if(sprite.output.color) {
|
} else if(sprite.output.color) {
|
||||||
color = palette(16 | sprite.output.color);
|
color = palette(16 | sprite.output.color);
|
||||||
|
}
|
||||||
|
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
||||||
|
if(!io.displayEnable) color = 0;
|
||||||
|
*screen++ = color;
|
||||||
}
|
}
|
||||||
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
} else {
|
||||||
if(!io.displayEnable || y >= vlines()) color = 0;
|
//Vblank
|
||||||
buffer[io.vcounter * 256 + x] = color;
|
step(512);
|
||||||
}
|
}
|
||||||
step(172);
|
step(172);
|
||||||
|
|
||||||
|
@ -67,11 +73,16 @@ auto VDP::step(uint clocks) -> void {
|
||||||
|
|
||||||
auto VDP::refresh() -> void {
|
auto VDP::refresh() -> void {
|
||||||
if(system.model() == Model::MasterSystem) {
|
if(system.model() == Model::MasterSystem) {
|
||||||
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
//center the video output vertically in the viewport
|
||||||
|
uint32* screen = buffer;
|
||||||
|
if(vlines() == 224) screen += 16 * 256;
|
||||||
|
if(vlines() == 240) screen += 24 * 256;
|
||||||
|
|
||||||
|
Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(system.model() == Model::GameGear) {
|
if(system.model() == Model::GameGear) {
|
||||||
Emulator::video.refresh(buffer + 24 * 256 + 48, 256 * sizeof(uint32), 160, 144);
|
Emulator::video.refresh(buffer + 48 * 256 + 48, 256 * sizeof(uint32), 160, 144);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +99,7 @@ auto VDP::vblank() -> bool {
|
||||||
auto VDP::power() -> void {
|
auto VDP::power() -> void {
|
||||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||||
|
|
||||||
|
memory::fill(&buffer, sizeof(buffer));
|
||||||
memory::fill(&io, sizeof(IO));
|
memory::fill(&io, sizeof(IO));
|
||||||
|
|
||||||
background.power();
|
background.power();
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct VDP : Thread {
|
||||||
private:
|
private:
|
||||||
auto palette(uint5 index) -> uint12;
|
auto palette(uint5 index) -> uint12;
|
||||||
|
|
||||||
uint32 buffer[256 * 262];
|
uint32 buffer[256 * 264];
|
||||||
uint8 vram[0x4000];
|
uint8 vram[0x4000];
|
||||||
uint8 cram[0x40]; //MS = 0x20, GG = 0x40
|
uint8 cram[0x40]; //MS = 0x20, GG = 0x40
|
||||||
|
|
||||||
|
|
|
@ -30,44 +30,32 @@ auto Cartridge::load() -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto node = document["board/ram"]) {
|
|
||||||
ram.size = node["size"].natural();
|
|
||||||
if(ram.size) {
|
|
||||||
ram.data = new uint8[ram.size]();
|
|
||||||
if(auto name = node["name"].text()) {
|
|
||||||
if(auto fp = platform->open(pathID(), name, File::Read)) {
|
|
||||||
fp->read(ram.data, ram.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::save() -> void {
|
auto Cartridge::save() -> void {
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
if(auto name = document["board/ram/name"].text()) {
|
|
||||||
if(auto fp = platform->open(pathID(), name, File::Write)) {
|
|
||||||
fp->write(ram.data, ram.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::unload() -> void {
|
auto Cartridge::unload() -> void {
|
||||||
delete[] rom.data;
|
delete[] rom.data;
|
||||||
delete[] ram.data;
|
|
||||||
rom = {};
|
rom = {};
|
||||||
ram = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::power() -> void {
|
auto Cartridge::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::Memory::mirror(uint addr, uint size) -> uint {
|
auto Cartridge::read(uint20 addr) -> uint8 {
|
||||||
|
if(!rom.size) return 0x00;
|
||||||
|
return rom.data[mirror(addr, rom.size)];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::write(uint20 addr, uint8 data) -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::mirror(uint addr, uint size) -> uint {
|
||||||
uint base = 0;
|
uint base = 0;
|
||||||
uint mask = 1 << 23;
|
uint mask = 1 << 20;
|
||||||
while(addr >= size) {
|
while(addr >= size) {
|
||||||
while(!(addr & mask)) mask >>= 1;
|
while(!(addr & mask)) mask >>= 1;
|
||||||
addr -= mask;
|
addr -= mask;
|
||||||
|
@ -80,14 +68,4 @@ auto Cartridge::Memory::mirror(uint addr, uint size) -> uint {
|
||||||
return base + addr;
|
return base + addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::Memory::read(uint addr) -> uint8 {
|
|
||||||
if(!size) return 0x00;
|
|
||||||
return this->data[mirror(addr, size)];
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::Memory::write(uint addr, uint8 data) -> void {
|
|
||||||
if(!size) return;
|
|
||||||
this->data[mirror(addr, size)] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,12 @@ struct Cartridge {
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
auto read(uint20 addr) -> uint8;
|
||||||
|
auto write(uint20 addr, uint8 data) -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
auto mirror(uint addr, uint size) -> uint;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
uint pathID = 0;
|
uint pathID = 0;
|
||||||
string sha256;
|
string sha256;
|
||||||
|
@ -21,14 +26,9 @@ private:
|
||||||
struct Memory {
|
struct Memory {
|
||||||
uint8* data = nullptr;
|
uint8* data = nullptr;
|
||||||
uint size = 0;
|
uint size = 0;
|
||||||
|
|
||||||
static auto mirror(uint addr, uint size) -> uint;
|
|
||||||
auto read(uint addr) -> uint8;
|
|
||||||
auto write(uint addr, uint8 data) -> void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Memory rom;
|
Memory rom;
|
||||||
Memory ram;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Cartridge cartridge;
|
extern Cartridge cartridge;
|
||||||
|
|
|
@ -11,7 +11,7 @@ auto CPU::Enter() -> void {
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
#if 1
|
#if 1
|
||||||
static uint counter = 0;
|
static uint counter = 0;
|
||||||
if(++counter < 10) {
|
if(counter++ < 40) {
|
||||||
print(disassemble(r.pc), "\n");
|
print(disassemble(r.pc), "\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,22 +29,29 @@ 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() * 6.0);
|
||||||
|
|
||||||
|
r.pc.byte(0) = read(0x1ffe);
|
||||||
|
r.pc.byte(1) = read(0x1fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::read(uint16 addr) -> uint8 {
|
auto CPU::read(uint21 addr) -> uint8 {
|
||||||
step(3);
|
if(!addr.bit(20)) return cartridge.read(addr);
|
||||||
return 0xea;
|
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(uint16 addr, uint8 data) -> void {
|
auto CPU::write(uint21 addr, uint8 data) -> void {
|
||||||
step(3);
|
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::lastCycle() -> void {
|
auto CPU::lastCycle() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::disassembleRead(uint16 pc) -> uint8 {
|
|
||||||
return 0xea;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,14 @@ struct CPU : Processor::HuC6280, Thread {
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
auto read(uint16 addr) -> uint8 override;
|
auto read(uint21 addr) -> uint8 override;
|
||||||
auto write(uint16 addr, uint8 data) -> void override;
|
auto write(uint21 addr, uint8 data) -> void override;
|
||||||
auto lastCycle() -> void override;
|
auto lastCycle() -> void override;
|
||||||
|
|
||||||
auto disassembleRead(uint16 addr) -> uint8 override;
|
|
||||||
|
|
||||||
vector<Thread*> peripherals;
|
vector<Thread*> peripherals;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram[0x2000];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//Video Display Controller
|
//Hudson Soft HuC6260 -- Video Color Encoder
|
||||||
|
//Hudson Soft HuC6270 -- Video Display Controller
|
||||||
|
|
||||||
struct VDC : Thread {
|
struct VDC : Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
|
|
|
@ -1,12 +1,218 @@
|
||||||
auto HuC6280::disassemble(uint16 pc) -> string {
|
auto HuC6280::disassemble(uint16 pc_) -> string {
|
||||||
string s{hex(r.pc, 4L), " "};
|
uint21 pc = mmu(pc_);
|
||||||
uint8 opcode = disassembleRead(pc++);
|
string s{hex((uint)pc.bits(13,20), 2L), ":", hex((uint)pc.bits(0,12), 4L), " "};
|
||||||
|
|
||||||
#define op(id, name, ...) case id: o = {name, string_vector{__VA_ARGS__}.merge(",")};
|
auto readByte = [&]() -> uint8 {
|
||||||
|
return read(pc++);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto readWord = [&]() -> uint16 {
|
||||||
|
uint16 data = read(pc++);
|
||||||
|
return data | read(pc++) << 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto absolute = [&]() -> string { return {"$", hex(readWord(), 4L)}; };
|
||||||
|
auto absoluteX = [&]() -> string { return {"$", hex(readWord(), 4L), ",x"}; };
|
||||||
|
auto absoluteY = [&]() -> string { return {"$", hex(readWord(), 4L), ",y"}; };
|
||||||
|
auto immediate = [&]() -> string { return {"#$", hex(readByte(), 2L)}; };
|
||||||
|
auto indirect = [&]() -> string { return {"($", hex(readByte(), 2L), ")"}; };
|
||||||
|
auto indirectX = [&]() -> string { return {"($", hex(readByte(), 2L), ",x)"}; };
|
||||||
|
auto indirectY = [&]() -> string { return {"($", hex(readByte(), 2L), "),y"}; };
|
||||||
|
auto memory = [&]() -> string { return {"(x),#$", hex(readByte(), 2L)}; };
|
||||||
|
auto relative = [&]() -> string { auto displacement = readByte(); return {"$", hex(pc + (int8)displacement, 4L)}; };
|
||||||
|
auto zeropage = [&]() -> string { return {"$", hex(readByte(), 2L)}; };
|
||||||
|
auto zeropageX = [&]() -> string { return {"$", hex(readByte(), 2L), ",x"}; };
|
||||||
|
auto zeropageY = [&]() -> string { return {"$", hex(readByte(), 2L), ",y"}; };
|
||||||
|
|
||||||
|
uint8 opcode = readByte();
|
||||||
|
|
||||||
|
#define op(id, name, ...) case id: o = {name, " ", string_vector{__VA_ARGS__}.merge(",")}; break;
|
||||||
string o;
|
string o;
|
||||||
switch(opcode) {
|
|
||||||
op(0xea, "nop")
|
if(T == 1) switch(opcode) {
|
||||||
|
op(0x09, "ora", memory())
|
||||||
|
op(0x29, "and", memory())
|
||||||
|
op(0x49, "eor", memory())
|
||||||
|
op(0x69, "adc", memory())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(T == 0) switch(opcode) {
|
||||||
|
op(0x01, "ora", indirectX())
|
||||||
|
op(0x02, "sxy")
|
||||||
|
op(0x05, "ora", zeropage())
|
||||||
|
op(0x06, "asl", zeropage())
|
||||||
|
op(0x08, "php")
|
||||||
|
op(0x09, "ora", immediate())
|
||||||
|
op(0x0a, "asl")
|
||||||
|
op(0x0d, "ora", absolute())
|
||||||
|
op(0x0e, "asl", absolute())
|
||||||
|
op(0x10, "bpl", relative())
|
||||||
|
op(0x11, "ora", indirectY())
|
||||||
|
op(0x12, "ora", indirect())
|
||||||
|
op(0x15, "ora", zeropageX())
|
||||||
|
op(0x16, "asl", zeropageX())
|
||||||
|
op(0x18, "clc")
|
||||||
|
op(0x19, "ora", absoluteY())
|
||||||
|
op(0x1a, "inc")
|
||||||
|
op(0x1d, "ora", absoluteX())
|
||||||
|
op(0x1e, "asl", absoluteX())
|
||||||
|
op(0x21, "and", indirectX())
|
||||||
|
op(0x22, "sax")
|
||||||
|
op(0x24, "bit", zeropage())
|
||||||
|
op(0x25, "and", zeropage())
|
||||||
|
op(0x26, "rol", zeropage())
|
||||||
|
op(0x28, "plp")
|
||||||
|
op(0x29, "and", immediate())
|
||||||
|
op(0x2a, "rol")
|
||||||
|
op(0x2c, "bit", absolute())
|
||||||
|
op(0x2d, "and", absolute())
|
||||||
|
op(0x2e, "rol", absolute())
|
||||||
|
op(0x30, "bmi", relative())
|
||||||
|
op(0x31, "and", indirectY())
|
||||||
|
op(0x32, "and", indirect())
|
||||||
|
op(0x34, "bit", zeropageX())
|
||||||
|
op(0x35, "and", zeropageX())
|
||||||
|
op(0x36, "rol", zeropageX())
|
||||||
|
op(0x38, "sec")
|
||||||
|
op(0x39, "and", absoluteY())
|
||||||
|
op(0x3a, "dec")
|
||||||
|
op(0x3c, "bit", absoluteX())
|
||||||
|
op(0x3d, "and", absoluteX())
|
||||||
|
op(0x3e, "rol", absoluteX())
|
||||||
|
op(0x41, "eor", indirectX())
|
||||||
|
op(0x42, "say")
|
||||||
|
op(0x43, "tma", immediate())
|
||||||
|
op(0x45, "eor", zeropage())
|
||||||
|
op(0x46, "lsr", zeropage())
|
||||||
|
op(0x48, "pha")
|
||||||
|
op(0x49, "eor", immediate())
|
||||||
|
op(0x4a, "lsr")
|
||||||
|
op(0x4d, "eor", absolute())
|
||||||
|
op(0x4e, "lsr", absolute())
|
||||||
|
op(0x50, "bvc", relative())
|
||||||
|
op(0x51, "eor", indirectY())
|
||||||
|
op(0x52, "eor", indirect())
|
||||||
|
op(0x53, "tam", immediate())
|
||||||
|
op(0x54, "csl")
|
||||||
|
op(0x55, "eor", zeropageX())
|
||||||
|
op(0x56, "lsr", zeropageX())
|
||||||
|
op(0x58, "cli")
|
||||||
|
op(0x59, "eor", absoluteY())
|
||||||
|
op(0x5a, "phy")
|
||||||
|
op(0x5d, "eor", absoluteX())
|
||||||
|
op(0x5e, "lsr", absoluteX())
|
||||||
|
op(0x61, "adc", indirectX())
|
||||||
|
op(0x62, "cla")
|
||||||
|
op(0x64, "stz", zeropage())
|
||||||
|
op(0x65, "adc", zeropage())
|
||||||
|
op(0x66, "ror", zeropage())
|
||||||
|
op(0x68, "pla")
|
||||||
|
op(0x69, "adc", immediate())
|
||||||
|
op(0x6a, "ror")
|
||||||
|
op(0x6d, "adc", absolute())
|
||||||
|
op(0x6e, "ror", absolute())
|
||||||
|
op(0x70, "bvs", relative())
|
||||||
|
op(0x71, "adc", indirectY())
|
||||||
|
op(0x72, "adc", indirect())
|
||||||
|
op(0x74, "stz", zeropageX())
|
||||||
|
op(0x75, "adc", zeropageX())
|
||||||
|
op(0x76, "ror", zeropageX())
|
||||||
|
op(0x78, "sei")
|
||||||
|
op(0x79, "adc", absoluteY())
|
||||||
|
op(0x7a, "ply")
|
||||||
|
op(0x7d, "adc", absoluteX())
|
||||||
|
op(0x7e, "ror", absoluteX())
|
||||||
|
op(0x80, "bra", relative())
|
||||||
|
op(0x81, "sta", indirectX())
|
||||||
|
op(0x82, "clx")
|
||||||
|
op(0x84, "sty", zeropage())
|
||||||
|
op(0x85, "sta", zeropage())
|
||||||
|
op(0x86, "stx", zeropage())
|
||||||
|
op(0x88, "dey")
|
||||||
|
op(0x89, "bit", immediate())
|
||||||
|
op(0x8a, "txa")
|
||||||
|
op(0x8c, "sty", absolute())
|
||||||
|
op(0x8d, "sta", absolute())
|
||||||
|
op(0x8e, "stx", absolute())
|
||||||
|
op(0x90, "bcc", relative())
|
||||||
|
op(0x91, "sta", indirectY())
|
||||||
|
op(0x92, "sta", indirect())
|
||||||
|
op(0x94, "sty", zeropageX())
|
||||||
|
op(0x95, "sta", zeropageX())
|
||||||
|
op(0x96, "stx", zeropageY())
|
||||||
|
op(0x98, "tya")
|
||||||
|
op(0x99, "sta", absoluteY())
|
||||||
|
op(0x9a, "txs")
|
||||||
|
op(0x9c, "stz", absolute())
|
||||||
|
op(0x9d, "sta", absoluteX())
|
||||||
|
op(0x9e, "stz", absoluteX())
|
||||||
|
op(0xa0, "ldy", immediate())
|
||||||
|
op(0xa1, "lda", indirectX())
|
||||||
|
op(0xa2, "ldx", immediate())
|
||||||
|
op(0xa4, "ldy", zeropage())
|
||||||
|
op(0xa5, "lda", zeropage())
|
||||||
|
op(0xa6, "ldx", zeropage())
|
||||||
|
op(0xa8, "tay")
|
||||||
|
op(0xa9, "lda", immediate())
|
||||||
|
op(0xaa, "tax")
|
||||||
|
op(0xac, "ldy", absolute())
|
||||||
|
op(0xad, "lda", absolute())
|
||||||
|
op(0xae, "ldx", absolute())
|
||||||
|
op(0xb0, "bcs", relative())
|
||||||
|
op(0xb1, "lda", indirectY())
|
||||||
|
op(0xb2, "lda", indirect())
|
||||||
|
op(0xb4, "ldy", zeropageX())
|
||||||
|
op(0xb5, "lda", zeropageX())
|
||||||
|
op(0xb6, "ldx", zeropageY())
|
||||||
|
op(0xb8, "clv")
|
||||||
|
op(0xb9, "lda", absoluteY())
|
||||||
|
op(0xba, "tsx")
|
||||||
|
op(0xbc, "ldy", absoluteX())
|
||||||
|
op(0xbd, "lda", absoluteX())
|
||||||
|
op(0xbe, "ldx", absoluteY())
|
||||||
|
op(0xc0, "cpy", immediate())
|
||||||
|
op(0xc1, "cmp", indirectX())
|
||||||
|
op(0xc2, "cly")
|
||||||
|
op(0xc5, "cmp", zeropage())
|
||||||
|
op(0xc6, "dec", zeropage())
|
||||||
|
op(0xc8, "iny")
|
||||||
|
op(0xc9, "cmp", immediate())
|
||||||
|
op(0xca, "dex")
|
||||||
|
op(0xcd, "cmp", absolute())
|
||||||
|
op(0xce, "dec", absolute())
|
||||||
|
op(0xd0, "bne", relative())
|
||||||
|
op(0xd1, "cmp", indirectY())
|
||||||
|
op(0xd2, "cmp", indirect())
|
||||||
|
op(0xd4, "csh")
|
||||||
|
op(0xd5, "cmp", zeropageX())
|
||||||
|
op(0xd6, "dec", zeropageX())
|
||||||
|
op(0xd8, "cld")
|
||||||
|
op(0xd9, "cmp", absoluteY())
|
||||||
|
op(0xda, "phx")
|
||||||
|
op(0xdd, "cmp", absoluteX())
|
||||||
|
op(0xde, "dec", absoluteX())
|
||||||
|
op(0xe0, "cpx", immediate())
|
||||||
|
op(0xe1, "sbc", indirectX())
|
||||||
|
op(0xe5, "sbc", zeropage())
|
||||||
|
op(0xe6, "inc", zeropage())
|
||||||
|
op(0xe8, "inx")
|
||||||
|
op(0xe9, "sbc", immediate())
|
||||||
|
op(0xea, "nop")
|
||||||
|
op(0xed, "sbc", absolute())
|
||||||
|
op(0xee, "inc", absolute())
|
||||||
|
op(0xf0, "beq", relative())
|
||||||
|
op(0xf1, "sbc", indirectY())
|
||||||
|
op(0xf2, "sbc", indirect())
|
||||||
|
op(0xf4, "set")
|
||||||
|
op(0xf5, "sbc", zeropageX())
|
||||||
|
op(0xf6, "inc", zeropageX())
|
||||||
|
op(0xf8, "sed")
|
||||||
|
op(0xf9, "sbc", absoluteY())
|
||||||
|
op(0xfa, "plx")
|
||||||
|
op(0xfd, "sbc", absoluteX())
|
||||||
|
op(0xfe, "inc", absoluteX())
|
||||||
|
}
|
||||||
|
|
||||||
if(!o) o = {"??? (", hex(opcode, 2L), ")"};
|
if(!o) o = {"??? (", hex(opcode, 2L), ")"};
|
||||||
s.append(pad(o, -16L, ' '));
|
s.append(pad(o, -16L, ' '));
|
||||||
#undef op
|
#undef op
|
||||||
|
@ -15,6 +221,7 @@ auto HuC6280::disassemble(uint16 pc) -> string {
|
||||||
s.append(" X:", hex(r.x, 2L));
|
s.append(" X:", hex(r.x, 2L));
|
||||||
s.append(" Y:", hex(r.y, 2L));
|
s.append(" Y:", hex(r.y, 2L));
|
||||||
s.append(" S:", hex(r.s, 2L));
|
s.append(" S:", hex(r.s, 2L));
|
||||||
|
s.append(" PC:", hex(pc_, 4L));
|
||||||
s.append(" ");
|
s.append(" ");
|
||||||
s.append(r.p.n ? "N" : "n");
|
s.append(r.p.n ? "N" : "n");
|
||||||
s.append(r.p.v ? "V" : "v");
|
s.append(r.p.v ? "V" : "v");
|
||||||
|
@ -24,6 +231,7 @@ auto HuC6280::disassemble(uint16 pc) -> string {
|
||||||
s.append(r.p.i ? "I" : "i");
|
s.append(r.p.i ? "I" : "i");
|
||||||
s.append(r.p.z ? "Z" : "z");
|
s.append(r.p.z ? "Z" : "z");
|
||||||
s.append(r.p.c ? "C" : "c");
|
s.append(r.p.c ? "C" : "c");
|
||||||
|
s.append(r.cs == 3 ? "+" : "-");
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,66 @@
|
||||||
|
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
|
#define A r.a
|
||||||
|
#define X r.x
|
||||||
|
#define Y r.y
|
||||||
|
#define S r.s
|
||||||
|
#define PC r.pc
|
||||||
|
#define PCH r.pc.byte(1)
|
||||||
|
#define PCL r.pc.byte(0)
|
||||||
|
#define P r.p
|
||||||
|
#define C r.p.c
|
||||||
|
#define Z r.p.z
|
||||||
|
#define I r.p.i
|
||||||
|
#define D r.p.d
|
||||||
|
#define B r.p.b
|
||||||
|
#define T r.p.t
|
||||||
|
#define V r.p.v
|
||||||
|
#define N r.p.n
|
||||||
|
#define EA r.ea
|
||||||
#define L lastCycle();
|
#define L lastCycle();
|
||||||
|
#define ALU (this->*alu)
|
||||||
#include "memory.cpp"
|
#include "memory.cpp"
|
||||||
#include "instruction.cpp"
|
#include "instruction.cpp"
|
||||||
#include "instructions.cpp"
|
#include "instructions.cpp"
|
||||||
#include "disassembler.cpp"
|
#include "disassembler.cpp"
|
||||||
|
#undef A
|
||||||
|
#undef X
|
||||||
|
#undef Y
|
||||||
|
#undef S
|
||||||
|
#undef PC
|
||||||
|
#undef PCH
|
||||||
|
#undef PCL
|
||||||
|
#undef P
|
||||||
|
#undef C
|
||||||
|
#undef Z
|
||||||
|
#undef I
|
||||||
|
#undef D
|
||||||
|
#undef B
|
||||||
|
#undef T
|
||||||
|
#undef V
|
||||||
|
#undef N
|
||||||
|
#undef EA
|
||||||
#undef L
|
#undef L
|
||||||
|
#undef ALU
|
||||||
|
|
||||||
auto HuC6280::power() -> void {
|
auto HuC6280::power() -> void {
|
||||||
r.a = 0x00;
|
r.a = 0x00;
|
||||||
r.x = 0x00;
|
r.x = 0x00;
|
||||||
r.y = 0x00;
|
r.y = 0x00;
|
||||||
r.s = 0x00;
|
r.s = 0xff;
|
||||||
r.pc = 0x0000;
|
r.pc = 0x0000;
|
||||||
r.p = 0x00;
|
r.mpr[0] = 0xff;
|
||||||
|
r.mpr[1] = 0xf8;
|
||||||
|
r.mpr[2] = 0x00;
|
||||||
|
r.mpr[3] = 0x00;
|
||||||
|
r.mpr[4] = 0x00;
|
||||||
|
r.mpr[5] = 0x00;
|
||||||
|
r.mpr[6] = 0x00;
|
||||||
|
r.mpr[7] = 0x00;
|
||||||
r.mdr = 0x00;
|
r.mdr = 0x00;
|
||||||
|
r.p = 0x04;
|
||||||
|
r.cs = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//Hudson Soft HuC6280A
|
//Hudson Soft HuC6280
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
@ -6,45 +6,107 @@ namespace Processor {
|
||||||
|
|
||||||
struct HuC6280 {
|
struct HuC6280 {
|
||||||
virtual auto step(uint clocks) -> void = 0;
|
virtual auto step(uint clocks) -> void = 0;
|
||||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
virtual auto read(uint21 addr) -> uint8 = 0;
|
||||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
virtual auto write(uint21 addr, uint8 data) -> void = 0;
|
||||||
virtual auto lastCycle() -> void = 0;
|
virtual auto lastCycle() -> void = 0;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
|
inline auto mmu(uint16) const -> uint21;
|
||||||
|
inline auto load(uint16) -> uint8;
|
||||||
|
inline auto store(uint16, uint8) -> void;
|
||||||
|
|
||||||
auto io() -> uint8;
|
auto io() -> uint8;
|
||||||
auto opcode() -> uint8;
|
auto opcode() -> uint8;
|
||||||
auto operand() -> uint8;
|
auto operand() -> uint8;
|
||||||
|
|
||||||
|
auto push(uint8) -> void;
|
||||||
|
auto pull() -> uint8;
|
||||||
|
|
||||||
//instruction.cpp
|
//instruction.cpp
|
||||||
auto instruction() -> void;
|
auto instruction() -> void;
|
||||||
|
|
||||||
//instructions.cpp
|
//instructions.cpp
|
||||||
auto instructionNOP() -> void;
|
auto ADC(uint8) -> uint8;
|
||||||
|
auto AND(uint8) -> uint8;
|
||||||
|
auto ASL(uint8) -> uint8;
|
||||||
|
auto BIT(uint8) -> uint8;
|
||||||
|
auto CMP(uint8) -> uint8;
|
||||||
|
auto CPX(uint8) -> uint8;
|
||||||
|
auto CPY(uint8) -> uint8;
|
||||||
|
auto DEC(uint8) -> uint8;
|
||||||
|
auto EOR(uint8) -> uint8;
|
||||||
|
auto INC(uint8) -> uint8;
|
||||||
|
auto LD (uint8) -> uint8;
|
||||||
|
auto LSR(uint8) -> uint8;
|
||||||
|
auto ORA(uint8) -> uint8;
|
||||||
|
auto ROL(uint8) -> uint8;
|
||||||
|
auto ROR(uint8) -> uint8;
|
||||||
|
auto SBC(uint8) -> uint8;
|
||||||
|
|
||||||
|
using fp = auto (HuC6280::*)(uint8) -> uint8;
|
||||||
|
auto instruction_alu_absolute(fp, uint8 = 0) -> void;
|
||||||
|
auto instruction_alu_immediate(fp) -> void;
|
||||||
|
auto instruction_alu_implied(fp, uint8&) -> void;
|
||||||
|
auto instruction_alu_indirect(fp, uint8 = 0) -> void;
|
||||||
|
auto instruction_alu_indirectY(fp) -> void;
|
||||||
|
auto instruction_alu_memory(fp) -> void;
|
||||||
|
auto instruction_alu_zeropage(fp, uint8 = 0) -> void;
|
||||||
|
auto instruction_bra(bool) -> void;
|
||||||
|
auto instruction_CLb(uint8&) -> void;
|
||||||
|
auto instruction_CLf(bool&) -> void;
|
||||||
|
auto instruction_CSL() -> void;
|
||||||
|
auto instruction_CSH() -> void;
|
||||||
|
auto instruction_LDA_indirect(uint8 index = 0) -> void;
|
||||||
|
auto instruction_LDA_indirectY() -> void;
|
||||||
|
auto instruction_LDb_absolute(uint8&, uint8 = 0) -> void;
|
||||||
|
auto instruction_LDb_immediate(uint8&) -> void;
|
||||||
|
auto instruction_LDb_zeropage(uint8&, uint8 = 0) -> void;
|
||||||
|
auto instruction_NOP() -> void;
|
||||||
|
auto instruction_PHb(uint8&) -> void;
|
||||||
|
auto instruction_PHP() -> void;
|
||||||
|
auto instruction_PLb(uint8&) -> void;
|
||||||
|
auto instruction_PLP() -> void;
|
||||||
|
auto instruction_SEf(bool&) -> void;
|
||||||
|
auto instruction_STA_indirect(uint8 index = 0) -> void;
|
||||||
|
auto instruction_STA_indirectY() -> void;
|
||||||
|
auto instruction_STb_absolute(uint8, uint8 = 0) -> void;
|
||||||
|
auto instruction_STb_zeropage(uint8, uint8 = 0) -> void;
|
||||||
|
auto instruction_Sbb(uint8&, uint8&) -> void;
|
||||||
|
auto instruction_TAM() -> void;
|
||||||
|
auto instruction_Tbb(uint8&, uint8&) -> void;
|
||||||
|
auto instruction_TMA() -> void;
|
||||||
|
auto instruction_TXS() -> void;
|
||||||
|
|
||||||
//disassembler.cpp
|
//disassembler.cpp
|
||||||
virtual auto disassembleRead(uint16 pc) -> uint8 = 0;
|
|
||||||
auto disassemble(uint16 pc) -> string;
|
auto disassemble(uint16 pc) -> string;
|
||||||
|
|
||||||
struct Flags {
|
struct Flags {
|
||||||
union {
|
bool c; //carry
|
||||||
uint8_t data = 0;
|
bool z; //zero
|
||||||
BooleanBitField<uint8_t, 0> c; //carry
|
bool i; //interrupt disable
|
||||||
BooleanBitField<uint8_t, 1> z; //zero
|
bool d; //decimal mode
|
||||||
BooleanBitField<uint8_t, 2> i; //interrupt
|
bool b; //break
|
||||||
BooleanBitField<uint8_t, 3> d; //decimal
|
bool t; //memory operation
|
||||||
BooleanBitField<uint8_t, 4> b; //break
|
bool v; //overflow
|
||||||
BooleanBitField<uint8_t, 5> t; //...
|
bool n; //negative
|
||||||
BooleanBitField<uint8_t, 6> v; //overflow
|
|
||||||
BooleanBitField<uint8_t, 7> n; //negative
|
|
||||||
};
|
|
||||||
|
|
||||||
inline operator uint() const { return data; }
|
inline operator uint8() const {
|
||||||
inline auto& operator =(uint value) { return data = value, *this; }
|
return c << 0 | z << 1 | i << 2 | d << 3 | b << 4 | t << 5 | v << 6 | n << 7;
|
||||||
inline auto& operator&=(uint value) { return data &= value, *this; }
|
}
|
||||||
inline auto& operator|=(uint value) { return data |= value, *this; }
|
|
||||||
inline auto& operator^=(uint value) { return data ^= value, *this; }
|
inline auto& operator=(uint8 data) {
|
||||||
|
c = data.bit(0);
|
||||||
|
z = data.bit(1);
|
||||||
|
i = data.bit(2);
|
||||||
|
d = data.bit(3);
|
||||||
|
b = data.bit(4);
|
||||||
|
t = data.bit(5);
|
||||||
|
v = data.bit(6);
|
||||||
|
n = data.bit(7);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
|
@ -53,8 +115,10 @@ struct HuC6280 {
|
||||||
uint8 y;
|
uint8 y;
|
||||||
uint8 s;
|
uint8 s;
|
||||||
uint16 pc;
|
uint16 pc;
|
||||||
Flags p;
|
uint8 mpr[8];
|
||||||
uint8 mdr;
|
uint8 mdr;
|
||||||
|
Flags p;
|
||||||
|
uint8 cs; //code speed (3 = fast, 12 = slow)
|
||||||
} r;
|
} r;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,196 @@
|
||||||
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
#define op(id, name, ...) case id: instruction_##name(__VA_ARGS__); return;
|
||||||
|
#define fp(name) &HuC6280::name
|
||||||
|
|
||||||
auto HuC6280::instruction() -> void {
|
auto HuC6280::instruction() -> void {
|
||||||
switch(opcode()) {
|
auto code = opcode();
|
||||||
|
|
||||||
|
if(T) {
|
||||||
|
T = 0;
|
||||||
|
switch(code) {
|
||||||
|
op(0x09, alu_memory, fp(ORA))
|
||||||
|
op(0x29, alu_memory, fp(AND))
|
||||||
|
op(0x49, alu_memory, fp(EOR))
|
||||||
|
op(0x69, alu_memory, fp(ADC))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(code) {
|
||||||
|
op(0x01, alu_indirect, fp(ORA), X)
|
||||||
|
op(0x02, Sbb, X, Y)
|
||||||
|
op(0x05, alu_zeropage, fp(ORA))
|
||||||
|
op(0x06, alu_zeropage, fp(ASL))
|
||||||
|
op(0x08, PHP)
|
||||||
|
op(0x09, alu_immediate, fp(ORA))
|
||||||
|
op(0x0a, alu_implied, fp(ASL), A)
|
||||||
|
op(0x0d, alu_absolute, fp(ORA))
|
||||||
|
op(0x0e, alu_absolute, fp(ASL))
|
||||||
|
op(0x10, bra, N == 0)
|
||||||
|
op(0x11, alu_indirectY, fp(ORA))
|
||||||
|
op(0x12, alu_indirect, fp(ORA))
|
||||||
|
op(0x15, alu_zeropage, fp(ORA), X)
|
||||||
|
op(0x16, alu_zeropage, fp(ASL), X)
|
||||||
|
op(0x18, CLf, C)
|
||||||
|
op(0x19, alu_absolute, fp(ORA), Y)
|
||||||
|
op(0x1a, alu_implied, fp(INC), A)
|
||||||
|
op(0x1d, alu_absolute, fp(ORA), X)
|
||||||
|
op(0x1e, alu_absolute, fp(ASL), X)
|
||||||
|
op(0x21, alu_indirect, fp(AND), X)
|
||||||
|
op(0x22, Sbb, A, X)
|
||||||
|
op(0x24, alu_zeropage, fp(BIT))
|
||||||
|
op(0x25, alu_zeropage, fp(AND))
|
||||||
|
op(0x26, alu_zeropage, fp(ROL))
|
||||||
|
op(0x28, PLP)
|
||||||
|
op(0x29, alu_immediate, fp(AND))
|
||||||
|
op(0x2a, alu_implied, fp(ROL), A)
|
||||||
|
op(0x2c, alu_absolute, fp(BIT))
|
||||||
|
op(0x2d, alu_absolute, fp(AND))
|
||||||
|
op(0x2e, alu_absolute, fp(ROL))
|
||||||
|
op(0x30, bra, N == 1)
|
||||||
|
op(0x31, alu_indirectY, fp(AND))
|
||||||
|
op(0x32, alu_indirect, fp(AND))
|
||||||
|
op(0x34, alu_zeropage, fp(BIT), X)
|
||||||
|
op(0x35, alu_zeropage, fp(AND), X)
|
||||||
|
op(0x36, alu_zeropage, fp(ROL), X)
|
||||||
|
op(0x38, SEf, C)
|
||||||
|
op(0x39, alu_absolute, fp(AND), Y)
|
||||||
|
op(0x3a, alu_implied, fp(DEC), A)
|
||||||
|
op(0x3c, alu_absolute, fp(BIT), X)
|
||||||
|
op(0x3d, alu_absolute, fp(AND), X)
|
||||||
|
op(0x3e, alu_absolute, fp(ROL), X)
|
||||||
|
op(0x41, alu_indirect, fp(EOR), X)
|
||||||
|
op(0x42, Sbb, A, Y)
|
||||||
|
op(0x43, TMA)
|
||||||
|
op(0x45, alu_zeropage, fp(EOR))
|
||||||
|
op(0x46, alu_zeropage, fp(LSR))
|
||||||
|
op(0x48, PHb, A)
|
||||||
|
op(0x49, alu_immediate, fp(EOR))
|
||||||
|
op(0x4a, alu_implied, fp(LSR), A)
|
||||||
|
op(0x4d, alu_absolute, fp(EOR))
|
||||||
|
op(0x4e, alu_absolute, fp(LSR))
|
||||||
|
op(0x50, bra, V == 0)
|
||||||
|
op(0x51, alu_indirectY, fp(EOR))
|
||||||
|
op(0x52, alu_indirect, fp(EOR))
|
||||||
|
op(0x53, TAM)
|
||||||
|
op(0x54, CSL)
|
||||||
|
op(0x55, alu_zeropage, fp(EOR), X)
|
||||||
|
op(0x56, alu_zeropage, fp(LSR), X)
|
||||||
|
op(0x58, CLf, I)
|
||||||
|
op(0x59, alu_absolute, fp(EOR), Y)
|
||||||
|
op(0x5a, PHb, Y)
|
||||||
|
op(0x5d, alu_absolute, fp(EOR), X)
|
||||||
|
op(0x5e, alu_absolute, fp(LSR), X)
|
||||||
|
op(0x61, alu_indirect, fp(ADC), X)
|
||||||
|
op(0x62, CLb, A)
|
||||||
|
op(0x64, STb_zeropage, 0)
|
||||||
|
op(0x65, alu_zeropage, fp(ADC))
|
||||||
|
op(0x66, alu_zeropage, fp(ROR))
|
||||||
|
op(0x68, PLb, A)
|
||||||
|
op(0x69, alu_immediate, fp(ADC))
|
||||||
|
op(0x6a, alu_implied, fp(ROR), A)
|
||||||
|
op(0x6d, alu_absolute, fp(ADC))
|
||||||
|
op(0x6e, alu_absolute, fp(ROR))
|
||||||
|
op(0x70, bra, V == 1)
|
||||||
|
op(0x71, alu_indirectY, fp(ADC))
|
||||||
|
op(0x72, alu_indirect, fp(ADC))
|
||||||
|
op(0x74, STb_zeropage, 0, X)
|
||||||
|
op(0x75, alu_zeropage, fp(ADC), X)
|
||||||
|
op(0x76, alu_zeropage, fp(ROR), X)
|
||||||
|
op(0x78, SEf, I)
|
||||||
|
op(0x79, alu_absolute, fp(ADC), Y)
|
||||||
|
op(0x7a, PLb, Y)
|
||||||
|
op(0x7d, alu_absolute, fp(ADC), X)
|
||||||
|
op(0x7e, alu_absolute, fp(ROR), X)
|
||||||
|
op(0x80, bra, 1)
|
||||||
|
op(0x81, STA_indirect, X)
|
||||||
|
op(0x82, CLb, X)
|
||||||
|
op(0x84, STb_zeropage, Y)
|
||||||
|
op(0x85, STb_zeropage, A)
|
||||||
|
op(0x86, STb_zeropage, X)
|
||||||
|
op(0x88, alu_implied, fp(DEC), Y)
|
||||||
|
op(0x89, alu_immediate, fp(BIT))
|
||||||
|
op(0x8a, Tbb, X, A)
|
||||||
|
op(0x8c, STb_absolute, Y)
|
||||||
|
op(0x8d, STb_absolute, A)
|
||||||
|
op(0x8e, STb_absolute, X)
|
||||||
|
op(0x90, bra, C == 0)
|
||||||
|
op(0x91, STA_indirectY)
|
||||||
|
op(0x92, STA_indirect)
|
||||||
|
op(0x94, STb_zeropage, Y, X)
|
||||||
|
op(0x95, STb_zeropage, A, X)
|
||||||
|
op(0x96, STb_zeropage, X, Y)
|
||||||
|
op(0x98, Tbb, Y, A)
|
||||||
|
op(0x99, STb_absolute, A, Y)
|
||||||
|
op(0x9a, TXS)
|
||||||
|
op(0x9c, STb_absolute, 0)
|
||||||
|
op(0x9d, STb_absolute, A, X)
|
||||||
|
op(0x9e, STb_absolute, 0, X)
|
||||||
|
op(0xa0, LDb_immediate, Y)
|
||||||
|
op(0xa1, LDA_indirect, X)
|
||||||
|
op(0xa2, LDb_immediate, X)
|
||||||
|
op(0xa4, LDb_zeropage, Y)
|
||||||
|
op(0xa5, LDb_zeropage, A)
|
||||||
|
op(0xa6, LDb_zeropage, X)
|
||||||
|
op(0xa8, Tbb, A, Y)
|
||||||
|
op(0xa9, LDb_immediate, A)
|
||||||
|
op(0xaa, Tbb, A, X)
|
||||||
|
op(0xac, LDb_absolute, Y)
|
||||||
|
op(0xad, LDb_absolute, A)
|
||||||
|
op(0xae, LDb_absolute, X)
|
||||||
|
op(0xb0, bra, C == 1)
|
||||||
|
op(0xb1, LDA_indirectY)
|
||||||
|
op(0xb2, LDA_indirect)
|
||||||
|
op(0xb4, LDb_zeropage, Y, X)
|
||||||
|
op(0xb5, LDb_zeropage, A, X)
|
||||||
|
op(0xb6, LDb_zeropage, X, Y)
|
||||||
|
op(0xb8, CLf, V)
|
||||||
|
op(0xb9, LDb_absolute, A, Y)
|
||||||
|
op(0xba, Tbb, S, X)
|
||||||
|
op(0xbc, LDb_absolute, Y, X)
|
||||||
|
op(0xbd, LDb_absolute, A, X)
|
||||||
|
op(0xbe, LDb_absolute, X, Y)
|
||||||
|
op(0xc0, alu_immediate, fp(CPY))
|
||||||
|
op(0xc1, alu_indirect, fp(CMP), X)
|
||||||
|
op(0xc2, CLb, Y)
|
||||||
|
op(0xc5, alu_zeropage, fp(CMP))
|
||||||
|
op(0xc6, alu_zeropage, fp(DEC))
|
||||||
|
op(0xc8, alu_implied, fp(INC), Y)
|
||||||
|
op(0xc9, alu_immediate, fp(CMP))
|
||||||
|
op(0xca, alu_implied, fp(DEC), X)
|
||||||
|
op(0xcd, alu_absolute, fp(CMP))
|
||||||
|
op(0xce, alu_absolute, fp(DEC))
|
||||||
|
op(0xd0, bra, Z == 0)
|
||||||
|
op(0xd1, alu_indirectY, fp(CMP))
|
||||||
|
op(0xd2, alu_indirect, fp(CMP))
|
||||||
|
op(0xd4, CSH)
|
||||||
|
op(0xd5, alu_zeropage, fp(CMP), X)
|
||||||
|
op(0xd6, alu_zeropage, fp(DEC), X)
|
||||||
|
op(0xd8, CLf, D)
|
||||||
|
op(0xd9, alu_absolute, fp(CMP), Y)
|
||||||
|
op(0xda, PHb, X)
|
||||||
|
op(0xdd, alu_absolute, fp(CMP), X)
|
||||||
|
op(0xde, alu_absolute, fp(DEC), X)
|
||||||
|
op(0xe0, alu_immediate, fp(CPX))
|
||||||
|
op(0xe1, alu_indirect, fp(SBC), X)
|
||||||
|
op(0xe5, alu_zeropage, fp(SBC))
|
||||||
|
op(0xe6, alu_zeropage, fp(INC))
|
||||||
|
op(0xe8, alu_implied, fp(INC), X)
|
||||||
|
op(0xe9, alu_immediate, fp(SBC))
|
||||||
op(0xea, NOP)
|
op(0xea, NOP)
|
||||||
|
op(0xed, alu_absolute, fp(SBC))
|
||||||
|
op(0xee, alu_absolute, fp(INC))
|
||||||
|
op(0xf0, bra, Z == 1)
|
||||||
|
op(0xf1, alu_indirectY, fp(SBC))
|
||||||
|
op(0xf2, alu_indirect, fp(SBC))
|
||||||
|
op(0xf4, SEf, T)
|
||||||
|
op(0xf5, alu_zeropage, fp(SBC), X)
|
||||||
|
op(0xf6, alu_zeropage, fp(INC), X)
|
||||||
|
op(0xf8, SEf, D)
|
||||||
|
op(0xf9, alu_absolute, fp(SBC), Y)
|
||||||
|
op(0xfa, PLb, X)
|
||||||
|
op(0xfd, alu_absolute, fp(SBC), X)
|
||||||
|
op(0xfe, alu_absolute, fp(INC), X)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef op
|
#undef op
|
||||||
|
#undef fp
|
||||||
|
|
|
@ -1,3 +1,329 @@
|
||||||
auto HuC6280::instructionNOP() -> void {
|
auto HuC6280::ADC(uint8 i) -> uint8 {
|
||||||
|
uint9 o = A + i + C;
|
||||||
|
C = o.bit(8);
|
||||||
|
Z = uint8(o) == 0;
|
||||||
|
V = ~(A ^ i) & (A ^ o) & 0x80;
|
||||||
|
N = o.bit(7);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::AND(uint8 i) -> uint8 {
|
||||||
|
uint8 o = A & i;
|
||||||
|
Z = o == 0;
|
||||||
|
N = o.bit(7);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::ASL(uint8 i) -> uint8 {
|
||||||
|
C = i.bit(7);
|
||||||
|
i <<= 1;
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::BIT(uint8 i) -> uint8 {
|
||||||
|
Z = i == 0;
|
||||||
|
V = i.bit(6);
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::CMP(uint8 i) -> uint8 {
|
||||||
|
uint9 o = A - i;
|
||||||
|
C = o.bit(8);
|
||||||
|
Z = uint8(o) == 0;
|
||||||
|
N = o.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::CPX(uint8 i) -> uint8 {
|
||||||
|
uint9 o = X - i;
|
||||||
|
C = o.bit(8);
|
||||||
|
Z = uint8(o) == 0;
|
||||||
|
N = o.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::CPY(uint8 i) -> uint8 {
|
||||||
|
uint9 o = Y - i;
|
||||||
|
C = o.bit(8);
|
||||||
|
Z = uint8(o) == 0;
|
||||||
|
N = o.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::DEC(uint8 i) -> uint8 {
|
||||||
|
i--;
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::EOR(uint8 i) -> uint8 {
|
||||||
|
uint8 o = A ^ i;
|
||||||
|
Z = o == 0;
|
||||||
|
N = o.bit(7);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::INC(uint8 i) -> uint8 {
|
||||||
|
i++;
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::LD(uint8 i) -> uint8 {
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::LSR(uint8 i) -> uint8 {
|
||||||
|
C = i.bit(0);
|
||||||
|
i >>= 1;
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::ORA(uint8 i) -> uint8 {
|
||||||
|
uint8 o = A | i;
|
||||||
|
Z = o == 0;
|
||||||
|
N = o.bit(7);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::ROL(uint8 i) -> uint8 {
|
||||||
|
bool c = C;
|
||||||
|
C = i.bit(7);
|
||||||
|
i = i << 1 | c;
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::ROR(uint8 i) -> uint8 {
|
||||||
|
bool c = C;
|
||||||
|
C = i.bit(0);
|
||||||
|
i = c << 7 | i >> 1;
|
||||||
|
Z = i == 0;
|
||||||
|
N = i.bit(7);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::SBC(uint8 i) -> uint8 {
|
||||||
|
return ADC(~i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_absolute(fp alu, uint8 index) -> void {
|
||||||
|
uint16 absolute = operand();
|
||||||
|
absolute |= operand() << 8;
|
||||||
|
io();
|
||||||
|
L A = ALU(load(absolute + index));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_immediate(fp alu) -> void {
|
||||||
|
A = ALU(operand());
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_implied(fp alu, uint8& b) -> void {
|
||||||
|
b = ALU(b);
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_indirect(fp alu, uint8 index) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
auto absolute = load(0x2000 + zeropage + index);
|
||||||
|
absolute |= load(0x2001 + zeropage + index) << 8;
|
||||||
|
L A = ALU(load(absolute));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_indirectY(fp alu) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
auto absolute = load(0x2000 + zeropage);
|
||||||
|
absolute |= load(0x2001 + zeropage) << 8;
|
||||||
|
L A = ALU(load(absolute + Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_memory(fp alu) -> void {
|
||||||
|
auto a = A;
|
||||||
|
A = load(0x2000 + X);
|
||||||
|
instruction_alu_immediate(alu);
|
||||||
|
store(0x2000 + X, A);
|
||||||
|
A = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_alu_zeropage(fp alu, uint8 index) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
L A = ALU(load(0x2000 + zeropage + index));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_bra(bool c) -> void {
|
||||||
|
if(!c) {
|
||||||
|
L operand();
|
||||||
|
} else {
|
||||||
|
auto displacement = operand();
|
||||||
|
io();
|
||||||
|
L io();
|
||||||
|
PC = PC + (int8)displacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_CLb(uint8& b) -> void {
|
||||||
|
b = 0;
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_CLf(bool& f) -> void {
|
||||||
|
f = 0;
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_CSL() -> void {
|
||||||
|
r.cs = 12;
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_CSH() -> void {
|
||||||
|
r.cs = 3;
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_LDA_indirect(uint8 index) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
auto absolute = load(0x2000 + zeropage + index);
|
||||||
|
absolute |= load(0x2001 + zeropage + index) << 8;
|
||||||
|
L A = LD(load(absolute));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_LDA_indirectY() -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
auto absolute = load(0x2000 + zeropage);
|
||||||
|
absolute |= load(0x2001 + zeropage) << 8;
|
||||||
|
L A = LD(load(absolute + Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_LDb_absolute(uint8& b, uint8 index) -> void {
|
||||||
|
uint16 absolute = operand();
|
||||||
|
absolute |= operand() << 8;
|
||||||
|
io();
|
||||||
|
L b = LD(load(absolute + index));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_LDb_immediate(uint8& b) -> void {
|
||||||
|
b = LD(operand());
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_LDb_zeropage(uint8& b, uint8 index) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
L b = LD(load(0x2000 + zeropage + index));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_NOP() -> void {
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_PHb(uint8& b) -> void {
|
||||||
|
io();
|
||||||
|
L push(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_PHP() -> void {
|
||||||
|
io();
|
||||||
|
L push(P);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_PLb(uint8& b) -> void {
|
||||||
|
io();
|
||||||
|
io();
|
||||||
|
L b = pull();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_PLP() -> void {
|
||||||
|
io();
|
||||||
|
io();
|
||||||
|
L P = pull();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_SEf(bool& f) -> void {
|
||||||
|
f = 1;
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_STA_indirect(uint8 index) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
auto absolute = load(0x2000 + zeropage + index);
|
||||||
|
absolute |= load(0x2001 + zeropage + index) << 8;
|
||||||
|
L store(absolute, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_STA_indirectY() -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
auto absolute = load(0x2000 + zeropage);
|
||||||
|
absolute |= load(0x2001 + zeropage) << 8;
|
||||||
|
L store(absolute + Y, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_STb_absolute(uint8 b, uint8 index) -> void {
|
||||||
|
uint16 absolute = operand();
|
||||||
|
absolute |= operand() << 8;
|
||||||
|
io();
|
||||||
|
L store(absolute + index, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_STb_zeropage(uint8 b, uint8 index) -> void {
|
||||||
|
auto zeropage = operand();
|
||||||
|
io();
|
||||||
|
L store(0x2000 + zeropage + index, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_Sbb(uint8& lhs, uint8& rhs) -> void {
|
||||||
|
swap(lhs, rhs);
|
||||||
|
io();
|
||||||
|
L io();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_TAM() -> void {
|
||||||
|
auto mask = operand();
|
||||||
|
io();
|
||||||
|
io();
|
||||||
|
L io();
|
||||||
|
for(uint index : range(8)) {
|
||||||
|
if(mask.bit(index)) r.mpr[index] = A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_Tbb(uint8& source, uint8& target) -> void {
|
||||||
|
target = source;
|
||||||
|
L io();
|
||||||
|
Z = target == 0;
|
||||||
|
N = target.bit(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_TMA() -> void {
|
||||||
|
auto mask = operand();
|
||||||
|
io();
|
||||||
|
L io();
|
||||||
|
for(uint index : range(8)) {
|
||||||
|
if(mask.bit(index)) { A = r.mpr[index]; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::instruction_TXS() -> void {
|
||||||
|
S = X;
|
||||||
L io();
|
L io();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,39 @@
|
||||||
|
auto HuC6280::mmu(uint16 addr) const -> uint21 {
|
||||||
|
return r.mpr[addr.bits(13,15)] << 13 | addr.bits(0,12);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
auto HuC6280::load(uint16 addr) -> uint8 {
|
||||||
|
step(r.cs);
|
||||||
|
return read(mmu(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::store(uint16 addr, uint8 data) -> void {
|
||||||
|
step(r.cs);
|
||||||
|
return write(mmu(addr), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
auto HuC6280::io() -> uint8 {
|
auto HuC6280::io() -> uint8 {
|
||||||
return read(r.pc);
|
return load(r.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HuC6280::opcode() -> uint8 {
|
auto HuC6280::opcode() -> uint8 {
|
||||||
return read(r.pc++);
|
return load(r.pc++);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HuC6280::operand() -> uint8 {
|
auto HuC6280::operand() -> uint8 {
|
||||||
return read(r.pc++);
|
return load(r.pc++);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
auto HuC6280::push(uint8 data) -> void {
|
||||||
|
store(0x2100 + ++S, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::pull() -> uint8 {
|
||||||
|
return load(0x2100 + S--);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,6 @@ namespace Processor {
|
||||||
#include "instructions.cpp"
|
#include "instructions.cpp"
|
||||||
|
|
||||||
auto Z80::power() -> void {
|
auto Z80::power() -> void {
|
||||||
}
|
|
||||||
|
|
||||||
auto Z80::reset() -> void {
|
|
||||||
memory::fill(&r, sizeof(Registers));
|
memory::fill(&r, sizeof(Registers));
|
||||||
r.hlp = &r.hl;
|
r.hlp = &r.hl;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +19,7 @@ auto Z80::irq(bool maskable, uint16 pc, uint8 extbus) -> bool {
|
||||||
|
|
||||||
push(r.pc);
|
push(r.pc);
|
||||||
|
|
||||||
switch(r.im) {
|
switch(maskable ? r.im : (uint2)1) {
|
||||||
|
|
||||||
case 0: {
|
case 0: {
|
||||||
//external data bus ($ff = RST $38)
|
//external data bus ($ff = RST $38)
|
||||||
|
|
|
@ -16,7 +16,6 @@ struct Z80 {
|
||||||
|
|
||||||
//z80.cpp
|
//z80.cpp
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
auto irq(bool maskable, uint16 vector = 0x0000, uint8 extbus = 0xff) -> bool;
|
auto irq(bool maskable, uint16 vector = 0x0000, uint8 extbus = 0xff) -> bool;
|
||||||
auto parity(uint8) const -> bool;
|
auto parity(uint8) const -> bool;
|
||||||
|
|
|
@ -60,14 +60,6 @@ auto InputManager::appendHotkeys() -> void {
|
||||||
hotkeys.append(hotkey);
|
hotkeys.append(hotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ auto hotkey = new InputHotkey;
|
|
||||||
hotkey->name = "Soft Reset";
|
|
||||||
hotkey->press = [] {
|
|
||||||
program->softReset();
|
|
||||||
};
|
|
||||||
hotkeys.append(hotkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto& hotkey : hotkeys) {
|
for(auto& hotkey : hotkeys) {
|
||||||
hotkey->path = string{"Hotkey/", hotkey->name}.replace(" ", "");
|
hotkey->path = string{"Hotkey/", hotkey->name}.replace(" ", "");
|
||||||
hotkey->assignment = settings(hotkey->path).text();
|
hotkey->assignment = settings(hotkey->path).text();
|
||||||
|
|
|
@ -42,8 +42,7 @@ Presentation::Presentation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
systemMenu.setText("System").setVisible(false);
|
systemMenu.setText("System").setVisible(false);
|
||||||
powerSystem.setText("Power").onActivate([&] { program->powerCycle(); });
|
reloadSystem.setText("Power Cycle").onActivate([&] { program->powerCycle(); });
|
||||||
resetSystem.setText("Reset").onActivate([&] { program->softReset(); });
|
|
||||||
unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); });
|
unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); });
|
||||||
|
|
||||||
settingsMenu.setText("Settings");
|
settingsMenu.setText("Settings");
|
||||||
|
@ -171,7 +170,6 @@ Presentation::Presentation() {
|
||||||
|
|
||||||
auto Presentation::updateEmulator() -> void {
|
auto Presentation::updateEmulator() -> void {
|
||||||
if(!emulator) return;
|
if(!emulator) return;
|
||||||
resetSystem.setVisible(emulator->information.resettable);
|
|
||||||
inputPort1.setVisible(false).reset();
|
inputPort1.setVisible(false).reset();
|
||||||
inputPort2.setVisible(false).reset();
|
inputPort2.setVisible(false).reset();
|
||||||
inputPort3.setVisible(false).reset();
|
inputPort3.setVisible(false).reset();
|
||||||
|
|
|
@ -19,13 +19,11 @@ struct Presentation : Window {
|
||||||
MenuBar menuBar{this};
|
MenuBar menuBar{this};
|
||||||
Menu libraryMenu{&menuBar};
|
Menu libraryMenu{&menuBar};
|
||||||
Menu systemMenu{&menuBar};
|
Menu systemMenu{&menuBar};
|
||||||
MenuItem powerSystem{&systemMenu};
|
|
||||||
MenuItem resetSystem{&systemMenu};
|
|
||||||
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
|
||||||
Menu inputPort1{&systemMenu};
|
Menu inputPort1{&systemMenu};
|
||||||
Menu inputPort2{&systemMenu};
|
Menu inputPort2{&systemMenu};
|
||||||
Menu inputPort3{&systemMenu};
|
Menu inputPort3{&systemMenu};
|
||||||
MenuSeparator systemMenuSeparatorUnload{&systemMenu};
|
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
||||||
|
MenuItem reloadSystem{&systemMenu};
|
||||||
MenuItem unloadSystem{&systemMenu};
|
MenuItem unloadSystem{&systemMenu};
|
||||||
Menu settingsMenu{&menuBar};
|
Menu settingsMenu{&menuBar};
|
||||||
Menu videoScaleMenu{&settingsMenu};
|
Menu videoScaleMenu{&settingsMenu};
|
||||||
|
|
|
@ -21,7 +21,6 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
|
||||||
|
|
||||||
Emulator::audio.reset(2, audio->get(Audio::Frequency).get<uint>(44100));
|
Emulator::audio.reset(2, audio->get(Audio::Frequency).get<uint>(44100));
|
||||||
inputManager->bind(emulator = &interface);
|
inputManager->bind(emulator = &interface);
|
||||||
connectDevices();
|
|
||||||
if(!emulator->load(medium.id)) {
|
if(!emulator->load(medium.id)) {
|
||||||
emulator = nullptr;
|
emulator = nullptr;
|
||||||
mediumPaths.reset();
|
mediumPaths.reset();
|
||||||
|
@ -29,6 +28,7 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
|
||||||
}
|
}
|
||||||
updateAudioDriver();
|
updateAudioDriver();
|
||||||
updateAudioEffects();
|
updateAudioEffects();
|
||||||
|
connectDevices();
|
||||||
emulator->power();
|
emulator->power();
|
||||||
|
|
||||||
presentation->resizeViewport();
|
presentation->resizeViewport();
|
||||||
|
|
|
@ -27,7 +27,6 @@ struct Program : Emulator::Platform {
|
||||||
|
|
||||||
//utility.cpp
|
//utility.cpp
|
||||||
auto powerCycle() -> void;
|
auto powerCycle() -> void;
|
||||||
auto softReset() -> void;
|
|
||||||
auto connectDevices() -> void;
|
auto connectDevices() -> void;
|
||||||
auto showMessage(const string& text) -> void;
|
auto showMessage(const string& text) -> void;
|
||||||
auto updateStatusText() -> void;
|
auto updateStatusText() -> void;
|
||||||
|
|
|
@ -4,13 +4,6 @@ auto Program::powerCycle() -> void {
|
||||||
showMessage("Power cycled");
|
showMessage("Power cycled");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::softReset() -> void {
|
|
||||||
if(!emulator) return;
|
|
||||||
if(!emulator->information.resettable) return powerCycle();
|
|
||||||
emulator->reset();
|
|
||||||
showMessage("System reset");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Program::connectDevices() -> void {
|
auto Program::connectDevices() -> void {
|
||||||
if(!emulator) return;
|
if(!emulator) return;
|
||||||
for(auto& port : emulator->ports) {
|
for(auto& port : emulator->ports) {
|
||||||
|
|
|
@ -11,7 +11,6 @@ struct PCEngineCartridge {
|
||||||
PCEngineCartridge::PCEngineCartridge(string location, uint8_t* data, uint size) {
|
PCEngineCartridge::PCEngineCartridge(string location, uint8_t* data, uint size) {
|
||||||
manifest.append("board\n");
|
manifest.append("board\n");
|
||||||
manifest.append(" rom name=program.rom size=0x", hex(size), "\n");
|
manifest.append(" rom name=program.rom size=0x", hex(size), "\n");
|
||||||
manifest.append(" ram name=save.ram size=0x8000\n");
|
|
||||||
manifest.append("\n");
|
manifest.append("\n");
|
||||||
manifest.append("information\n");
|
manifest.append("information\n");
|
||||||
manifest.append(" title: ", Location::prefix(location), "\n");
|
manifest.append(" title: ", Location::prefix(location), "\n");
|
||||||
|
|
Loading…
Reference in New Issue