mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
ff3750de4f
commit
40802b0b9f
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
namespace Famicom {
|
||||
|
||||
ControllerPort controllerPort1;
|
||||
ControllerPort controllerPort2;
|
||||
#include "gamepad/gamepad.cpp"
|
||||
|
||||
Controller::Controller(bool port) : port(port) {
|
||||
Controller::Controller(uint port) : port(port) {
|
||||
if(!handle()) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
|
@ -15,8 +17,8 @@ Controller::~Controller() {
|
|||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main();
|
||||
if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main();
|
||||
if(controllerPort1.device->active()) controllerPort1.device->main();
|
||||
if(controllerPort2.device->active()) controllerPort2.device->main();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,4 +27,32 @@ auto Controller::main() -> void {
|
|||
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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
// 7: gnd
|
||||
|
||||
struct Controller : Thread {
|
||||
enum : bool { Port1 = 0, Port2 = 1 };
|
||||
|
||||
Controller(bool port);
|
||||
Controller(uint port);
|
||||
virtual ~Controller();
|
||||
static auto Enter() -> void;
|
||||
|
||||
|
@ -27,7 +25,21 @@ struct Controller : Thread {
|
|||
virtual auto data() -> uint3 { return 0; }
|
||||
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"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Gamepad::Gamepad(bool port) : Controller(port) {
|
||||
Gamepad::Gamepad(uint port) : Controller(port) {
|
||||
}
|
||||
|
||||
auto Gamepad::data() -> uint3 {
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Gamepad : Controller {
|
|||
Up, Down, Left, Right, B, A, Select, Start,
|
||||
};
|
||||
|
||||
Gamepad(bool port);
|
||||
Gamepad(uint port);
|
||||
auto data() -> uint3;
|
||||
auto latch(bool data) -> void;
|
||||
|
||||
|
|
|
@ -10,12 +10,12 @@ auto CPU::readIO(uint16 addr) -> uint8 {
|
|||
switch(addr) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,8 @@ auto CPU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
}
|
||||
|
||||
case 0x4016: {
|
||||
Famicom::peripherals.controllerPort1->latch(data.bit(0));
|
||||
Famicom::peripherals.controllerPort2->latch(data.bit(0));
|
||||
controllerPort1.device->latch(data.bit(0));
|
||||
controllerPort2.device->latch(data.bit(0));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,8 @@ auto Interface::unload() -> 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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -45,6 +45,8 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
cpu.serialize(s);
|
||||
apu.serialize(s);
|
||||
ppu.serialize(s);
|
||||
controllerPort1.serialize(s);
|
||||
controllerPort2.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serializeInit() -> void {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Famicom {
|
||||
|
||||
#include "peripherals.cpp"
|
||||
#include "video.cpp"
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
@ -56,7 +55,9 @@ auto System::save() -> void {
|
|||
|
||||
auto System::unload() -> void {
|
||||
if(!loaded()) return;
|
||||
peripherals.unload();
|
||||
cpu.peripherals.reset();
|
||||
controllerPort1.unload();
|
||||
controllerPort2.unload();
|
||||
cartridge.unload();
|
||||
information.loaded = false;
|
||||
}
|
||||
|
@ -76,7 +77,12 @@ auto System::power() -> void {
|
|||
apu.power();
|
||||
ppu.power();
|
||||
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 {
|
||||
|
|
|
@ -41,17 +41,7 @@ private:
|
|||
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 Peripherals peripherals;
|
||||
|
||||
auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; }
|
||||
auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
struct Gamepad : Controller {
|
||||
enum : uint {
|
||||
Up, Down, Left, Right, A, B, C, X, Y, Z, Start,
|
||||
Up, Down, Left, Right, A, B, C, Start,
|
||||
};
|
||||
|
||||
Gamepad(uint port);
|
||||
|
|
|
@ -34,9 +34,6 @@ Interface::Interface() {
|
|||
device.inputs.append({0, "A" });
|
||||
device.inputs.append({0, "B" });
|
||||
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"});
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
|
|
|
@ -45,8 +45,8 @@ auto Bus::in(uint8 addr) -> uint8 {
|
|||
case 3: {
|
||||
if(Model::MasterSystem()) {
|
||||
bool reset = !platform->inputPoll(ID::Port::Hardware, ID::Device::MasterSystemControls, 0);
|
||||
auto port1 = peripherals.controllerPort1->readData();
|
||||
auto port2 = peripherals.controllerPort2->readData();
|
||||
auto port1 = controllerPort1.device->readData();
|
||||
auto port2 = controllerPort2.device->readData();
|
||||
if(addr.bit(0) == 0) {
|
||||
return port1.bits(0,5) << 0 | port2.bits(0,1) << 6;
|
||||
} else {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace MasterSystem {
|
||||
|
||||
ControllerPort controllerPort1;
|
||||
ControllerPort controllerPort2;
|
||||
#include "gamepad/gamepad.cpp"
|
||||
|
||||
Controller::Controller(uint port) : port(port) {
|
||||
|
@ -15,8 +17,8 @@ Controller::~Controller() {
|
|||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
if(auto device = peripherals.controllerPort1) if(device->active()) device->main();
|
||||
if(auto device = peripherals.controllerPort2) if(device->active()) device->main();
|
||||
if(controllerPort1.device->active()) controllerPort1.device->main();
|
||||
if(controllerPort2.device->active()) controllerPort2.device->main();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,4 +27,33 @@ auto Controller::main() -> void {
|
|||
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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,4 +10,18 @@ struct Controller : Thread {
|
|||
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"
|
||||
|
|
|
@ -30,10 +30,6 @@ auto Interface::unload() -> void {
|
|||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::connect(uint port, uint device) -> void {
|
||||
peripherals.connect(port, device);
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ struct Interface : Emulator::Interface {
|
|||
auto save() -> 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 run() -> void override;
|
||||
|
||||
|
@ -56,6 +56,8 @@ struct MasterSystemInterface : Interface {
|
|||
auto videoColor(uint32 color) -> uint64 override;
|
||||
|
||||
auto load(uint id) -> bool override;
|
||||
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
};
|
||||
|
||||
struct GameGearInterface : Interface {
|
||||
|
|
|
@ -68,3 +68,8 @@ auto MasterSystemInterface::load(uint id) -> bool {
|
|||
if(id == ID::MasterSystem) return system.load(this, System::Model::MasterSystem);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -60,6 +60,8 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
cpu.serialize(s);
|
||||
vdp.serialize(s);
|
||||
psg.serialize(s);
|
||||
controllerPort1.serialize(s);
|
||||
controllerPort2.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serialize(serializer& s) -> void {
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace MasterSystem {
|
|||
System system;
|
||||
Scheduler scheduler;
|
||||
Cheat cheat;
|
||||
#include "peripherals.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto System::run() -> void {
|
||||
|
@ -51,7 +50,11 @@ auto System::save() -> void {
|
|||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
peripherals.unload();
|
||||
if(MasterSystem::Model::MasterSystem()) {
|
||||
cpu.peripherals.reset();
|
||||
controllerPort1.unload();
|
||||
controllerPort2.unload();
|
||||
}
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
|
@ -70,7 +73,13 @@ auto System::power() -> void {
|
|||
psg.power();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,17 +36,7 @@ private:
|
|||
} 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 Peripherals peripherals;
|
||||
|
||||
auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; }
|
||||
auto Model::GameGear() -> bool { return system.model() == System::Model::GameGear; }
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace PCEngine {
|
||||
|
||||
ControllerPort controllerPort;
|
||||
#include "gamepad/gamepad.cpp"
|
||||
|
||||
Controller::Controller() {
|
||||
if(!handle()) create(Controller::Enter, 100);
|
||||
if(!handle()) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
|
@ -15,7 +16,7 @@ Controller::~Controller() {
|
|||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,4 +9,16 @@ struct Controller : Thread {
|
|||
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"
|
||||
|
|
|
@ -54,7 +54,7 @@ auto CPU::read_(uint8 bank, uint13 addr) -> uint8 {
|
|||
//note 2: we state that the CD-ROM drive is present.
|
||||
//this is so games can use its backup RAM for save data.
|
||||
return (
|
||||
PCEngine::peripherals.controllerPort->readData() << 0
|
||||
controllerPort.device->readData() << 0
|
||||
| 1 << 4
|
||||
| 1 << 5
|
||||
| 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
|
||||
if((addr & 0x1c00) == 0x1000) {
|
||||
io.mdr = data;
|
||||
PCEngine::peripherals.controllerPort->writeData(data.bits(0,1));
|
||||
controllerPort.device->writeData(data.bits(0,1));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ auto Interface::unload() -> 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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -61,6 +61,7 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
vdc0.serialize(s);
|
||||
vdc1.serialize(s);
|
||||
psg.serialize(s);
|
||||
controllerPort.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serialize(serializer& s) -> void {
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace PCEngine {
|
|||
System system;
|
||||
Scheduler scheduler;
|
||||
Cheat cheat;
|
||||
#include "peripherals.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto System::run() -> void {
|
||||
|
@ -44,7 +43,8 @@ auto System::save() -> void {
|
|||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
peripherals.unload();
|
||||
cpu.peripherals.reset();
|
||||
controllerPort.unload();
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,8 @@ auto System::power() -> void {
|
|||
psg.power();
|
||||
scheduler.primary(cpu);
|
||||
|
||||
peripherals.reset();
|
||||
controllerPort.power();
|
||||
controllerPort.connect(settings.controllerPort);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,16 +33,7 @@ private:
|
|||
} information;
|
||||
};
|
||||
|
||||
struct Peripherals {
|
||||
auto unload() -> void;
|
||||
auto reset() -> void;
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
||||
Controller* controllerPort = nullptr;
|
||||
};
|
||||
|
||||
extern System system;
|
||||
extern Peripherals peripherals;
|
||||
|
||||
auto Model::PCEngine() -> bool { return system.model() == System::Model::PCEngine; }
|
||||
auto Model::SuperGrafx() -> bool { return system.model() == System::Model::SuperGrafx; }
|
||||
|
|
|
@ -413,7 +413,7 @@ auto SPC700::instructionIndirectXWrite(uint8& data) -> void {
|
|||
|
||||
auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void {
|
||||
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++));
|
||||
ZF = data == 0;
|
||||
NF = data & 0x80;
|
||||
|
@ -421,7 +421,7 @@ auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void {
|
|||
|
||||
auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,10 +28,6 @@ namespace Processor {
|
|||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
auto SPC700::idle(uint16 address) -> void {
|
||||
read(address);
|
||||
}
|
||||
|
||||
auto SPC700::page(uint8 address) const -> uint16 {
|
||||
return PF << 8 | address;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Processor {
|
||||
|
||||
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 write(uint16 addessr, uint8 data) -> void = 0;
|
||||
virtual auto synchronizing() const -> bool = 0;
|
||||
|
@ -11,7 +11,6 @@ struct SPC700 {
|
|||
virtual auto readDisassembler(uint16 address) -> uint8 { return 0; }
|
||||
|
||||
//spc700.cpp
|
||||
inline auto idle(uint16 address) -> void;
|
||||
inline auto page(uint8 address) const -> uint16;
|
||||
inline auto stack(uint8 address) const -> uint16;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ ControllerPort controllerPort2;
|
|||
#include "super-scope/super-scope.cpp"
|
||||
#include "justifier/justifier.cpp"
|
||||
|
||||
Controller::Controller(bool port) : port(port) {
|
||||
Controller::Controller(uint port) : port(port) {
|
||||
if(!handle()) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
|
@ -33,15 +33,16 @@ auto Controller::main() -> void {
|
|||
|
||||
auto Controller::iobit() -> bool {
|
||||
switch(port) {
|
||||
case Controller::Port1: return cpu.pio() & 0x40;
|
||||
case Controller::Port2: return cpu.pio() & 0x80;
|
||||
case ID::Port::Controller1: return cpu.pio() & 0x40;
|
||||
case ID::Port::Controller2: return cpu.pio() & 0x80;
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
auto Controller::iobit(bool data) -> void {
|
||||
switch(port) {
|
||||
case Controller::Port1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break;
|
||||
case Controller::Port2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break;
|
||||
case ID::Port::Controller1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break;
|
||||
case ID::Port::Controller2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
// 7: gnd
|
||||
|
||||
struct Controller : Thread {
|
||||
enum : bool { Port1 = 0, Port2 = 1 };
|
||||
|
||||
Controller(bool port);
|
||||
Controller(uint port);
|
||||
virtual ~Controller();
|
||||
static auto Enter() -> void;
|
||||
|
||||
|
@ -24,7 +22,7 @@ struct Controller : Thread {
|
|||
virtual auto data() -> uint2 { return 0; }
|
||||
virtual auto latch(bool data) -> void {}
|
||||
|
||||
const bool port;
|
||||
const uint port;
|
||||
};
|
||||
|
||||
struct ControllerPort {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Gamepad::Gamepad(bool port) : Controller(port) {
|
||||
Gamepad::Gamepad(uint port) : Controller(port) {
|
||||
latched = 0;
|
||||
counter = 0;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Gamepad : Controller {
|
|||
Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start,
|
||||
};
|
||||
|
||||
Gamepad(bool port);
|
||||
Gamepad(uint port);
|
||||
|
||||
auto data() -> uint2;
|
||||
auto latch(bool data) -> void;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
Justifier::Justifier(bool port, bool chained):
|
||||
Justifier::Justifier(uint port, bool chained):
|
||||
Controller(port),
|
||||
chained(chained),
|
||||
device(!chained ? ID::Device::Justifier : ID::Device::Justifiers)
|
||||
{
|
||||
create(Controller::Enter, 21'477'272);
|
||||
create(Controller::Enter, system.cpuFrequency());
|
||||
latched = 0;
|
||||
counter = 0;
|
||||
active = 0;
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Justifier : Controller {
|
|||
X, Y, Trigger, Start,
|
||||
};
|
||||
|
||||
Justifier(bool port, bool chained);
|
||||
Justifier(uint port, bool chained);
|
||||
~Justifier();
|
||||
|
||||
auto main() -> void;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Mouse::Mouse(bool port) : Controller(port) {
|
||||
Mouse::Mouse(uint port) : Controller(port) {
|
||||
latched = 0;
|
||||
counter = 0;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Mouse : Controller {
|
|||
X, Y, Left, Right,
|
||||
};
|
||||
|
||||
Mouse(bool port);
|
||||
Mouse(uint port);
|
||||
|
||||
auto data() -> uint2;
|
||||
auto latch(bool data) -> void;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
SuperMultitap::SuperMultitap(bool port) : Controller(port) {
|
||||
SuperMultitap::SuperMultitap(uint port) : Controller(port) {
|
||||
latched = 0;
|
||||
counter1 = 0;
|
||||
counter2 = 0;
|
||||
|
|
|
@ -3,7 +3,7 @@ struct SuperMultitap : Controller {
|
|||
Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start,
|
||||
};
|
||||
|
||||
SuperMultitap(bool port);
|
||||
SuperMultitap(uint port);
|
||||
|
||||
auto data() -> uint2;
|
||||
auto latch(bool data) -> void;
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
//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.
|
||||
|
||||
SuperScope::SuperScope(bool port) : Controller(port) {
|
||||
create(Controller::Enter, 21'477'272);
|
||||
SuperScope::SuperScope(uint port) : Controller(port) {
|
||||
create(Controller::Enter, system.cpuFrequency());
|
||||
sprite = Emulator::video.createSprite(32, 32);
|
||||
sprite->setPixels(Resource::Sprite::CrosshairGreen);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ struct SuperScope : Controller {
|
|||
X, Y, Trigger, Cursor, Turbo, Pause,
|
||||
};
|
||||
|
||||
SuperScope(bool port);
|
||||
SuperScope(uint port);
|
||||
~SuperScope();
|
||||
|
||||
auto main() -> void;
|
||||
|
|
|
@ -116,9 +116,6 @@ auto CPU::power() -> void {
|
|||
channel.hdmaDoTransfer = false;
|
||||
}
|
||||
|
||||
//$2140-217f
|
||||
for(auto& port : io.port) port = 0x00;
|
||||
|
||||
//$2181-$2183
|
||||
io.wramAddress = 0x000000;
|
||||
|
||||
|
|
|
@ -4,11 +4,9 @@ struct CPU : Processor::WDC65816, Thread, PPUcounter {
|
|||
auto joylatch() const -> bool;
|
||||
auto synchronizing() const -> bool override;
|
||||
|
||||
//cpu.cpp
|
||||
CPU();
|
||||
|
||||
auto readPort(uint2 port) const -> uint8;
|
||||
auto writePort(uint2 port, uint8 data) -> void;
|
||||
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto load(Markup::Node) -> bool;
|
||||
|
@ -135,9 +133,6 @@ private:
|
|||
} status;
|
||||
|
||||
struct IO {
|
||||
//$2140-217f
|
||||
uint8 port[4];
|
||||
|
||||
//$2181-$2183
|
||||
uint17 wramAddress;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
auto CPU::readAPU(uint24 addr, uint8 data) -> uint8 {
|
||||
synchronize(smp);
|
||||
return smp.readPort(addr.bits(0,1));
|
||||
return smp.portRead(addr.bits(0,1));
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
|
|
|
@ -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 {
|
||||
status.clockCount = 6;
|
||||
dmaEdge();
|
||||
|
|
|
@ -49,8 +49,6 @@ auto CPU::serialize(serializer& s) -> void {
|
|||
s.integer(status.autoJoypadLatch);
|
||||
s.integer(status.autoJoypadCounter);
|
||||
|
||||
s.array(io.port);
|
||||
|
||||
s.integer(io.wramAddress);
|
||||
|
||||
s.integer(io.joypadStrobeLatch);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
auto DSP::brrDecode(Voice& v) -> void {
|
||||
//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 scale = (state._brrHeader >> 4);
|
||||
|
|
|
@ -232,6 +232,8 @@ auto DSP::power() -> void {
|
|||
create(Enter, system.apuFrequency());
|
||||
stream = Emulator::audio.createStream(2, frequency() / 768.0);
|
||||
|
||||
for(auto& byte : apuram) byte = random(0x00);
|
||||
|
||||
memory::fill(&state, sizeof(State));
|
||||
state.noise = 0x4000;
|
||||
state.echoHistoryOffset = 0;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
struct DSP : Thread {
|
||||
shared_pointer<Emulator::Stream> stream;
|
||||
uint8 apuram[64 * 1024];
|
||||
|
||||
DSP();
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ auto DSP::echoOutput(bool channel) -> int {
|
|||
|
||||
auto DSP::echoRead(bool channel) -> void {
|
||||
uint addr = state._echoPointer + channel * 2;
|
||||
uint8 lo = smp.apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = smp.apuram[(uint16)(addr + 1)];
|
||||
uint8 lo = apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = apuram[(uint16)(addr + 1)];
|
||||
int s = (int16)((hi << 8) + lo);
|
||||
state.echoHistory[channel][state.echoHistoryOffset] = s >> 1;
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ auto DSP::echoWrite(bool channel) -> void {
|
|||
if(!(state._echoDisabled & 0x20)) {
|
||||
uint addr = state._echoPointer + channel * 2;
|
||||
int s = state._echoOut[channel];
|
||||
smp.apuram[(uint16)(addr + 0)] = s;
|
||||
smp.apuram[(uint16)(addr + 1)] = s >> 8;
|
||||
apuram[(uint16)(addr + 0)] = s;
|
||||
apuram[(uint16)(addr + 1)] = s >> 8;
|
||||
}
|
||||
|
||||
state._echoOut[channel] = 0;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
void DSP::serialize(serializer& s) {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(apuram);
|
||||
|
||||
s.array(state.regs, 128);
|
||||
s.array(state.echoHistory[0]);
|
||||
s.array(state.echoHistory[1]);
|
||||
|
|
|
@ -22,8 +22,8 @@ auto DSP::voice2(Voice& v) -> void {
|
|||
//read sample pointer (ignored if not needed)
|
||||
uint16 addr = state._dirAddress;
|
||||
if(!v.konDelay) addr += 2;
|
||||
uint8 lo = smp.apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = smp.apuram[(uint16)(addr + 1)];
|
||||
uint8 lo = apuram[(uint16)(addr + 0)];
|
||||
uint8 hi = apuram[(uint16)(addr + 1)];
|
||||
state._brrNextAddress = ((hi << 8) + lo);
|
||||
|
||||
state._adsr0 = VREG(ADSR0);
|
||||
|
@ -43,8 +43,8 @@ auto DSP::voice3a(Voice& v) -> void {
|
|||
}
|
||||
|
||||
auto DSP::voice3b(Voice& v) -> void {
|
||||
state._brrByte = smp.apuram[(uint16)(v.brrAddress + v.brrOffset)];
|
||||
state._brrHeader = smp.apuram[(uint16)(v.brrAddress)];
|
||||
state._brrByte = apuram[(uint16)(v.brrAddress + v.brrOffset)];
|
||||
state._brrHeader = apuram[(uint16)(v.brrAddress)];
|
||||
}
|
||||
|
||||
auto DSP::voice3c(Voice& v) -> void {
|
||||
|
|
|
@ -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(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
|
||||
if(io.ramWritable && !io.ramDisable) apuram[addr] = data;
|
||||
if(io.ramWritable && !io.ramDisable) dsp.apuram[addr] = data;
|
||||
}
|
||||
|
||||
auto SMP::readPort(uint2 port) const -> uint8 {
|
||||
return io.port[0xf4 + port];
|
||||
auto SMP::portRead(uint2 port) const -> uint8 {
|
||||
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 {
|
||||
io.port[0xf4 + port] = data;
|
||||
auto SMP::portWrite(uint2 port, uint8 data) -> void {
|
||||
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;
|
||||
|
||||
switch(addr) {
|
||||
case 0xf0: //TEST -- write-only register
|
||||
case 0xf0: //TEST (write-only register)
|
||||
return 0x00;
|
||||
|
||||
case 0xf1: //CONTROL -- write-only register
|
||||
case 0xf1: //CONTROL (write-only register)
|
||||
return 0x00;
|
||||
|
||||
case 0xf2: //DSPADDR
|
||||
|
@ -35,55 +42,64 @@ auto SMP::readBus(uint16 addr) -> uint8 {
|
|||
return dsp.read(io.dspAddr & 0x7f);
|
||||
|
||||
case 0xf4: //CPUIO0
|
||||
synchronize(cpu);
|
||||
return io.apu0;
|
||||
|
||||
case 0xf5: //CPUIO1
|
||||
synchronize(cpu);
|
||||
return io.apu1;
|
||||
|
||||
case 0xf6: //CPUIO2
|
||||
synchronize(cpu);
|
||||
return io.apu2;
|
||||
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize(cpu);
|
||||
return cpu.readPort(addr);
|
||||
return io.apu3;
|
||||
|
||||
case 0xf8: //RAM0
|
||||
return io.ram00f8;
|
||||
case 0xf8: //AUXIO4
|
||||
return io.aux4;
|
||||
|
||||
case 0xf9: //RAM1
|
||||
return io.ram00f9;
|
||||
case 0xf9: //AUXIO5
|
||||
return io.aux5;
|
||||
|
||||
case 0xfa: //T0TARGET
|
||||
case 0xfb: //T1TARGET
|
||||
case 0xfc: //T2TARGET -- write-only registers
|
||||
case 0xfc: //T2TARGET (write-only registers)
|
||||
return 0x00;
|
||||
|
||||
case 0xfd: //T0OUT -- 4-bit counter value
|
||||
case 0xfd: //T0OUT (4-bit counter value)
|
||||
result = timer0.stage3;
|
||||
timer0.stage3 = 0;
|
||||
return result;
|
||||
|
||||
case 0xfe: //T1OUT -- 4-bit counter value
|
||||
case 0xfe: //T1OUT (4-bit counter value)
|
||||
result = timer1.stage3;
|
||||
timer1.stage3 = 0;
|
||||
return result;
|
||||
|
||||
case 0xff: //T2OUT -- 4-bit counter value
|
||||
case 0xff: //T2OUT (4-bit counter value)
|
||||
result = timer2.stage3;
|
||||
timer2.stage3 = 0;
|
||||
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) {
|
||||
case 0xf0: //TEST
|
||||
if(r.p.p) break; //writes only valid when P flag is clear
|
||||
|
||||
io.clockSpeed = (data >> 6) & 3;
|
||||
io.timerSpeed = (data >> 4) & 3;
|
||||
io.timersEnable = data & 0x08;
|
||||
io.ramDisable = data & 0x04;
|
||||
io.ramWritable = data & 0x02;
|
||||
io.timersDisable = data & 0x01;
|
||||
io.timersDisable = data.bit (0);
|
||||
io.ramWritable = data.bit (1);
|
||||
io.ramDisable = data.bit (2);
|
||||
io.timersEnable = data.bit (3);
|
||||
io.ramSpeed = data.bits(4,5);
|
||||
io.romIOSpeed = data.bits(6,7);
|
||||
|
||||
io.timerStep = (1 << io.clockSpeed) + (2 << io.timerSpeed);
|
||||
io.timerStep = (1 << io.romIOSpeed) + (2 << io.ramSpeed);
|
||||
|
||||
timer0.synchronizeStage1();
|
||||
timer1.synchronizeStage1();
|
||||
|
@ -91,40 +107,38 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
break;
|
||||
|
||||
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
|
||||
if(!timer2.enable && (data & 0x04)) {
|
||||
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)) {
|
||||
if(!timer0.enable && data.bit(0)) {
|
||||
timer0.stage2 = 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;
|
||||
|
||||
case 0xf2: //DSPADDR
|
||||
|
@ -137,19 +151,31 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
break;
|
||||
|
||||
case 0xf4: //CPUIO0
|
||||
synchronize(cpu);
|
||||
io.cpu0 = data;
|
||||
break;
|
||||
|
||||
case 0xf5: //CPUIO1
|
||||
synchronize(cpu);
|
||||
io.cpu1 = data;
|
||||
break;
|
||||
|
||||
case 0xf6: //CPUIO2
|
||||
synchronize(cpu);
|
||||
io.cpu2 = data;
|
||||
break;
|
||||
|
||||
case 0xf7: //CPUIO3
|
||||
synchronize(cpu);
|
||||
writePort(addr, data);
|
||||
io.cpu3 = data;
|
||||
break;
|
||||
|
||||
case 0xf8: //RAM0
|
||||
io.ram00f8 = data;
|
||||
case 0xf8: //AUXIO4
|
||||
io.aux4 = data;
|
||||
break;
|
||||
|
||||
case 0xf9: //RAM1
|
||||
io.ram00f9 = data;
|
||||
case 0xf9: //AUXIO5
|
||||
io.aux5 = data;
|
||||
break;
|
||||
|
||||
case 0xfa: //T0TARGET
|
||||
|
@ -166,34 +192,41 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
|||
|
||||
case 0xfd: //T0OUT
|
||||
case 0xfe: //T1OUT
|
||||
case 0xff: //T2OUT -- read-only registers
|
||||
case 0xff: //T2OUT (read-only registers)
|
||||
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 {
|
||||
step(24);
|
||||
auto SMP::speed(uint16 addr) const -> uint {
|
||||
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();
|
||||
}
|
||||
|
||||
auto SMP::read(uint16 addr) -> uint8 {
|
||||
step(12);
|
||||
uint8 data = readBus(addr);
|
||||
step(12);
|
||||
step(24 * speed(addr));
|
||||
uint8 data = busRead(addr);
|
||||
cycleEdge();
|
||||
return data;
|
||||
}
|
||||
|
||||
auto SMP::write(uint16 addr, uint8 data) -> void {
|
||||
step(24);
|
||||
writeBus(addr, data);
|
||||
step(24 * speed(addr));
|
||||
busWrite(addr, data);
|
||||
cycleEdge();
|
||||
}
|
||||
|
||||
auto SMP::readDisassembler(uint16 addr) -> uint8 {
|
||||
if((addr & 0xfff0) == 0x00f0) return 0x00;
|
||||
if((addr & 0xffc0) == 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
||||
return apuram[addr];
|
||||
if(addr >= 0xffc0 && io.iplromEnable) return iplrom[addr & 0x3f];
|
||||
return dsp.apuram[addr];
|
||||
}
|
||||
|
|
|
@ -2,27 +2,33 @@ auto SMP::serialize(serializer& s) -> void {
|
|||
SPC700::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(apuram);
|
||||
|
||||
s.integer(io.clockCounter);
|
||||
s.integer(io.dspCounter);
|
||||
s.integer(io.timerStep);
|
||||
|
||||
s.integer(io.clockSpeed);
|
||||
s.integer(io.timerSpeed);
|
||||
s.integer(io.timersEnable);
|
||||
s.integer(io.ramDisable);
|
||||
s.integer(io.ramWritable);
|
||||
s.integer(io.apu0);
|
||||
s.integer(io.apu1);
|
||||
s.integer(io.apu2);
|
||||
s.integer(io.apu3);
|
||||
|
||||
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.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.ram00f9);
|
||||
s.integer(io.aux4);
|
||||
s.integer(io.aux5);
|
||||
|
||||
s.integer(timer0.stage0);
|
||||
s.integer(timer0.stage1);
|
||||
|
|
|
@ -39,19 +39,24 @@ auto SMP::power() -> void {
|
|||
r.pc.byte.l = iplrom[62];
|
||||
r.pc.byte.h = iplrom[63];
|
||||
|
||||
for(auto& byte : apuram) byte = random(0x00);
|
||||
|
||||
//timing
|
||||
io.clockCounter = 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
|
||||
io.clockSpeed = 0;
|
||||
io.timerSpeed = 0;
|
||||
io.timersEnable = true;
|
||||
io.ramDisable = false;
|
||||
io.ramWritable = true;
|
||||
io.timersDisable = false;
|
||||
io.ramWritable = true;
|
||||
io.ramDisable = false;
|
||||
io.timersEnable = true;
|
||||
io.ramSpeed = 0;
|
||||
io.romIOSpeed = 0;
|
||||
|
||||
//$00f1
|
||||
io.iplromEnable = true;
|
||||
|
@ -60,14 +65,14 @@ auto SMP::power() -> void {
|
|||
io.dspAddr = 0x00;
|
||||
|
||||
//$00f4-00f7
|
||||
io.port[0] = 0x00;
|
||||
io.port[1] = 0x00;
|
||||
io.port[2] = 0x00;
|
||||
io.port[3] = 0x00;
|
||||
io.cpu0 = 0x00;
|
||||
io.cpu1 = 0x00;
|
||||
io.cpu2 = 0x00;
|
||||
io.cpu3 = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
io.ram00f8 = 0x00;
|
||||
io.ram00f9 = 0x00;
|
||||
//$00f8-$00f9
|
||||
io.aux4 = 0x00;
|
||||
io.aux5 = 0x00;
|
||||
|
||||
timer0.stage0 = 0;
|
||||
timer1.stage0 = 0;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
//Sony CXP1100Q-1
|
||||
|
||||
struct SMP : Processor::SPC700, Thread {
|
||||
uint8 iplrom[64];
|
||||
|
||||
//smp.cpp
|
||||
auto synchronizing() const -> bool override;
|
||||
|
||||
auto readPort(uint2 port) const -> uint8;
|
||||
auto writePort(uint2 port, uint8 data) -> void;
|
||||
auto portRead(uint2 port) const -> uint8;
|
||||
auto portWrite(uint2 port, uint8 data) -> void;
|
||||
|
||||
auto main() -> void;
|
||||
auto load(Markup::Node) -> bool;
|
||||
|
@ -14,9 +16,6 @@ struct SMP : Processor::SPC700, Thread {
|
|||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 iplrom[64];
|
||||
uint8 apuram[64 * 1024];
|
||||
|
||||
private:
|
||||
struct IO {
|
||||
//timing
|
||||
|
@ -24,13 +23,19 @@ private:
|
|||
uint dspCounter;
|
||||
uint timerStep;
|
||||
|
||||
//external
|
||||
uint8 apu0;
|
||||
uint8 apu1;
|
||||
uint8 apu2;
|
||||
uint8 apu3;
|
||||
|
||||
//$00f0
|
||||
uint8 clockSpeed;
|
||||
uint8 timerSpeed;
|
||||
bool timersEnable;
|
||||
bool ramDisable;
|
||||
bool ramWritable;
|
||||
bool timersDisable;
|
||||
uint1 timersDisable;
|
||||
uint1 ramWritable;
|
||||
uint1 ramDisable;
|
||||
uint1 timersEnable;
|
||||
uint2 ramSpeed;
|
||||
uint2 romIOSpeed;
|
||||
|
||||
//$00f1
|
||||
bool iplromEnable;
|
||||
|
@ -39,23 +44,27 @@ private:
|
|||
uint8 dspAddr;
|
||||
|
||||
//$00f4-00f7
|
||||
uint8 port[4];
|
||||
uint8 cpu0;
|
||||
uint8 cpu1;
|
||||
uint8 cpu2;
|
||||
uint8 cpu3;
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 ram00f8;
|
||||
uint8 ram00f9;
|
||||
//$00f8-00f9
|
||||
uint8 aux4;
|
||||
uint8 aux5;
|
||||
} io;
|
||||
|
||||
static auto Enter() -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto readRAM(uint16 addr) -> uint8;
|
||||
auto writeRAM(uint16 addr, uint8 data) -> void;
|
||||
auto ramRead(uint16 addr) -> uint8;
|
||||
auto ramWrite(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto readBus(uint16 addr) -> uint8;
|
||||
auto writeBus(uint16 addr, uint8 data) -> void;
|
||||
auto busRead(uint16 addr) -> uint8;
|
||||
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 write(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
|
|
|
@ -15,15 +15,6 @@ auto SMP::cycleEdge() -> void {
|
|||
timer0.tick();
|
||||
timer1.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 {
|
||||
|
|
Loading…
Reference in New Issue