Update to v103r05 release.

byuu says:

Changelog:

  - fc/controller: added ControllerPort class; removed Peripherals class
  - md/controller/gamepad: removed X,Y,Z buttons since this isn't a
    6-button controller
  - ms/controller: added ControllerPort class (not used in Game Gear
    mode); removed Peripherals class
  - pce/controller: added ControllerPort class; removed Peripherals
    class
  - processor/spc700: idle(address) is part of SMP class again, contains
    flag to detect mov (x)+ edge case
  - sfc/controller/super-scope,justifier: use CPU frequency instead of
    hard-coding NTSC frequency
  - sfc/cpu: move 4x8-bit SMP ports to SMP class
  - sfc/smp: move APU RAM to DSP class
  - sfc/smp: improved emulation of TEST registers bits 4-7 [information
    from nocash]
      - d4,d5 is RAM wait states (1,2,5,10)
      - d6,d7 is ROM/IO wait states (1,2,5,10)
  - sfc/smp: code cleanup to new style (order from lowest to highest
    bits; use .bit(s) functions)
  - sfc/smp: $00f8,$00f9 are P4/P5 auxiliary ports; named the registers
    better
This commit is contained in:
Tim Allen 2017-07-01 16:15:27 +10:00
parent ff3750de4f
commit 40802b0b9f
62 changed files with 403 additions and 375 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 = "103.04"; static const string Version = "103.05";
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

@ -2,9 +2,11 @@
namespace Famicom { namespace Famicom {
ControllerPort controllerPort1;
ControllerPort controllerPort2;
#include "gamepad/gamepad.cpp" #include "gamepad/gamepad.cpp"
Controller::Controller(bool port) : port(port) { Controller::Controller(uint port) : port(port) {
if(!handle()) create(Controller::Enter, 1); if(!handle()) create(Controller::Enter, 1);
} }
@ -15,8 +17,8 @@ Controller::~Controller() {
auto Controller::Enter() -> void { auto Controller::Enter() -> void {
while(true) { while(true) {
scheduler.synchronize(); scheduler.synchronize();
if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main(); if(controllerPort1.device->active()) controllerPort1.device->main();
if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main(); if(controllerPort2.device->active()) controllerPort2.device->main();
} }
} }
@ -25,4 +27,32 @@ auto Controller::main() -> void {
synchronize(cpu); synchronize(cpu);
} }
//
auto ControllerPort::connect(uint deviceID) -> void {
if(!system.loaded()) return;
delete device;
switch(deviceID) { default:
case ID::Device::None: device = new Controller(port); break;
case ID::Device::Gamepad: device = new Gamepad(port); break;
}
cpu.peripherals.reset();
if(auto device = controllerPort1.device) cpu.peripherals.append(device);
if(auto device = controllerPort2.device) cpu.peripherals.append(device);
}
auto ControllerPort::power(uint port) -> void {
this->port = port;
}
auto ControllerPort::unload() -> void {
delete device;
device = nullptr;
}
auto ControllerPort::serialize(serializer& s) -> void {
}
} }

View File

@ -17,9 +17,7 @@
// 7: gnd // 7: gnd
struct Controller : Thread { struct Controller : Thread {
enum : bool { Port1 = 0, Port2 = 1 }; Controller(uint port);
Controller(bool port);
virtual ~Controller(); virtual ~Controller();
static auto Enter() -> void; static auto Enter() -> void;
@ -27,7 +25,21 @@ struct Controller : Thread {
virtual auto data() -> uint3 { return 0; } virtual auto data() -> uint3 { return 0; }
virtual auto latch(bool data) -> void {} virtual auto latch(bool data) -> void {}
const bool port; const uint port;
}; };
struct ControllerPort {
auto connect(uint deviceID) -> void;
auto power(uint port) -> void;
auto unload() -> void;
auto serialize(serializer&) -> void;
uint port;
Controller* device = nullptr;
};
extern ControllerPort controllerPort1;
extern ControllerPort controllerPort2;
#include "gamepad/gamepad.hpp" #include "gamepad/gamepad.hpp"

View File

@ -1,4 +1,4 @@
Gamepad::Gamepad(bool port) : Controller(port) { Gamepad::Gamepad(uint port) : Controller(port) {
} }
auto Gamepad::data() -> uint3 { auto Gamepad::data() -> uint3 {

View File

@ -3,7 +3,7 @@ struct Gamepad : Controller {
Up, Down, Left, Right, B, A, Select, Start, Up, Down, Left, Right, B, A, Select, Start,
}; };
Gamepad(bool port); Gamepad(uint port);
auto data() -> uint3; auto data() -> uint3;
auto latch(bool data) -> void; auto latch(bool data) -> void;

View File

@ -10,12 +10,12 @@ auto CPU::readIO(uint16 addr) -> uint8 {
switch(addr) { switch(addr) {
case 0x4016: { case 0x4016: {
auto data = Famicom::peripherals.controllerPort1->data(); auto data = controllerPort1.device->data();
return (mdr() & 0xc0) | data.bit(2) << 4 | data.bit(1) << 3 | data.bit(0) << 0; return (mdr() & 0xc0) | data.bit(2) << 4 | data.bit(1) << 3 | data.bit(0) << 0;
} }
case 0x4017: { case 0x4017: {
auto data = Famicom::peripherals.controllerPort2->data(); auto data = controllerPort2.device->data();
return (mdr() & 0xc0) | data.bit(2) << 4 | data.bit(1) << 3 | data.bit(0) << 0; return (mdr() & 0xc0) | data.bit(2) << 4 | data.bit(1) << 3 | data.bit(0) << 0;
} }
@ -34,8 +34,8 @@ auto CPU::writeIO(uint16 addr, uint8 data) -> void {
} }
case 0x4016: { case 0x4016: {
Famicom::peripherals.controllerPort1->latch(data.bit(0)); controllerPort1.device->latch(data.bit(0));
Famicom::peripherals.controllerPort2->latch(data.bit(0)); controllerPort2.device->latch(data.bit(0));
return; return;
} }

View File

@ -132,7 +132,8 @@ auto Interface::unload() -> void {
} }
auto Interface::connect(uint port, uint device) -> void { auto Interface::connect(uint port, uint device) -> void {
peripherals.connect(port, device); if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);
} }
auto Interface::power() -> void { auto Interface::power() -> void {

View File

@ -1,46 +0,0 @@
Peripherals peripherals;
auto Peripherals::unload() -> void {
delete controllerPort1;
delete controllerPort2;
controllerPort1 = nullptr;
controllerPort2 = nullptr;
}
auto Peripherals::reset() -> void {
connect(ID::Port::Controller1, settings.controllerPort1);
connect(ID::Port::Controller2, settings.controllerPort2);
}
auto Peripherals::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller1) {
settings.controllerPort1 = device;
if(!system.loaded()) return;
delete controllerPort1;
switch(device) { default:
case ID::Device::None: controllerPort1 = new Controller(0); break;
case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
}
}
if(port == ID::Port::Controller2) {
settings.controllerPort2 = device;
if(!system.loaded()) return;
delete controllerPort2;
switch(device) { default:
case ID::Device::None: controllerPort2 = new Controller(1); break;
case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
}
}
if(port == ID::Port::Expansion) {
settings.expansionPort = device;
if(!system.loaded()) return;
}
cpu.peripherals.reset();
cpu.peripherals.append(controllerPort1);
cpu.peripherals.append(controllerPort2);
}

View File

@ -45,6 +45,8 @@ auto System::serializeAll(serializer& s) -> void {
cpu.serialize(s); cpu.serialize(s);
apu.serialize(s); apu.serialize(s);
ppu.serialize(s); ppu.serialize(s);
controllerPort1.serialize(s);
controllerPort2.serialize(s);
} }
auto System::serializeInit() -> void { auto System::serializeInit() -> void {

View File

@ -2,7 +2,6 @@
namespace Famicom { namespace Famicom {
#include "peripherals.cpp"
#include "video.cpp" #include "video.cpp"
#include "serialization.cpp" #include "serialization.cpp"
System system; System system;
@ -56,7 +55,9 @@ auto System::save() -> void {
auto System::unload() -> void { auto System::unload() -> void {
if(!loaded()) return; if(!loaded()) return;
peripherals.unload(); cpu.peripherals.reset();
controllerPort1.unload();
controllerPort2.unload();
cartridge.unload(); cartridge.unload();
information.loaded = false; information.loaded = false;
} }
@ -76,7 +77,12 @@ auto System::power() -> void {
apu.power(); apu.power();
ppu.power(); ppu.power();
scheduler.primary(cpu); scheduler.primary(cpu);
peripherals.reset();
controllerPort1.power(ID::Port::Controller1);
controllerPort2.power(ID::Port::Controller2);
controllerPort1.connect(settings.controllerPort1);
controllerPort2.connect(settings.controllerPort2);
} }
auto System::init() -> void { auto System::init() -> void {

View File

@ -41,17 +41,7 @@ private:
uint _serializeSize = 0; uint _serializeSize = 0;
}; };
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
auto connect(uint port, uint device) -> void;
Controller* controllerPort1 = nullptr;
Controller* controllerPort2 = nullptr;
};
extern System system; extern System system;
extern Peripherals peripherals;
auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; } auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; }
auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; } auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; }

