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 {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -20,10 +20,6 @@ auto APU::step(uint clocks) -> void {
|
|||
auto APU::power() -> void {
|
||||
Z80::bus = &busAPU;
|
||||
Z80::power();
|
||||
}
|
||||
|
||||
auto APU::reset() -> void {
|
||||
Z80::reset();
|
||||
create(APU::Enter, system.colorburst());
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ struct APU : Processor::Z80, Thread {
|
|||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
};
|
||||
|
||||
extern APU apu;
|
||||
|
|
|
@ -55,7 +55,7 @@ auto System::reset() -> void {
|
|||
scheduler.reset();
|
||||
cartridge.reset();
|
||||
cpu.reset();
|
||||
apu.reset();
|
||||
apu.power();
|
||||
vdp.reset();
|
||||
psg.reset();
|
||||
ym2612.reset();
|
||||
|
|
|
@ -20,8 +20,8 @@ auto Bus::in(uint8 addr) -> uint8 {
|
|||
|
||||
case 0: {
|
||||
if(system.model() == Model::GameGear) {
|
||||
auto hardware = peripherals.hardware->readData();
|
||||
return hardware.bit(6) << 7 | 0x7f;
|
||||
bool start = !platform->inputPoll(ID::Port::Hardware, ID::Device::GameGearControls, 6);
|
||||
return start << 7 | 0x7f;
|
||||
}
|
||||
|
||||
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
||||
|
@ -37,19 +37,26 @@ auto Bus::in(uint8 addr) -> uint8 {
|
|||
|
||||
case 3: {
|
||||
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 port2 = peripherals.controllerPort2->readData();
|
||||
if(addr.bit(0) == 0) {
|
||||
return port1.bits(0,5) << 0 | port2.bits(0,1) << 6;
|
||||
} 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) {
|
||||
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) {
|
||||
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 {
|
||||
return 0xff;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace MasterSystem {
|
||||
|
||||
#include "mastersystem/mastersystem.cpp"
|
||||
#include "gamegear/gamegear.cpp"
|
||||
#include "gamepad/gamepad.cpp"
|
||||
|
||||
Controller::Controller(uint port) : port(port) {
|
||||
|
@ -16,7 +14,6 @@ Controller::~Controller() {
|
|||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
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.controllerPort2) if(device->active()) device->main();
|
||||
}
|
||||
|
|
|
@ -5,11 +5,9 @@ struct Controller : Thread {
|
|||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
virtual auto readData() -> uint8 { return 0xff; }
|
||||
virtual auto readData() -> uint7 { return 0x7f; }
|
||||
|
||||
const uint port;
|
||||
};
|
||||
|
||||
#include "mastersystem/mastersystem.hpp"
|
||||
#include "gamegear/gamegear.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) {
|
||||
}
|
||||
|
||||
auto Gamepad::readData() -> uint8 {
|
||||
uint8 data = 0xff;
|
||||
auto Gamepad::readData() -> uint7 {
|
||||
uint7 data = 0x7f;
|
||||
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
|
|
|
@ -5,5 +5,5 @@ struct Gamepad : Controller {
|
|||
|
||||
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 {
|
||||
//note: SMS1 extbus value is random; SMS2+ is pulled high ($ff)
|
||||
|
||||
if(state.nmiLine) {
|
||||
state.nmiLine = 0; //edge-sensitive
|
||||
irq(0, 0x0066, 0xff);
|
||||
|
@ -31,6 +29,16 @@ auto CPU::step(uint clocks) -> void {
|
|||
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 {
|
||||
state.nmiLine = value;
|
||||
}
|
||||
|
@ -44,6 +52,8 @@ auto CPU::power() -> void {
|
|||
Z80::power();
|
||||
create(CPU::Enter, system.colorburst());
|
||||
|
||||
r.pc = 0x0000; //reset vector address
|
||||
|
||||
memory::fill(&state, sizeof(State));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ struct CPU : Processor::Z80, Thread {
|
|||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto pollPause() -> void;
|
||||
auto setNMI(bool value) -> void;
|
||||
auto setINT(bool value) -> void;
|
||||
|
||||
|
|
|
@ -88,7 +88,6 @@ struct GameGearInterface : Emulator::Interface {
|
|||
};
|
||||
|
||||
struct Settings {
|
||||
uint hardware = 0;
|
||||
uint controllerPort1 = 0;
|
||||
uint controllerPort2 = 0;
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ MasterSystemInterface::MasterSystemInterface() {
|
|||
|
||||
{ Device device{ID::Device::MasterSystemControls, "Controls"};
|
||||
device.inputs.append({0, "Reset"});
|
||||
device.inputs.append({0, "Pause"});
|
||||
hardware.devices.append(device);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
Peripherals peripherals;
|
||||
|
||||
auto Peripherals::unload() -> void {
|
||||
delete hardware;
|
||||
delete controllerPort1;
|
||||
delete controllerPort2;
|
||||
hardware = nullptr;
|
||||
controllerPort1 = nullptr;
|
||||
controllerPort2 = nullptr;
|
||||
}
|
||||
|
||||
auto Peripherals::reset() -> void {
|
||||
connect(ID::Port::Hardware, settings.hardware);
|
||||
connect(ID::Port::Controller1, settings.controllerPort1);
|
||||
connect(ID::Port::Controller2, settings.controllerPort2);
|
||||
}
|
||||
|
@ -19,14 +16,6 @@ auto Peripherals::connect(uint port, uint device) -> void {
|
|||
cpu.peripherals.reset();
|
||||
|
||||
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) {
|
||||
settings.controllerPort1 = device;
|
||||
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(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;
|
||||
|
||||
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 {
|
||||
|
|
|
@ -27,7 +27,6 @@ struct Peripherals {
|
|||
auto reset() -> void;
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
||||
Controller* hardware = nullptr;
|
||||
Controller* controllerPort1 = nullptr;
|
||||
Controller* controllerPort2 = nullptr;
|
||||
};
|
||||
|
|
|
@ -30,6 +30,8 @@ auto VDP::main() -> void {
|
|||
|
||||
//684 clocks/scanline
|
||||
uint y = io.vcounter;
|
||||
if(y < vlines()) {
|
||||
uint32* screen = buffer + (24 + y) * 256;
|
||||
for(uint x : range(256)) {
|
||||
background.run();
|
||||
sprite.run();
|
||||
|
@ -42,8 +44,12 @@ auto VDP::main() -> void {
|
|||
color = palette(16 | sprite.output.color);
|
||||
}
|
||||
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
||||
if(!io.displayEnable || y >= vlines()) color = 0;
|
||||
buffer[io.vcounter * 256 + x] = color;
|
||||
if(!io.displayEnable) color = 0;
|
||||
*screen++ = color;
|
||||
}
|
||||
} else {
|
||||
//Vblank
|
||||
step(512);
|
||||
}
|
||||
step(172);
|
||||
|
||||
|
@ -67,11 +73,16 @@ auto VDP::step(uint clocks) -> void {
|
|||
|
||||
auto VDP::refresh() -> void {
|
||||
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) {
|
||||
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 {
|
||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||
|
||||
memory::fill(&buffer, sizeof(buffer));
|
||||
memory::fill(&io, sizeof(IO));
|
||||
|
||||
background.power();
|
||||
|
|
|
@ -68,7 +68,7 @@ struct VDP : Thread {
|
|||
private:
|
||||
auto palette(uint5 index) -> uint12;
|
||||
|
||||
uint32 buffer[256 * 262];
|
||||
uint32 buffer[256 * 264];
|
||||
uint8 vram[0x4000];
|
||||
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;
|
||||
}
|
||||
|
||||
auto Cartridge::save() -> void {
|
||||
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 {
|
||||
delete[] rom.data;
|
||||
delete[] ram.data;
|
||||
rom = {};
|
||||
ram = {};
|
||||
}
|
||||
|
||||
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 mask = 1 << 23;
|
||||
uint mask = 1 << 20;
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
|
@ -80,14 +68,4 @@ auto Cartridge::Memory::mirror(uint addr, uint size) -> uint {
|
|||
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 read(uint20 addr) -> uint8;
|
||||
auto write(uint20 addr, uint8 data) -> void;
|
||||
|
||||
private:
|
||||
auto mirror(uint addr, uint size) -> uint;
|
||||
|
||||
struct Information {
|
||||
uint pathID = 0;
|
||||
string sha256;
|
||||
|
@ -21,14 +26,9 @@ private:
|
|||
struct Memory {
|
||||
uint8* data = nullptr;
|
||||
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 ram;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
|
|
@ -11,7 +11,7 @@ auto CPU::Enter() -> void {
|
|||
auto CPU::main() -> void {
|
||||
#if 1
|
||||
static uint counter = 0;
|
||||
if(++counter < 10) {
|
||||
if(counter++ < 40) {
|
||||
print(disassemble(r.pc), "\n");
|
||||
}
|
||||
#endif
|
||||
|
@ -29,22 +29,29 @@ auto CPU::step(uint clocks) -> void {
|
|||
auto CPU::power() -> void {
|
||||
HuC6280::power();
|
||||
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 {
|
||||
step(3);
|
||||
return 0xea;
|
||||
auto CPU::read(uint21 addr) -> uint8 {
|
||||
if(!addr.bit(20)) return cartridge.read(addr);
|
||||
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 {
|
||||
step(3);
|
||||
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::lastCycle() -> void {
|
||||
}
|
||||
|
||||
auto CPU::disassembleRead(uint16 pc) -> uint8 {
|
||||
return 0xea;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@ struct CPU : Processor::HuC6280, Thread {
|
|||
|
||||
auto power() -> void;
|
||||
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
auto read(uint21 addr) -> uint8 override;
|
||||
auto write(uint21 addr, uint8 data) -> void override;
|
||||
auto lastCycle() -> void override;
|
||||
|
||||
auto disassembleRead(uint16 addr) -> uint8 override;
|
||||
|
||||
vector<Thread*> peripherals;
|
||||
|
||||
private:
|
||||
uint8 ram[0x2000];
|
||||
};
|
||||
|
||||
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 {
|
||||
static auto Enter() -> void;
|
||||
|
|
|
@ -1,12 +1,218 @@
|
|||
auto HuC6280::disassemble(uint16 pc) -> string {
|
||||
string s{hex(r.pc, 4L), " "};
|
||||
uint8 opcode = disassembleRead(pc++);
|
||||
auto HuC6280::disassemble(uint16 pc_) -> string {
|
||||
uint21 pc = mmu(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;
|
||||
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), ")"};
|
||||
s.append(pad(o, -16L, ' '));
|
||||
#undef op
|
||||
|
@ -15,6 +221,7 @@ auto HuC6280::disassemble(uint16 pc) -> string {
|
|||
s.append(" X:", hex(r.x, 2L));
|
||||
s.append(" Y:", hex(r.y, 2L));
|
||||
s.append(" S:", hex(r.s, 2L));
|
||||
s.append(" PC:", hex(pc_, 4L));
|
||||
s.append(" ");
|
||||
s.append(r.p.n ? "N" : "n");
|
||||
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.z ? "Z" : "z");
|
||||
s.append(r.p.c ? "C" : "c");
|
||||
s.append(r.cs == 3 ? "+" : "-");
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -3,21 +3,66 @@
|
|||
|
||||
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 ALU (this->*alu)
|
||||
#include "memory.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.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 ALU
|
||||
|
||||
auto HuC6280::power() -> void {
|
||||
r.a = 0x00;
|
||||
r.x = 0x00;
|
||||
r.y = 0x00;
|
||||
r.s = 0x00;
|
||||
r.s = 0xff;
|
||||
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.p = 0x04;
|
||||
r.cs = 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//Hudson Soft HuC6280A
|
||||
//Hudson Soft HuC6280
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -6,45 +6,107 @@ namespace Processor {
|
|||
|
||||
struct HuC6280 {
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto read(uint21 addr) -> uint8 = 0;
|
||||
virtual auto write(uint21 addr, uint8 data) -> void = 0;
|
||||
virtual auto lastCycle() -> void = 0;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
//memory.cpp
|
||||
inline auto mmu(uint16) const -> uint21;
|
||||
inline auto load(uint16) -> uint8;
|
||||
inline auto store(uint16, uint8) -> void;
|
||||
|
||||
auto io() -> uint8;
|
||||
auto opcode() -> uint8;
|
||||
auto operand() -> uint8;
|
||||
|
||||
auto push(uint8) -> void;
|
||||
auto pull() -> uint8;
|
||||
|
||||
//instruction.cpp
|
||||
auto instruction() -> void;
|
||||
|
||||
//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
|
||||
virtual auto disassembleRead(uint16 pc) -> uint8 = 0;
|
||||
auto disassemble(uint16 pc) -> string;
|
||||
|
||||
struct Flags {
|
||||
union {
|
||||
uint8_t data = 0;
|
||||
BooleanBitField<uint8_t, 0> c; //carry
|
||||
BooleanBitField<uint8_t, 1> z; //zero
|
||||
BooleanBitField<uint8_t, 2> i; //interrupt
|
||||
BooleanBitField<uint8_t, 3> d; //decimal
|
||||
BooleanBitField<uint8_t, 4> b; //break
|
||||
BooleanBitField<uint8_t, 5> t; //...
|
||||
BooleanBitField<uint8_t, 6> v; //overflow
|
||||
BooleanBitField<uint8_t, 7> n; //negative
|
||||
};
|
||||
bool c; //carry
|
||||
bool z; //zero
|
||||
bool i; //interrupt disable
|
||||
bool d; //decimal mode
|
||||
bool b; //break
|
||||
bool t; //memory operation
|
||||
bool v; //overflow
|
||||
bool n; //negative
|
||||
|
||||
inline operator uint() const { return data; }
|
||||
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^=(uint value) { return data ^= value, *this; }
|
||||
inline operator uint8() const {
|
||||
return c << 0 | z << 1 | i << 2 | d << 3 | b << 4 | t << 5 | v << 6 | n << 7;
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -53,8 +115,10 @@ struct HuC6280 {
|
|||
uint8 y;
|
||||
uint8 s;
|
||||
uint16 pc;
|
||||
Flags p;
|
||||
uint8 mpr[8];
|
||||
uint8 mdr;
|
||||
Flags p;
|
||||
uint8 cs; //code speed (3 = fast, 12 = slow)
|
||||
} 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 {
|
||||
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(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 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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
return read(r.pc);
|
||||
return load(r.pc);
|
||||
}
|
||||
|
||||
auto HuC6280::opcode() -> uint8 {
|
||||
return read(r.pc++);
|
||||
return load(r.pc++);
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
auto Z80::power() -> void {
|
||||
}
|
||||
|
||||
auto Z80::reset() -> void {
|
||||
memory::fill(&r, sizeof(Registers));
|
||||
r.hlp = &r.hl;
|
||||
}
|
||||
|
@ -22,7 +19,7 @@ auto Z80::irq(bool maskable, uint16 pc, uint8 extbus) -> bool {
|
|||
|
||||
push(r.pc);
|
||||
|
||||
switch(r.im) {
|
||||
switch(maskable ? r.im : (uint2)1) {
|
||||
|
||||
case 0: {
|
||||
//external data bus ($ff = RST $38)
|
||||
|
|
|
@ -16,7 +16,6 @@ struct Z80 {
|
|||
|
||||
//z80.cpp
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto irq(bool maskable, uint16 vector = 0x0000, uint8 extbus = 0xff) -> bool;
|
||||
auto parity(uint8) const -> bool;
|
||||
|
|
|
@ -60,14 +60,6 @@ auto InputManager::appendHotkeys() -> void {
|
|||
hotkeys.append(hotkey);
|
||||
}
|
||||
|
||||
{ auto hotkey = new InputHotkey;
|
||||
hotkey->name = "Soft Reset";
|
||||
hotkey->press = [] {
|
||||
program->softReset();
|
||||
};
|
||||
hotkeys.append(hotkey);
|
||||
}
|
||||
|
||||
for(auto& hotkey : hotkeys) {
|
||||
hotkey->path = string{"Hotkey/", hotkey->name}.replace(" ", "");
|
||||
hotkey->assignment = settings(hotkey->path).text();
|
||||
|
|
|
@ -42,8 +42,7 @@ Presentation::Presentation() {
|
|||
}
|
||||
|
||||
systemMenu.setText("System").setVisible(false);
|
||||
powerSystem.setText("Power").onActivate([&] { program->powerCycle(); });
|
||||
resetSystem.setText("Reset").onActivate([&] { program->softReset(); });
|
||||
reloadSystem.setText("Power Cycle").onActivate([&] { program->powerCycle(); });
|
||||
unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); });
|
||||
|
||||
settingsMenu.setText("Settings");
|
||||
|
@ -171,7 +170,6 @@ Presentation::Presentation() {
|
|||
|
||||
auto Presentation::updateEmulator() -> void {
|
||||
if(!emulator) return;
|
||||
resetSystem.setVisible(emulator->information.resettable);
|
||||
inputPort1.setVisible(false).reset();
|
||||
inputPort2.setVisible(false).reset();
|
||||
inputPort3.setVisible(false).reset();
|
||||
|
|
|
@ -19,13 +19,11 @@ struct Presentation : Window {
|
|||
MenuBar menuBar{this};
|
||||
Menu libraryMenu{&menuBar};
|
||||
Menu systemMenu{&menuBar};
|
||||
MenuItem powerSystem{&systemMenu};
|
||||
MenuItem resetSystem{&systemMenu};
|
||||
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
||||
Menu inputPort1{&systemMenu};
|
||||
Menu inputPort2{&systemMenu};
|
||||
Menu inputPort3{&systemMenu};
|
||||
MenuSeparator systemMenuSeparatorUnload{&systemMenu};
|
||||
MenuSeparator systemMenuSeparatorPorts{&systemMenu};
|
||||
MenuItem reloadSystem{&systemMenu};
|
||||
MenuItem unloadSystem{&systemMenu};
|
||||
Menu settingsMenu{&menuBar};
|
||||
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));
|
||||
inputManager->bind(emulator = &interface);
|
||||
connectDevices();
|
||||
if(!emulator->load(medium.id)) {
|
||||
emulator = nullptr;
|
||||
mediumPaths.reset();
|
||||
|
@ -29,6 +28,7 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
|
|||
}
|
||||
updateAudioDriver();
|
||||
updateAudioEffects();
|
||||
connectDevices();
|
||||
emulator->power();
|
||||
|
||||
presentation->resizeViewport();
|
||||
|
|
|
@ -27,7 +27,6 @@ struct Program : Emulator::Platform {
|
|||
|
||||
//utility.cpp
|
||||
auto powerCycle() -> void;
|
||||
auto softReset() -> void;
|
||||
auto connectDevices() -> void;
|
||||
auto showMessage(const string& text) -> void;
|
||||
auto updateStatusText() -> void;
|
||||
|
|
|
@ -4,13 +4,6 @@ auto Program::powerCycle() -> void {
|
|||
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 {
|
||||
if(!emulator) return;
|
||||
for(auto& port : emulator->ports) {
|
||||
|
|
|
@ -11,7 +11,6 @@ struct PCEngineCartridge {
|
|||
PCEngineCartridge::PCEngineCartridge(string location, uint8_t* data, uint size) {
|
||||
manifest.append("board\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("information\n");
|
||||
manifest.append(" title: ", Location::prefix(location), "\n");
|
||||
|
|
Loading…
Reference in New Issue