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:
Tim Allen 2017-01-14 10:59:38 +11:00
parent 21ee597aae
commit 26bd7590ad
42 changed files with 1002 additions and 224 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "101.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/";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +0,0 @@
struct GameGearControls : Controller {
enum : uint {
Up, Down, Left, Right, One, Two, Start,
};
GameGearControls(uint port);
auto readData() -> uint8 override;
};

View File

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

View File

@ -5,5 +5,5 @@ struct Gamepad : Controller {
Gamepad(uint port); Gamepad(uint port);
auto readData() -> uint8 override; auto readData() -> uint7 override;
}; };

View File

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

View File

@ -1,9 +0,0 @@
struct MasterSystemControls : Controller {
enum : uint {
Reset,
};
MasterSystemControls(uint port);
auto readData() -> uint8 override;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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