View File

@ -1,6 +1,6 @@
struct Gamepad : Controller { struct Gamepad : Controller {
enum : uint { enum : uint {
Up, Down, Left, Right, A, B, C, X, Y, Z, Start, Up, Down, Left, Right, A, B, C, Start,
}; };
Gamepad(uint port); Gamepad(uint port);

View File

@ -34,9 +34,6 @@ Interface::Interface() {
device.inputs.append({0, "A" }); device.inputs.append({0, "A" });
device.inputs.append({0, "B" }); device.inputs.append({0, "B" });
device.inputs.append({0, "C" }); device.inputs.append({0, "C" });
device.inputs.append({0, "X" });
device.inputs.append({0, "Y" });
device.inputs.append({0, "Z" });
device.inputs.append({0, "Start"}); device.inputs.append({0, "Start"});
controllerPort1.devices.append(device); controllerPort1.devices.append(device);
controllerPort2.devices.append(device); controllerPort2.devices.append(device);

View File

@ -45,8 +45,8 @@ auto Bus::in(uint8 addr) -> uint8 {
case 3: { case 3: {
if(Model::MasterSystem()) { if(Model::MasterSystem()) {
bool reset = !platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 0); bool reset = !platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 0);
auto port1 = peripherals.controllerPort1->readData(); auto port1 = controllerPort1.device->readData();
auto port2 = peripherals.controllerPort2->readData(); auto port2 = controllerPort2.device->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 {

View File

@ -2,6 +2,8 @@
namespace MasterSystem { namespace MasterSystem {
ControllerPort controllerPort1;
ControllerPort controllerPort2;
#include "gamepad/gamepad.cpp" #include "gamepad/gamepad.cpp"
Controller::Controller(uint port) : port(port) { Controller::Controller(uint port) : port(port) {
@ -15,8 +17,8 @@ Controller::~Controller() {
auto Controller::Enter() -> void { auto Controller::Enter() -> void {
while(true) { while(true) {
scheduler.synchronize(); scheduler.synchronize();
if(auto device = peripherals.controllerPort1) if(device->active()) device->main(); if(controllerPort1.device->active()) controllerPort1.device->main();
if(auto device = peripherals.controllerPort2) if(device->active()) device->main(); if(controllerPort2.device->active()) controllerPort2.device->main();
} }
} }
@ -25,4 +27,33 @@ auto Controller::main() -> void {
synchronize(cpu); synchronize(cpu);
} }
//
auto ControllerPort::connect(uint deviceID) -> void {
delete device;
if(!system.loaded()) return;
if(!Model::MasterSystem()) return;
switch(deviceID) { default:
case ID::Device::None: device = new Controller(port); break;
case ID::Device::Gamepad: device = new Gamepad(port); break;
}
cpu.peripherals.reset();
if(auto device = controllerPort1.device) cpu.peripherals.append(device);
if(auto device = controllerPort2.device) cpu.peripherals.append(device);
}
auto ControllerPort::power(uint port) -> void {
this->port = port;
}
auto ControllerPort::unload() -> void {
delete device;
device = nullptr;
}
auto ControllerPort::serialize(serializer& s) -> void {
}
} }

View File

@ -10,4 +10,18 @@ struct Controller : Thread {
const uint port; const uint port;
}; };
struct ControllerPort {
auto connect(uint deviceID) -> void;
auto power(uint port) -> void;
auto unload() -> void;
auto serialize(serializer&) -> void;
uint port;
Controller* device = nullptr;
};
extern ControllerPort controllerPort1;
extern ControllerPort controllerPort2;
#include "gamepad/gamepad.hpp" #include "gamepad/gamepad.hpp"

View File

@ -30,10 +30,6 @@ auto Interface::unload() -> void {
system.unload(); system.unload();
} }
auto Interface::connect(uint port, uint device) -> void {
peripherals.connect(port, device);
}
auto Interface::power() -> void { auto Interface::power() -> void {
system.power(); system.power();
} }

View File

@ -31,7 +31,7 @@ struct Interface : Emulator::Interface {
auto save() -> void override; auto save() -> void override;
auto unload() -> void override; auto unload() -> void override;
auto connect(uint port, uint device) -> void override; auto connect(uint port, uint device) -> void override {}
auto power() -> void override; auto power() -> void override;
auto run() -> void override; auto run() -> void override;
@ -56,6 +56,8 @@ struct MasterSystemInterface : Interface {
auto videoColor(uint32 color) -> uint64 override; auto videoColor(uint32 color) -> uint64 override;
auto load(uint id) -> bool override; auto load(uint id) -> bool override;
auto connect(uint port, uint device) -> void override;
}; };
struct GameGearInterface : Interface { struct GameGearInterface : Interface {

View File

@ -68,3 +68,8 @@ auto MasterSystemInterface::load(uint id) -> bool {
if(id == ID::MasterSystem) return system.load(this, System::Model::MasterSystem); if(id == ID::MasterSystem) return system.load(this, System::Model::MasterSystem);
return false; return false;
} }
auto MasterSystemInterface::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);
}

View File

@ -1,44 +0,0 @@
Peripherals peripherals;
auto Peripherals::unload() -> void {
delete controllerPort1;
delete controllerPort2;
controllerPort1 = nullptr;
controllerPort2 = nullptr;
}
auto Peripherals::reset() -> void {
connect(ID::Port::Controller1, settings.controllerPort1);
connect(ID::Port::Controller2, settings.controllerPort2);
}
auto Peripherals::connect(uint port, uint device) -> void {
cpu.peripherals.reset();
if(Model::MasterSystem()) {
if(port == ID::Port::Controller1) {
settings.controllerPort1 = device;
if(!system.loaded()) return;
delete controllerPort1;
switch(device) { default:
case ID::Device::None: controllerPort1 = new Controller(ID::Port::Controller1); break;
case ID::Device::Gamepad: controllerPort1 = new Gamepad(ID::Port::Controller1); break;
}
}
if(port == ID::Port::Controller2) {
settings.controllerPort2 = device;
if(!system.loaded()) return;
delete controllerPort2;
switch(device) { default:
case ID::Device::None: controllerPort2 = new Controller(ID::Port::Controller2); break;
case ID::Device::Gamepad: controllerPort2 = new Gamepad(ID::Port::Controller2); break;
}
}
cpu.peripherals.append(controllerPort1);
cpu.peripherals.append(controllerPort2);
}
}

View File

@ -60,6 +60,8 @@ auto System::serializeAll(serializer& s) -> void {
cpu.serialize(s); cpu.serialize(s);
vdp.serialize(s); vdp.serialize(s);
psg.serialize(s); psg.serialize(s);
controllerPort1.serialize(s);
controllerPort2.serialize(s);
} }
auto System::serialize(serializer& s) -> void { auto System::serialize(serializer& s) -> void {

View File

@ -5,7 +5,6 @@ namespace MasterSystem {
System system; System system;
Scheduler scheduler; Scheduler scheduler;
Cheat cheat; Cheat cheat;
#include "peripherals.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto System::run() -> void { auto System::run() -> void {
@ -51,7 +50,11 @@ auto System::save() -> void {
} }
auto System::unload() -> void { auto System::unload() -> void {
peripherals.unload(); if(MasterSystem::Model::MasterSystem()) {
cpu.peripherals.reset();
controllerPort1.unload();
controllerPort2.unload();
}
cartridge.unload(); cartridge.unload();
} }
@ -70,7 +73,13 @@ auto System::power() -> void {
psg.power(); psg.power();
scheduler.primary(cpu); scheduler.primary(cpu);
peripherals.reset(); if(MasterSystem::Model::MasterSystem()) {
controllerPort1.power(ID::Port::Controller1);
controllerPort2.power(ID::Port::Controller2);
controllerPort1.connect(settings.controllerPort1);
controllerPort2.connect(settings.controllerPort2);
}
} }
} }

View File

@ -36,17 +36,7 @@ private:
} information; } information;
}; };
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
auto connect(uint port, uint device) -> void;
Controller* controllerPort1 = nullptr;
Controller* controllerPort2 = nullptr;
};
extern System system; extern System system;
extern Peripherals peripherals;
auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; } auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; }
auto Model::GameGear() -> bool { return system.model() == System::Model::GameGear; } auto Model::GameGear() -> bool { return system.model() == System::Model::GameGear; }

View File

@ -2,10 +2,11 @@
namespace PCEngine { namespace PCEngine {
ControllerPort controllerPort;
#include "gamepad/gamepad.cpp" #include "gamepad/gamepad.cpp"
Controller::Controller() { Controller::Controller() {
if(!handle()) create(Controller::Enter, 100); if(!handle()) create(Controller::Enter, 1);
} }
Controller::~Controller() { Controller::~Controller() {
@ -15,7 +16,7 @@ Controller::~Controller() {
auto Controller::Enter() -> void { auto Controller::Enter() -> void {
while(true) { while(true) {
scheduler.synchronize(); scheduler.synchronize();
if(peripherals.controllerPort->active()) peripherals.controllerPort->main(); if(controllerPort.device->active()) controllerPort.device->main();
} }
} }
@ -24,4 +25,30 @@ auto Controller::main() -> void {
synchronize(cpu); synchronize(cpu);
} }
//
auto ControllerPort::connect(uint deviceID) -> void {
delete device;
if(!system.loaded()) return;
switch(deviceID) { default:
case ID::Device::None: device = new Controller; break;
case ID::Device::Gamepad: device = new Gamepad; break;
}
cpu.peripherals.reset();
if(auto device = controllerPort.device) cpu.peripherals.append(device);
}
auto ControllerPort::power() -> void {
}
auto ControllerPort::unload() -> void {
delete device;
device = nullptr;
}
auto ControllerPort::serialize(serializer& s) -> void {
}
} }

View File

@ -9,4 +9,16 @@ struct Controller : Thread {
virtual auto writeData(uint2) -> void {} virtual auto writeData(uint2) -> void {}
}; };
struct ControllerPort {
auto connect(uint deviceID) -> void;
auto power() -> void;
auto unload() -> void;
auto serialize(serializer&) -> void;
Controller* device = nullptr;
};
extern ControllerPort controllerPort;
#include "gamepad/gamepad.hpp" #include "gamepad/gamepad.hpp"

View File

@ -54,7 +54,7 @@ auto CPU::read_(uint8 bank, uint13 addr) -> uint8 {
//note 2: we state that the CD-ROM drive is present. //note 2: we state that the CD-ROM drive is present.
//this is so games can use its backup RAM for save data. //this is so games can use its backup RAM for save data.
return ( return (
PCEngine::peripherals.controllerPort->readData() << 0 controllerPort.device->readData() << 0
| 1 << 4 | 1 << 4
| 1 << 5 | 1 << 5
| 0 << 6 //device (0 = Turbografx-16; 1 = PC Engine) | 0 << 6 //device (0 = Turbografx-16; 1 = PC Engine)
@ -162,7 +162,7 @@ auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void {
//$1000-13ff I/O //$1000-13ff I/O
if((addr & 0x1c00) == 0x1000) { if((addr & 0x1c00) == 0x1000) {
io.mdr = data; io.mdr = data;
PCEngine::peripherals.controllerPort->writeData(data.bits(0,1)); controllerPort.device->writeData(data.bits(0,1));
return; return;
} }

View File

@ -85,7 +85,7 @@ auto Interface::unload() -> void {
} }
auto Interface::connect(uint port, uint device) -> void { auto Interface::connect(uint port, uint device) -> void {
PCEngine::peripherals.connect(port, device); if(port == ID::Port::Controller) controllerPort.connect(settings.controllerPort = device);
} }
auto Interface::power() -> void { auto Interface::power() -> void {

View File

@ -1,26 +0,0 @@
Peripherals peripherals;
auto Peripherals::unload() -> void {
delete controllerPort;
controllerPort = nullptr;
}
auto Peripherals::reset() -> void {
connect(ID::Port::Controller, settings.controllerPort);
}
auto Peripherals::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller) {
settings.controllerPort = device;
if(!system.loaded()) return;
delete controllerPort;
switch(device) { default:
case ID::Device::None: controllerPort = new Controller; break;
case ID::Device::Gamepad: controllerPort = new Gamepad; break;
}
}
cpu.peripherals.reset();
cpu.peripherals.append(controllerPort);
}

View File

@ -61,6 +61,7 @@ auto System::serializeAll(serializer& s) -> void {
vdc0.serialize(s); vdc0.serialize(s);
vdc1.serialize(s); vdc1.serialize(s);
psg.serialize(s); psg.serialize(s);
controllerPort.serialize(s);
} }
auto System::serialize(serializer& s) -> void { auto System::serialize(serializer& s) -> void {

View File

@ -5,7 +5,6 @@ namespace PCEngine {
System system; System system;
Scheduler scheduler; Scheduler scheduler;
Cheat cheat; Cheat cheat;
#include "peripherals.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto System::run() -> void { auto System::run() -> void {
@ -44,7 +43,8 @@ auto System::save() -> void {
} }
auto System::unload() -> void { auto System::unload() -> void {
peripherals.unload(); cpu.peripherals.reset();
controllerPort.unload();
cartridge.unload(); cartridge.unload();
} }
@ -66,7 +66,8 @@ auto System::power() -> void {
psg.power(); psg.power();
scheduler.primary(cpu); scheduler.primary(cpu);
peripherals.reset(); controllerPort.power();
controllerPort.connect(settings.controllerPort);
} }
} }

View File

@ -33,16 +33,7 @@ private:
} information; } information;
}; };
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
auto connect(uint port, uint device) -> void;
Controller* controllerPort = nullptr;
};
extern System system; extern System system;
extern Peripherals peripherals;
auto Model::PCEngine() -> bool { return system.model() == System::Model::PCEngine; } auto Model::PCEngine() -> bool { return system.model() == System::Model::PCEngine; }
auto Model::SuperGrafx() -> bool { return system.model() == System::Model::SuperGrafx; } auto Model::SuperGrafx() -> bool { return system.model() == System::Model::SuperGrafx; }

View File

@ -413,7 +413,7 @@ auto SPC700::instructionIndirectXWrite(uint8& data) -> void {
auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void { auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void {
idle(PC); idle(PC);
idle(); //quirk: does not read internal SMP registers idle(page(X), false); //quirk: does not read internal SMP registers
data = read(page(X++)); data = read(page(X++));
ZF = data == 0; ZF = data == 0;
NF = data & 0x80; NF = data & 0x80;
@ -421,7 +421,7 @@ auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void {
auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void { auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void {
idle(PC); idle(PC);
idle(); //quirk: does not read internal SMP registers idle(page(X), false); //quirk: does not read internal SMP registers
write(page(X++), data); write(page(X++), data);
} }

View File

@ -28,10 +28,6 @@ namespace Processor {
#include "serialization.cpp" #include "serialization.cpp"
#include "disassembler.cpp" #include "disassembler.cpp"
auto SPC700::idle(uint16 address) -> void {
read(address);
}
auto SPC700::page(uint8 address) const -> uint16 { auto SPC700::page(uint8 address) const -> uint16 {
return PF << 8 | address; return PF << 8 | address;
} }

View File

@ -3,7 +3,7 @@
namespace Processor { namespace Processor {
struct SPC700 { struct SPC700 {
virtual auto idle() -> void = 0; virtual auto idle(uint16 address, bool read = true) -> void = 0;
virtual auto read(uint16 address) -> uint8 = 0; virtual auto read(uint16 address) -> uint8 = 0;
virtual auto write(uint16 addessr, uint8 data) -> void = 0; virtual auto write(uint16 addessr, uint8 data) -> void = 0;
virtual auto synchronizing() const -> bool = 0; virtual auto synchronizing() const -> bool = 0;
@ -11,7 +11,6 @@ struct SPC700 {
virtual auto readDisassembler(uint16 address) -> uint8 { return 0; } virtual auto readDisassembler(uint16 address) -> uint8 { return 0; }
//spc700.cpp //spc700.cpp
inline auto idle(uint16 address) -> void;
inline auto page(uint8 address) const -> uint16; inline auto page(uint8 address) const -> uint16;
inline auto stack(uint8 address) const -> uint16; inline auto stack(uint8 address) const -> uint16;

View File

@ -10,7 +10,7 @@ ControllerPort controllerPort2;
#include "super-scope/super-scope.cpp" #include "super-scope/super-scope.cpp"
#include "justifier/justifier.cpp" #include "justifier/justifier.cpp"
Controller::Controller(bool port) : port(port) { Controller::Controller(uint port) : port(port) {
if(!handle()) create(Controller::Enter, 1); if(!handle()) create(Controller::Enter, 1);
} }
@ -33,15 +33,16 @@ auto Controller::main() -> void {
auto Controller::iobit() -> bool { auto Controller::iobit() -> bool {
switch(port) { switch(port) {
case Controller::Port1: return cpu.pio() & 0x40; case ID::Port::Controller1: return cpu.pio() & 0x40;
case Controller::Port2: return cpu.pio() & 0x80; case ID::Port::Controller2: return cpu.pio() & 0x80;
} }
unreachable;
} }
auto Controller::iobit(bool data) -> void { auto Controller::iobit(bool data) -> void {
switch(port) { switch(port) {
case Controller::Port1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break; case ID::Port::Controller1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break;
case Controller::Port2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break; case ID::Port::Controller2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break;
} }
} }

View File

@ -12,9 +12,7 @@
// 7: gnd // 7: gnd
struct Controller : Thread { struct Controller : Thread {
enum : bool { Port1 = 0, Port2 = 1 }; Controller(uint port);
Controller(bool port);
virtual ~Controller(); virtual ~Controller();
static auto Enter() -> void; static auto Enter() -> void;
@ -24,7 +22,7 @@ struct Controller : Thread {
virtual auto data() -> uint2 { return 0; } virtual auto data() -> uint2 { return 0; }
virtual auto latch(bool data) -> void {} virtual auto latch(bool data) -> void {}
const bool port; const uint port;
}; };
struct ControllerPort { struct ControllerPort {

View File

@ -1,4 +1,4 @@
Gamepad::Gamepad(bool port) : Controller(port) { Gamepad::Gamepad(uint port) : Controller(port) {
latched = 0; latched = 0;
counter = 0; counter = 0;
} }

View File

@ -3,7 +3,7 @@ struct Gamepad : Controller {
Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start,
}; };
Gamepad(bool port); Gamepad(uint port);
auto data() -> uint2; auto data() -> uint2;
auto latch(bool data) -> void; auto latch(bool data) -> void;

View File

@ -1,9 +1,9 @@
Justifier::Justifier(bool port, bool chained): Justifier::Justifier(uint port, bool chained):
Controller(port), Controller(port),
chained(chained), chained(chained),
device(!chained ? ID::Device::Justifier : ID::Device::Justifiers) device(!chained ? ID::Device::Justifier : ID::Device::Justifiers)
{ {
create(Controller::Enter, 21'477'272); create(Controller::Enter, system.cpuFrequency());
latched = 0; latched = 0;
counter = 0; counter = 0;
active = 0; active = 0;

View File

@ -3,7 +3,7 @@ struct Justifier : Controller {
X, Y, Trigger, Start, X, Y, Trigger, Start,
}; };
Justifier(bool port, bool chained); Justifier(uint port, bool chained);
~Justifier(); ~Justifier();
auto main() -> void; auto main() -> void;

View File

@ -1,4 +1,4 @@
Mouse::Mouse(bool port) : Controller(port) { Mouse::Mouse(uint port) : Controller(port) {
latched = 0; latched = 0;
counter = 0; counter = 0;

View File

@ -3,7 +3,7 @@ struct Mouse : Controller {
X, Y, Left, Right, X, Y, Left, Right,
}; };
Mouse(bool port); Mouse(uint port);
auto data() -> uint2; auto data() -> uint2;
auto latch(bool data) -> void; auto latch(bool data) -> void;

View File

@ -1,4 +1,4 @@
SuperMultitap::SuperMultitap(bool port) : Controller(port) { SuperMultitap::SuperMultitap(uint port) : Controller(port) {
latched = 0; latched = 0;
counter1 = 0; counter1 = 0;
counter2 = 0; counter2 = 0;

View File

@ -3,7 +3,7 @@ struct SuperMultitap : Controller {
Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start,
}; };
SuperMultitap(bool port); SuperMultitap(uint port);
auto data() -> uint2; auto data() -> uint2;
auto latch(bool data) -> void; auto latch(bool data) -> void;

View File

@ -10,8 +10,8 @@
//require manual polling of PIO ($4201.d6) to determine when iobit was written. //require manual polling of PIO ($4201.d6) to determine when iobit was written.
//Note that no commercial game ever utilizes a Super Scope in port 1. //Note that no commercial game ever utilizes a Super Scope in port 1.
SuperScope::SuperScope(bool port) : Controller(port) { SuperScope::SuperScope(uint port) : Controller(port) {
create(Controller::Enter, 21'477'272); create(Controller::Enter, system.cpuFrequency());
sprite = Emulator::video.createSprite(32, 32); sprite = Emulator::video.createSprite(32, 32);
sprite->setPixels(Resource::Sprite::CrosshairGreen); sprite->setPixels(Resource::Sprite::CrosshairGreen);

View File

@ -5,7 +5,7 @@ struct SuperScope : Controller {
X, Y, Trigger, Cursor, Turbo, Pause, X, Y, Trigger, Cursor, Turbo, Pause,
}; };
SuperScope(bool port); SuperScope(uint port);
~SuperScope(); ~SuperScope();
auto main() -> void; auto main() -> void;

View File

@ -116,9 +116,6 @@ auto CPU::power() -> void {
channel.hdmaDoTransfer = false; channel.hdmaDoTransfer = false;
} }
//$2140-217f
for(auto& port : io.port) port = 0x00;
//$2181-$2183 //$2181-$2183
io.wramAddress = 0x000000; io.wramAddress = 0x000000;

View File

@ -4,11 +4,9 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
auto joylatch() const -> bool; auto joylatch() const -> bool;
auto synchronizing() const -> bool override; auto synchronizing() const -> bool override;
//cpu.cpp
CPU(); CPU();
auto readPort(uint2 port) const -> uint8;
auto writePort(uint2 port, uint8 data) -> void;
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto load(Markup::Node) -> bool; auto load(Markup::Node) -> bool;
@ -135,9 +133,6 @@ private:
} status; } status;
struct IO { struct IO {
//$2140-217f
uint8 port[4];
//$2181-$2183 //$2181-$2183
uint17 wramAddress; uint17 wramAddress;

View File

@ -1,6 +1,6 @@
auto CPU::readAPU(uint24 addr, uint8 data) -> uint8 { auto CPU::readAPU(uint24 addr, uint8 data) -> uint8 {
synchronize(smp); synchronize(smp);
return smp.readPort(addr.bits(0,1)); return smp.portRead(addr.bits(0,1));
} }
auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 { auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
@ -158,7 +158,7 @@ auto CPU::readDMA(uint24 addr, uint8 data) -> uint8 {
auto CPU::writeAPU(uint24 addr, uint8 data) -> void { auto CPU::writeAPU(uint24 addr, uint8 data) -> void {
synchronize(smp); synchronize(smp);
return writePort(addr.bits(0,1), data); return smp.portWrite(addr.bits(0,1), data);
} }
auto CPU::writeCPU(uint24 addr, uint8 data) -> void { auto CPU::writeCPU(uint24 addr, uint8 data) -> void {

View File

@ -1,11 +1,3 @@
auto CPU::readPort(uint2 port) const -> uint8 {
return io.port[port];
}
auto CPU::writePort(uint2 port, uint8 data) -> void {
io.port[port] = data;
}
auto CPU::idle() -> void { auto CPU::idle() -> void {
status.clockCount = 6; status.clockCount = 6;
dmaEdge(); dmaEdge();

View File

@ -49,8 +49,6 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(status.autoJoypadLatch); s.integer(status.autoJoypadLatch);
s.integer(status.autoJoypadCounter); s.integer(status.autoJoypadCounter);
s.array(io.port);
s.integer(io.wramAddress); s.integer(io.wramAddress);
s.integer(io.joypadStrobeLatch); s.integer(io.joypadStrobeLatch);

View File

@ -1,6 +1,6 @@
auto DSP::brrDecode(Voice& v) -> void { auto DSP::brrDecode(Voice& v) -> void {
//state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle //state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle
int nybbles = (state._brrByte << 8) + smp.apuram[(uint16)(v.brrAddress + v.brrOffset + 1)]; int nybbles = (state._brrByte << 8) + apuram[(uint16)(v.brrAddress + v.brrOffset + 1)];
const int filter = (state._brrHeader >> 2) & 3; const int filter = (state._brrHeader >> 2) & 3;
const int scale = (state._brrHeader >> 4); const int scale = (state._brrHeader >> 4);

View File

@ -232,6 +232,8 @@ auto DSP::power() -> void {
create(Enter, system.apuFrequency()); create(Enter, system.apuFrequency());
stream = Emulator::audio.createStream(2, frequency() / 768.0); stream = Emulator::audio.createStream(2, frequency() / 768.0);
for(auto& byte : apuram) byte = random(0x00);
memory::fill(&state, sizeof(State)); memory::fill(&state, sizeof(State));
state.noise = 0x4000; state.noise = 0x4000;
state.echoHistoryOffset = 0; state.echoHistoryOffset = 0;

View File

@ -2,6 +2,7 @@
struct DSP : Thread { struct DSP : Thread {
shared_pointer<Emulator::Stream> stream; shared_pointer<Emulator::Stream> stream;
uint8 apuram[64 * 1024];
DSP(); DSP();

View File

@ -11,8 +11,8 @@ auto DSP::echoOutput(bool channel) -> int {
auto DSP::echoRead(bool channel) -> void { auto DSP::echoRead(bool channel) -> void {
uint addr = state._echoPointer + channel * 2; uint addr = state._echoPointer + channel * 2;
uint8 lo = smp.apuram[(uint16)(addr + 0)]; uint8 lo = apuram[(uint16)(addr + 0)];
uint8 hi = smp.apuram[(uint16)(addr + 1)]; uint8 hi = apuram[(uint16)(addr + 1)];
int s = (int16)((hi << 8) + lo); int s = (int16)((hi << 8) + lo);
state.echoHistory[channel][state.echoHistoryOffset] = s >> 1; state.echoHistory[channel][state.echoHistoryOffset] = s >> 1;
} }
@ -21,8 +21,8 @@ auto DSP::echoWrite(bool channel) -> void {
if(!(state._echoDisabled & 0x20)) { if(!(state._echoDisabled & 0x20)) {
uint addr = state._echoPointer + channel * 2; uint addr = state._echoPointer + channel * 2;
int s = state._echoOut[channel]; int s = state._echoOut[channel];
smp.apuram[(uint16)(addr + 0)] = s; apuram[(uint16)(addr + 0)] = s;
smp.apuram[(uint16)(addr + 1)] = s >> 8; apuram[(uint16)(addr + 1)] = s >> 8;
} }
state._echoOut[channel] = 0; state._echoOut[channel] = 0;

View File

@ -1,6 +1,8 @@
void DSP::serialize(serializer& s) { void DSP::serialize(serializer& s) {
Thread::serialize(s); Thread::serialize(s);
s.array(apuram);
s.array(state.regs, 128); s.array(state.regs, 128);
s.array(state.echoHistory[0]); s.array(state.echoHistory[0]);
s.array(state.echoHistory[1]); s.array(state.echoHistory[1]);

View File

@ -22,8 +22,8 @@ auto DSP::voice2(Voice& v) -> void {
//read sample pointer (ignored if not needed) //read sample pointer (ignored if not needed)
uint16 addr = state._dirAddress; uint16 addr = state._dirAddress;
if(!v.konDelay) addr += 2; if(!v.konDelay) addr += 2;
uint8 lo = smp.apuram[(uint16)(addr + 0)]; uint8 lo = apuram[(uint16)(addr + 0)];
uint8 hi = smp.apuram[(uint16)(addr + 1)]; uint8 hi = apuram[(uint16)(addr + 1)];
state._brrNextAddress = ((hi << 8) + lo); state._brrNextAddress = ((hi << 8) + lo);
state._adsr0 = VREG(ADSR0); state._adsr0 = VREG(ADSR0);
@ -43,8 +43,8 @@ auto DSP::voice3a(Voice& v) -> void {
} }
auto DSP::voice3b(Voice& v) -> void { auto DSP::voice3b(Voice& v) -> void {
state._brrByte = smp.apuram[(uint16)(v.brrAddress + v.brrOffset)]; state._brrByte = apuram[(uint16)(v.brrAddress + v.brrOffset)];
state._brrHeader = smp.apuram[(uint16)(v.brrAddress)]; state._brrHeader = apuram[(uint16)(v.brrAddress)];
} }
auto DSP::voice3c(Voice& v) -> void { auto DSP::voice3c(Voice& v) -> void {

View File

@ -1,30 +1,37 @@
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 { alwaysinline auto SMP::ramRead(uint16 addr) -> uint8 {
if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f]; if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
if(io.ramDisable) return 0x5a; //0xff on mini-SNES if(io.ramDisable) return 0x5a; //0xff on mini-SNES
return apuram[addr]; return dsp.apuram[addr];
} }
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void { alwaysinline auto SMP::ramWrite(uint16 addr, uint8 data) -> void {
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled //writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
if(io.ramWritable && !io.ramDisable) apuram[addr] = data; if(io.ramWritable && !io.ramDisable) dsp.apuram[addr] = data;
} }
auto SMP::readPort(uint2 port) const -> uint8 { auto SMP::portRead(uint2 port) const -> uint8 {
return io.port[0xf4 + port]; if(port == 0) return io.cpu0;
if(port == 1) return io.cpu1;
if(port == 2) return io.cpu2;
if(port == 3) return io.cpu3;
unreachable;
} }
auto SMP::writePort(uint2 port, uint8 data) -> void { auto SMP::portWrite(uint2 port, uint8 data) -> void {
io.port[0xf4 + port] = data; if(port == 0) io.apu0 = data;
if(port == 1) io.apu1 = data;
if(port == 2) io.apu2 = data;
if(port == 3) io.apu3 = data;
} }
auto SMP::readBus(uint16 addr) -> uint8 { auto SMP::busRead(uint16 addr) -> uint8 {
uint result; uint result;
switch(addr) { switch(addr) {
case 0xf0: //TEST -- write-only register case 0xf0: //TEST (write-only register)
return 0x00; return 0x00;
case 0xf1: //CONTROL -- write-only register case 0xf1: //CONTROL (write-only register)
return 0x00; return 0x00;
case 0xf2: //DSPADDR case 0xf2: //DSPADDR
@ -35,55 +42,64 @@ auto SMP::readBus(uint16 addr) -> uint8 {
return dsp.read(io.dspAddr & 0x7f); return dsp.read(io.dspAddr & 0x7f);
case 0xf4: //CPUIO0 case 0xf4: //CPUIO0
synchronize(cpu);
return io.apu0;
case 0xf5: //CPUIO1 case 0xf5: //CPUIO1
synchronize(cpu);
return io.apu1;
case 0xf6: //CPUIO2 case 0xf6: //CPUIO2
synchronize(cpu);
return io.apu2;
case 0xf7: //CPUIO3 case 0xf7: //CPUIO3
synchronize(cpu); synchronize(cpu);
return cpu.readPort(addr); return io.apu3;
case 0xf8: //RAM0 case 0xf8: //AUXIO4
return io.ram00f8; return io.aux4;
case 0xf9: //RAM1 case 0xf9: //AUXIO5
return io.ram00f9; return io.aux5;
case 0xfa: //T0TARGET case 0xfa: //T0TARGET
case 0xfb: //T1TARGET case 0xfb: //T1TARGET
case 0xfc: //T2TARGET -- write-only registers case 0xfc: //T2TARGET (write-only registers)
return 0x00; return 0x00;
case 0xfd: //T0OUT -- 4-bit counter value case 0xfd: //T0OUT (4-bit counter value)
result = timer0.stage3; result = timer0.stage3;
timer0.stage3 = 0; timer0.stage3 = 0;
return result; return result;
case 0xfe: //T1OUT -- 4-bit counter value case 0xfe: //T1OUT (4-bit counter value)
result = timer1.stage3; result = timer1.stage3;
timer1.stage3 = 0; timer1.stage3 = 0;
return result; return result;
case 0xff: //T2OUT -- 4-bit counter value case 0xff: //T2OUT (4-bit counter value)
result = timer2.stage3; result = timer2.stage3;
timer2.stage3 = 0; timer2.stage3 = 0;
return result; return result;
} }
return readRAM(addr); return ramRead(addr);
} }
auto SMP::writeBus(uint16 addr, uint8 data) -> void { auto SMP::busWrite(uint16 addr, uint8 data) -> void {
switch(addr) { switch(addr) {
case 0xf0: //TEST case 0xf0: //TEST
if(r.p.p) break; //writes only valid when P flag is clear if(r.p.p) break; //writes only valid when P flag is clear
io.clockSpeed = (data >> 6) & 3; io.timersDisable = data.bit (0);
io.timerSpeed = (data >> 4) & 3; io.ramWritable = data.bit (1);
io.timersEnable = data & 0x08; io.ramDisable = data.bit (2);
io.ramDisable = data & 0x04; io.timersEnable = data.bit (3);
io.ramWritable = data & 0x02; io.ramSpeed = data.bits(4,5);
io.timersDisable = data & 0x01; io.romIOSpeed = data.bits(6,7);
io.timerStep = (1 << io.clockSpeed) + (2 << io.timerSpeed); io.timerStep = (1 << io.romIOSpeed) + (2 << io.ramSpeed);
timer0.synchronizeStage1(); timer0.synchronizeStage1();
timer1.synchronizeStage1(); timer1.synchronizeStage1();
@ -91,40 +107,38 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
break; break;
case 0xf1: //CONTROL case 0xf1: //CONTROL
io.iplromEnable = data & 0x80;
if(data & 0x30) {
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
synchronize(cpu);
if(data & 0x20) {
cpu.writePort(2, 0x00);
cpu.writePort(3, 0x00);
}
if(data & 0x10) {
cpu.writePort(0, 0x00);
cpu.writePort(1, 0x00);
}
}
//0->1 transistion resets timers //0->1 transistion resets timers
if(!timer2.enable && (data & 0x04)) { if(!timer0.enable && data.bit(0)) {
timer2.stage2 = 0;
timer2.stage3 = 0;
}
timer2.enable = data & 0x04;
if(!timer1.enable && (data & 0x02)) {
timer1.stage2 = 0;
timer1.stage3 = 0;
}
timer1.enable = data & 0x02;
if(!timer0.enable && (data & 0x01)) {
timer0.stage2 = 0; timer0.stage2 = 0;
timer0.stage3 = 0; timer0.stage3 = 0;
} }
timer0.enable = data & 0x01; timer0.enable = data.bit(0);
if(!timer1.enable && data.bit(1)) {
timer1.stage2 = 0;
timer1.stage3 = 0;
}
timer1.enable = data.bit(1);
if(!timer2.enable && data.bit(2)) {
timer2.stage2 = 0;
timer2.stage3 = 0;
}
timer2.enable = data.bit(2);
if(data.bit(4)) {
synchronize(cpu);
io.apu0 = 0x00;
io.apu1 = 0x00;
}
if(data.bit(5)) {
synchronize(cpu);
io.apu2 = 0x00;
io.apu3 = 0x00;
}
io.iplromEnable = data.bit(7);
break; break;
case 0xf2: //DSPADDR case 0xf2: //DSPADDR
@ -137,19 +151,31 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
break; break;
case 0xf4: //CPUIO0 case 0xf4: //CPUIO0
synchronize(cpu);
io.cpu0 = data;
break;
case 0xf5: //CPUIO1 case 0xf5: //CPUIO1
synchronize(cpu);
io.cpu1 = data;
break;
case 0xf6: //CPUIO2 case 0xf6: //CPUIO2
synchronize(cpu);
io.cpu2 = data;
break;
case 0xf7: //CPUIO3 case 0xf7: //CPUIO3
synchronize(cpu); synchronize(cpu);
writePort(addr, data); io.cpu3 = data;
break; break;
case 0xf8: //RAM0 case 0xf8: //AUXIO4
io.ram00f8 = data; io.aux4 = data;
break; break;
case 0xf9: //RAM1 case 0xf9: //AUXIO5
io.ram00f9 = data; io.aux5 = data;
break; break;
case 0xfa: //T0TARGET case 0xfa: //T0TARGET
@ -166,34 +192,41 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
case 0xfd: //T0OUT case 0xfd: //T0OUT
case 0xfe: //T1OUT case 0xfe: //T1OUT
case 0xff: //T2OUT -- read-only registers case 0xff: //T2OUT (read-only registers)
break; break;
} }
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus ramWrite(addr, data); //all writes, even to I/O registers, appear on bus
} }
auto SMP::idle() -> void { auto SMP::speed(uint16 addr) const -> uint {
step(24); static const uint waitStates[4] = {1, 2, 5, 10};
if((addr & 0xfff0) == 0x00f0) return waitStates[io.romIOSpeed];
if(addr >= 0xffc0 && io.iplromEnable) return waitStates[io.romIOSpeed];
return waitStates[io.ramSpeed];
}
auto SMP::idle(uint16 addr, bool read) -> void {
step(24 * speed(addr));
if(read) busRead(addr);
cycleEdge(); cycleEdge();
} }
auto SMP::read(uint16 addr) -> uint8 { auto SMP::read(uint16 addr) -> uint8 {
step(12); step(24 * speed(addr));
uint8 data = readBus(addr); uint8 data = busRead(addr);
step(12);
cycleEdge(); cycleEdge();
return data; return data;
} }
auto SMP::write(uint16 addr, uint8 data) -> void { auto SMP::write(uint16 addr, uint8 data) -> void {
step(24); step(24 * speed(addr));
writeBus(addr, data); busWrite(addr, data);
cycleEdge(); cycleEdge();
} }
auto SMP::readDisassembler(uint16 addr) -> uint8 { auto SMP::readDisassembler(uint16 addr) -> uint8 {
if((addr & 0xfff0) == 0x00f0) return 0x00; if((addr & 0xfff0) == 0x00f0) return 0x00;
if((addr & 0xffc0) == 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f]; if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
return apuram[addr]; return dsp.apuram[addr];
} }

View File

@ -2,27 +2,33 @@ auto SMP::serialize(serializer& s) -> void {
SPC700::serialize(s); SPC700::serialize(s);
Thread::serialize(s); Thread::serialize(s);
s.array(apuram);
s.integer(io.clockCounter); s.integer(io.clockCounter);
s.integer(io.dspCounter); s.integer(io.dspCounter);
s.integer(io.timerStep); s.integer(io.timerStep);
s.integer(io.clockSpeed); s.integer(io.apu0);
s.integer(io.timerSpeed); s.integer(io.apu1);
s.integer(io.timersEnable); s.integer(io.apu2);
s.integer(io.ramDisable); s.integer(io.apu3);
s.integer(io.ramWritable);
s.integer(io.timersDisable); s.integer(io.timersDisable);
s.integer(io.ramWritable);
s.integer(io.ramDisable);
s.integer(io.timersEnable);
s.integer(io.ramSpeed);
s.integer(io.romIOSpeed);
s.integer(io.iplromEnable); s.integer(io.iplromEnable);
s.integer(io.dspAddr); s.integer(io.dspAddr);
s.array(io.port); s.integer(io.cpu0);
s.integer(io.cpu1);
s.integer(io.cpu2);
s.integer(io.cpu3);
s.integer(io.ram00f8); s.integer(io.aux4);
s.integer(io.ram00f9); s.integer(io.aux5);
s.integer(timer0.stage0); s.integer(timer0.stage0);
s.integer(timer0.stage1); s.integer(timer0.stage1);

View File

@ -39,19 +39,24 @@ auto SMP::power() -> void {
r.pc.byte.l = iplrom[62]; r.pc.byte.l = iplrom[62];
r.pc.byte.h = iplrom[63]; r.pc.byte.h = iplrom[63];
for(auto& byte : apuram) byte = random(0x00); //timing
io.clockCounter = 0; io.clockCounter = 0;
io.dspCounter = 0; io.dspCounter = 0;
io.timerStep = 3; io.timerStep = (1 << 0) + (2 << 0);
//external
io.apu0 = 0x00;
io.apu1 = 0x00;
io.apu2 = 0x00;
io.apu3 = 0x00;
//$00f0 //$00f0
io.clockSpeed = 0;
io.timerSpeed = 0;
io.timersEnable = true;
io.ramDisable = false;
io.ramWritable = true;
io.timersDisable = false; io.timersDisable = false;
io.ramWritable = true;
io.ramDisable = false;
io.timersEnable = true;
io.ramSpeed = 0;
io.romIOSpeed = 0;
//$00f1 //$00f1
io.iplromEnable = true; io.iplromEnable = true;
@ -60,14 +65,14 @@ auto SMP::power() -> void {
io.dspAddr = 0x00; io.dspAddr = 0x00;
//$00f4-00f7 //$00f4-00f7
io.port[0] = 0x00; io.cpu0 = 0x00;
io.port[1] = 0x00; io.cpu1 = 0x00;
io.port[2] = 0x00; io.cpu2 = 0x00;
io.port[3] = 0x00; io.cpu3 = 0x00;
//$00f8,$00f9 //$00f8-$00f9
io.ram00f8 = 0x00; io.aux4 = 0x00;
io.ram00f9 = 0x00; io.aux5 = 0x00;
timer0.stage0 = 0; timer0.stage0 = 0;
timer1.stage0 = 0; timer1.stage0 = 0;

View File

@ -1,11 +1,13 @@
//Sony CXP1100Q-1 //Sony CXP1100Q-1
struct SMP : Processor::SPC700, Thread { struct SMP : Processor::SPC700, Thread {
uint8 iplrom[64];
//smp.cpp //smp.cpp
auto synchronizing() const -> bool override; auto synchronizing() const -> bool override;
auto readPort(uint2 port) const -> uint8; auto portRead(uint2 port) const -> uint8;
auto writePort(uint2 port, uint8 data) -> void; auto portWrite(uint2 port, uint8 data) -> void;
auto main() -> void; auto main() -> void;
auto load(Markup::Node) -> bool; auto load(Markup::Node) -> bool;
@ -14,9 +16,6 @@ struct SMP : Processor::SPC700, Thread {
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
uint8 iplrom[64];
uint8 apuram[64 * 1024];
private: private:
struct IO { struct IO {
//timing //timing
@ -24,13 +23,19 @@ private:
uint dspCounter; uint dspCounter;
uint timerStep; uint timerStep;
//external
uint8 apu0;
uint8 apu1;
uint8 apu2;
uint8 apu3;
//$00f0 //$00f0
uint8 clockSpeed; uint1 timersDisable;
uint8 timerSpeed; uint1 ramWritable;
bool timersEnable; uint1 ramDisable;
bool ramDisable; uint1 timersEnable;
bool ramWritable; uint2 ramSpeed;
bool timersDisable; uint2 romIOSpeed;
//$00f1 //$00f1
bool iplromEnable; bool iplromEnable;
@ -39,23 +44,27 @@ private:
uint8 dspAddr; uint8 dspAddr;
//$00f4-00f7 //$00f4-00f7
uint8 port[4]; uint8 cpu0;
uint8 cpu1;
uint8 cpu2;
uint8 cpu3;
//$00f8,$00f9 //$00f8-00f9
uint8 ram00f8; uint8 aux4;
uint8 ram00f9; uint8 aux5;
} io; } io;
static auto Enter() -> void; static auto Enter() -> void;
//memory.cpp //memory.cpp
auto readRAM(uint16 addr) -> uint8; auto ramRead(uint16 addr) -> uint8;
auto writeRAM(uint16 addr, uint8 data) -> void; auto ramWrite(uint16 addr, uint8 data) -> void;
auto readBus(uint16 addr) -> uint8; auto busRead(uint16 addr) -> uint8;
auto writeBus(uint16 addr, uint8 data) -> void; auto busWrite(uint16 addr, uint8 data) -> void;
auto idle() -> void override; auto speed(uint16 addr) const -> uint;
auto idle(uint16 addr, bool read = true) -> void override;
auto read(uint16 addr) -> uint8 override; auto read(uint16 addr) -> uint8 override;
auto write(uint16 addr, uint8 data) -> void override; auto write(uint16 addr, uint8 data) -> void override;

View File

@ -15,15 +15,6 @@ auto SMP::cycleEdge() -> void {
timer0.tick(); timer0.tick();
timer1.tick(); timer1.tick();
timer2.tick(); timer2.tick();
//TEST register S-SMP speed control
//24 clocks have already been added for this cycle at this point
switch(io.clockSpeed) {
case 0: break; //100% speed
case 1: step(24); break; // 50% speed
case 2: while(true) step(24); // 0% speed -- locks S-SMP
case 3: step(24 * 9); break; // 10% speed
}
} }
template<uint Frequency> auto SMP::Timer<Frequency>::tick() -> void { template<uint Frequency> auto SMP::Timer<Frequency>::tick() -> void {