mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Starts to introduce a new grammar for ROM requests.
They can be optional, and chained together in AND or OR combinations. A central catalogue knows the definitions of all ROMs.
This commit is contained in:
parent
3858e79579
commit
a30eeaab6a
@ -787,45 +787,41 @@ template <bool has_fdc> class ConcreteMachine:
|
||||
ay_.ay().set_port_handler(&key_state_);
|
||||
|
||||
// construct the list of necessary ROMs
|
||||
const std::string machine_name = "AmstradCPC";
|
||||
std::vector<ROMMachine::ROM> required_roms = {
|
||||
ROMMachine::ROM(machine_name, "the Amstrad Disk Operating System", "amsdos.rom", 16*1024, 0x1fe22ecd)
|
||||
};
|
||||
std::string model_number;
|
||||
uint32_t crcs[2];
|
||||
bool has_amsdos = false;
|
||||
ROM::Name firmware, basic;
|
||||
|
||||
switch(target.model) {
|
||||
default:
|
||||
model_number = "6128";
|
||||
has_128k_ = true;
|
||||
crcs[0] = 0x0219bb74;
|
||||
crcs[1] = 0xca6af63d;
|
||||
break;
|
||||
case Analyser::Static::AmstradCPC::Target::Model::CPC464:
|
||||
model_number = "464";
|
||||
has_128k_ = false;
|
||||
crcs[0] = 0x815752df;
|
||||
crcs[1] = 0x7d9a3bac;
|
||||
firmware = ROM::Name::CPC464Firmware;
|
||||
basic = ROM::Name::CPC464BASIC;
|
||||
break;
|
||||
case Analyser::Static::AmstradCPC::Target::Model::CPC664:
|
||||
model_number = "664";
|
||||
has_128k_ = false;
|
||||
crcs[0] = 0x3f5a6dc4;
|
||||
crcs[1] = 0x32fee492;
|
||||
firmware = ROM::Name::CPC664Firmware;
|
||||
basic = ROM::Name::CPC664BASIC;
|
||||
break;
|
||||
default:
|
||||
firmware = ROM::Name::CPC6128Firmware;
|
||||
basic = ROM::Name::CPC6128BASIC;
|
||||
break;
|
||||
}
|
||||
required_roms.emplace_back(machine_name, "the CPC " + model_number + " firmware", "os" + model_number + ".rom", 16*1024, crcs[0]);
|
||||
required_roms.emplace_back(machine_name, "the CPC " + model_number + " BASIC ROM", "basic" + model_number + ".rom", 16*1024, crcs[1]);
|
||||
|
||||
// fetch and verify the ROMs
|
||||
const auto roms = rom_fetcher(required_roms);
|
||||
|
||||
for(std::size_t index = 0; index < roms.size(); ++index) {
|
||||
auto &data = roms[index];
|
||||
if(!data) throw ROMMachine::Error::MissingROMs;
|
||||
roms_[index] = std::move(*data);
|
||||
roms_[index].resize(16384);
|
||||
ROM::Request request = ROM::Request(firmware) && ROM::Request(basic);
|
||||
if(has_amsdos) {
|
||||
request = request && ROM::Request(ROM::Name::AMSDOS);
|
||||
}
|
||||
|
||||
// Fetch and verify the ROMs.
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
if(has_amsdos) {
|
||||
roms_[ROMType::AMSDOS] = *roms.find(ROM::Name::AMSDOS);
|
||||
}
|
||||
roms_[ROMType::OS] = *roms.find(firmware);
|
||||
roms_[ROMType::BASIC] = *roms.find(basic);
|
||||
|
||||
// Establish default memory map
|
||||
upper_rom_is_paged_ = true;
|
||||
upper_rom_ = ROMType::BASIC;
|
||||
|
@ -377,49 +377,49 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
|
||||
|
||||
// Pick the required ROMs.
|
||||
using Target = Analyser::Static::AppleII::Target;
|
||||
const std::string machine_name = "AppleII";
|
||||
std::vector<ROMMachine::ROM> rom_descriptions;
|
||||
size_t rom_size = 12*1024;
|
||||
ROM::Name character, system;
|
||||
|
||||
switch(target.model) {
|
||||
default:
|
||||
rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::II));
|
||||
rom_descriptions.emplace_back(machine_name, "the original Apple II ROM", "apple2o.rom", 12*1024, 0xba210588);
|
||||
character = ROM::Name::AppleIICharacter;
|
||||
system = ROM::Name::AppleIIOriginal;
|
||||
break;
|
||||
case Target::Model::IIplus:
|
||||
rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::II));
|
||||
rom_descriptions.emplace_back(machine_name, "the Apple II+ ROM", "apple2.rom", 12*1024, 0xf66f9c26);
|
||||
character = ROM::Name::AppleIICharacter;
|
||||
system = ROM::Name::AppleIIPlus;
|
||||
break;
|
||||
case Target::Model::IIe:
|
||||
rom_size += 3840;
|
||||
rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::IIe));
|
||||
rom_descriptions.emplace_back(machine_name, "the Apple IIe ROM", "apple2eu.rom", 32*1024, 0xe12be18d);
|
||||
character = ROM::Name::AppleIIeCharacter;
|
||||
system = ROM::Name::AppleIIe;
|
||||
break;
|
||||
case Target::Model::EnhancedIIe:
|
||||
rom_size += 3840;
|
||||
rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::EnhancedIIe));
|
||||
rom_descriptions.emplace_back(machine_name, "the Enhanced Apple IIe ROM", "apple2e.rom", 32*1024, 0x65989942);
|
||||
character = ROM::Name::AppleIIEnhancedECharacter;
|
||||
system = ROM::Name::AppleIIEnhancedE;
|
||||
break;
|
||||
}
|
||||
const auto roms = rom_fetcher(rom_descriptions);
|
||||
|
||||
// Try to install a Disk II card now, before checking the ROM list,
|
||||
// to make sure that Disk II dependencies have been communicated.
|
||||
if(target.disk_controller != Target::DiskController::None) {
|
||||
ROM::Request request = ROM::Request(character) && ROM::Request(system);
|
||||
|
||||
// Add the necessary Disk II requests if appropriate.
|
||||
const bool has_disk_controller = target.disk_controller != Target::DiskController::None;
|
||||
const bool is_sixteen_sector = target.disk_controller == Target::DiskController::SixteenSector;
|
||||
if(has_disk_controller) {
|
||||
// Apple recommended slot 6 for the (first) Disk II.
|
||||
install_card(6, new Apple::II::DiskIICard(rom_fetcher, target.disk_controller == Target::DiskController::SixteenSector));
|
||||
request = request && DiskIICard::rom_request(is_sixteen_sector);
|
||||
}
|
||||
|
||||
// Now, check and move the ROMs.
|
||||
if(!roms[0] || !roms[1]) {
|
||||
// Request, validate and install ROMs.
|
||||
auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
rom_ = std::move(*roms[1]);
|
||||
if(rom_.size() > rom_size) {
|
||||
rom_.erase(rom_.begin(), rom_.end() - off_t(rom_size));
|
||||
if(has_disk_controller) {
|
||||
install_card(6, new Apple::II::DiskIICard(roms, is_sixteen_sector));
|
||||
}
|
||||
|
||||
video_.set_character_rom(*roms[0]);
|
||||
rom_ = std::move(*roms.find(system));
|
||||
video_.set_character_rom(*roms.find(character));
|
||||
|
||||
// Set up the default memory blocks. On a II or II+ these values will never change.
|
||||
// On a IIe they'll be affected by selection of auxiliary RAM.
|
||||
|
@ -10,27 +10,34 @@
|
||||
|
||||
using namespace Apple::II;
|
||||
|
||||
DiskIICard::DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector) : diskii_(2045454) {
|
||||
std::vector<std::unique_ptr<std::vector<uint8_t>>> roms;
|
||||
ROM::Request DiskIICard::rom_request(bool is_16_sector) {
|
||||
if(is_16_sector) {
|
||||
roms = rom_fetcher({
|
||||
{"DiskII", "the Disk II 16-sector boot ROM", "boot-16.rom", 256, 0xce7144f6},
|
||||
{"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 } }
|
||||
});
|
||||
return ROM::Request(ROM::Name::DiskIIBoot16Sector) && ROM::Request(ROM::Name::DiskIIStateMachine16Sector);
|
||||
} else {
|
||||
roms = rom_fetcher({
|
||||
{"DiskII", "the Disk II 13-sector boot ROM", "boot-13.rom", 256, 0xd34eb2ff},
|
||||
{"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 } }
|
||||
// {"DiskII", "the Disk II 13-sector state machine ROM", "state-machine-13.rom", 256, 0x62e22620 }
|
||||
/* TODO: once the DiskII knows how to decode common images of the 13-sector state machine, use that instead of the 16-sector. */
|
||||
});
|
||||
/* TODO: once the DiskII knows how to decode common images of the 13-sector state machine, use that instead of the 16-sector. */
|
||||
return ROM::Request(ROM::Name::DiskIIBoot13Sector) && ROM::Request(ROM::Name::DiskIIStateMachine16Sector);
|
||||
}
|
||||
if(!roms[0] || !roms[1]) {
|
||||
}
|
||||
|
||||
|
||||
DiskIICard::DiskIICard(ROM::Map &map, bool is_16_sector) : diskii_(2045454) {
|
||||
std::vector<std::unique_ptr<std::vector<uint8_t>>> roms;
|
||||
ROM::Map::iterator state_machine, boot;
|
||||
if(is_16_sector) {
|
||||
state_machine = map.find(ROM::Name::DiskIIStateMachine16Sector);
|
||||
boot = map.find(ROM::Name::DiskIIBoot16Sector);
|
||||
} else {
|
||||
// TODO: see above re: 13-sector state machine.
|
||||
state_machine = map.find(ROM::Name::DiskIIStateMachine16Sector);
|
||||
boot = map.find(ROM::Name::DiskIIBoot13Sector);
|
||||
}
|
||||
|
||||
if(state_machine == map.end() || boot == map.end()) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
boot_ = std::move(*roms[0]);
|
||||
diskii_.set_state_machine(*roms[1]);
|
||||
boot_ = std::move(boot->second);
|
||||
diskii_.set_state_machine(state_machine->second);
|
||||
set_select_constraints(None);
|
||||
diskii_.set_clocking_hint_observer(this);
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ namespace II {
|
||||
|
||||
class DiskIICard: public Card, public ClockingHint::Observer {
|
||||
public:
|
||||
DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector);
|
||||
static ROM::Request rom_request(bool is_16_sector);
|
||||
DiskIICard(ROM::Map &, bool is_16_sector);
|
||||
|
||||
void perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) final;
|
||||
void run_for(Cycles cycles, int stretches) final;
|
||||
|
@ -228,36 +228,6 @@ template <typename TimeUnit> class VideoSwitches {
|
||||
return external_.annunciator_3;
|
||||
}
|
||||
|
||||
enum class CharacterROM {
|
||||
/// The ROM that shipped with both the Apple II and the II+.
|
||||
II,
|
||||
/// The ROM that shipped with the original IIe.
|
||||
IIe,
|
||||
/// The ROM that shipped with the Enhanced IIe.
|
||||
EnhancedIIe,
|
||||
/// The ROM that shipped with the IIgs.
|
||||
IIgs
|
||||
};
|
||||
|
||||
/// @returns A file-level description of @c rom.
|
||||
static ROMMachine::ROM rom_description(CharacterROM rom) {
|
||||
const std::string machine_name = "AppleII";
|
||||
switch(rom) {
|
||||
case CharacterROM::II:
|
||||
return ROMMachine::ROM(machine_name, "the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6);
|
||||
|
||||
case CharacterROM::IIe:
|
||||
return ROMMachine::ROM(machine_name, "the Apple IIe character ROM", "apple2eu-character.rom", 4*1024, 0x816a86f1);
|
||||
|
||||
default: // To appease GCC.
|
||||
case CharacterROM::EnhancedIIe:
|
||||
return ROMMachine::ROM(machine_name, "the Enhanced Apple IIe character ROM", "apple2e-character.rom", 4*1024, 0x2651014d);
|
||||
|
||||
case CharacterROM::IIgs:
|
||||
return ROMMachine::ROM(machine_name, "the Apple IIgs character ROM", "apple2gs.chr", 4*1024, 0x91e53cd8);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the character ROM for this video output.
|
||||
void set_character_rom(const std::vector<uint8_t> &rom) {
|
||||
character_rom_ = rom;
|
||||
|
@ -189,31 +189,23 @@ class ConcreteMachine:
|
||||
speaker_.set_input_rate(float(CLOCK_RATE) / float(audio_divider));
|
||||
|
||||
using Target = Analyser::Static::AppleIIgs::Target;
|
||||
std::vector<ROMMachine::ROM> rom_descriptions;
|
||||
const std::string machine_name = "AppleIIgs";
|
||||
ROM::Name system;
|
||||
switch(target.model) {
|
||||
case Target::Model::ROM00:
|
||||
/* TODO */
|
||||
case Target::Model::ROM01:
|
||||
rom_descriptions.emplace_back(machine_name, "the Apple IIgs ROM01", "apple2gs.rom", 128*1024, 0x42f124b0);
|
||||
break;
|
||||
|
||||
case Target::Model::ROM03:
|
||||
rom_descriptions.emplace_back(machine_name, "the Apple IIgs ROM03", "apple2gs.rom2", 256*1024, 0xde7ddf29);
|
||||
break;
|
||||
case Target::Model::ROM00: system = ROM::Name::AppleIIgsROM00; break;
|
||||
case Target::Model::ROM01: system = ROM::Name::AppleIIgsROM01; break;
|
||||
case Target::Model::ROM03: system = ROM::Name::AppleIIgsROM03; break;
|
||||
}
|
||||
rom_descriptions.push_back(video_->rom_description(Video::Video::CharacterROM::EnhancedIIe));
|
||||
constexpr ROM::Name characters = ROM::Name::AppleIIEnhancedECharacter;
|
||||
constexpr ROM::Name microcontroller = ROM::Name::AppleIIgsMicrocontrollerROM03;
|
||||
|
||||
// TODO: pick a different ADB ROM for earlier machine revisions?
|
||||
rom_descriptions.emplace_back(machine_name, "the Apple IIgs ADB microcontroller ROM", "341s0632-2", 4*1024, 0xe1c11fb0);
|
||||
|
||||
const auto roms = rom_fetcher(rom_descriptions);
|
||||
if(!roms[0] || !roms[1] || !roms[2]) {
|
||||
ROM::Request request = ROM::Request(system) && ROM::Request(characters) && ROM::Request(microcontroller);
|
||||
auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
rom_ = *roms[0];
|
||||
video_->set_character_rom(*roms[1]);
|
||||
adb_glu_->set_microcontroller_rom(*roms[2]);
|
||||
rom_ = roms.find(system)->second;
|
||||
video_->set_character_rom(roms.find(characters)->second);
|
||||
adb_glu_->set_microcontroller_rom(roms.find(microcontroller)->second);
|
||||
|
||||
// Run only the currently-interesting self test.
|
||||
// rom_[0x36402] = 2;
|
||||
|
@ -96,25 +96,24 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
using Model = Analyser::Static::Macintosh::Target::Model;
|
||||
const std::string machine_name = "Macintosh";
|
||||
uint32_t ram_size, rom_size;
|
||||
std::vector<ROMMachine::ROM> rom_descriptions;
|
||||
ROM::Name rom_name;
|
||||
switch(model) {
|
||||
default:
|
||||
case Model::Mac128k:
|
||||
ram_size = 128*1024;
|
||||
rom_size = 64*1024;
|
||||
rom_descriptions.emplace_back(machine_name, "the Macintosh 128k ROM", "mac128k.rom", 64*1024, 0x6d0c8a28);
|
||||
rom_name = ROM::Name::Macintosh128k;
|
||||
break;
|
||||
case Model::Mac512k:
|
||||
ram_size = 512*1024;
|
||||
rom_size = 64*1024;
|
||||
rom_descriptions.emplace_back(machine_name, "the Macintosh 512k ROM", "mac512k.rom", 64*1024, 0xcf759e0d);
|
||||
rom_name = ROM::Name::Macintosh512k;
|
||||
break;
|
||||
case Model::Mac512ke:
|
||||
case Model::MacPlus: {
|
||||
ram_size = ((model == Model::MacPlus) ? 4096 : 512)*1024;
|
||||
rom_size = 128*1024;
|
||||
const std::initializer_list<uint32_t> crc32s = { 0x4fa5b399, 0x7cacd18f, 0xb2102e8e };
|
||||
rom_descriptions.emplace_back(machine_name, "the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s);
|
||||
rom_name = ROM::Name::MacintoshPlus;
|
||||
} break;
|
||||
}
|
||||
ram_mask_ = ram_size - 1;
|
||||
@ -123,12 +122,12 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
||||
video_.set_ram(reinterpret_cast<uint16_t *>(ram_.data()), ram_mask_ >> 1);
|
||||
|
||||
// Grab a copy of the ROM and convert it into big-endian data.
|
||||
const auto roms = rom_fetcher(rom_descriptions);
|
||||
if(!roms[0]) {
|
||||
ROM::Request request(rom_name);
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
roms[0]->resize(rom_size);
|
||||
Memory::PackBigEndian16(*roms[0], rom_);
|
||||
Memory::PackBigEndian16(roms.find(rom_name)->second, rom_);
|
||||
|
||||
// Randomise memory contents.
|
||||
Memory::Fuzz(ram_);
|
||||
|
@ -74,15 +74,13 @@ class ConcreteMachine:
|
||||
video_->set_ram(reinterpret_cast<uint16_t *>(ram_.data()), ram_.size());
|
||||
Memory::Fuzz(ram_);
|
||||
|
||||
std::vector<ROMMachine::ROM> rom_descriptions = {
|
||||
{"AtariST", "the UK TOS 1.00 ROM", "tos100.img", 192*1024, 0x1a586c64}
|
||||
// {"AtariST", "the UK TOS 1.04 ROM", "tos104.img", 192*1024, 0xa50d1d43}
|
||||
};
|
||||
const auto roms = rom_fetcher(rom_descriptions);
|
||||
if(!roms[0]) {
|
||||
constexpr ROM::Name rom_name = ROM::Name::AtariSTTOS100;
|
||||
ROM::Request request(rom_name);
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
Memory::PackBigEndian16(*roms[0], rom_);
|
||||
Memory::PackBigEndian16(roms.find(rom_name)->second, rom_);
|
||||
|
||||
// Set up basic memory map.
|
||||
memory_map_[0] = BusDevice::MostlyRAM;
|
||||
|
@ -127,15 +127,13 @@ class ConcreteMachine:
|
||||
joysticks_.emplace_back(new Joystick);
|
||||
joysticks_.emplace_back(new Joystick);
|
||||
|
||||
const auto roms = rom_fetcher(
|
||||
{ {"ColecoVision", "the ColecoVision BIOS", "coleco.rom", 8*1024, 0x3aa93ef3} });
|
||||
|
||||
if(!roms[0]) {
|
||||
constexpr ROM::Name rom_name = ROM::Name::ColecoVisionBIOS;
|
||||
const ROM::Request request(rom_name);
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
bios_ = *roms[0];
|
||||
bios_.resize(8192);
|
||||
bios_ = roms.find(rom_name)->second;
|
||||
|
||||
if(!target.media.cartridges.empty()) {
|
||||
const auto &segment = target.media.cartridges.front()->get_segments().front();
|
||||
|
@ -41,7 +41,8 @@ namespace C1540 {
|
||||
*/
|
||||
class Machine final: public MachineBase {
|
||||
public:
|
||||
Machine(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher);
|
||||
static ROM::Request rom_request(Personality personality);
|
||||
Machine(Personality personality, const ROM::Map &roms);
|
||||
|
||||
/*!
|
||||
Sets the serial bus to which this drive should attach itself.
|
||||
|
@ -16,7 +16,14 @@
|
||||
|
||||
using namespace Commodore::C1540;
|
||||
|
||||
MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
ROM::Request MachineBase::rom_request(Personality personality) {
|
||||
switch(personality) {
|
||||
case Personality::C1540: return ROM::Request(ROM::Name::Commodore1540);
|
||||
case Personality::C1541: return ROM::Request(ROM::Name::Commodore1541);
|
||||
}
|
||||
}
|
||||
|
||||
MachineBase::MachineBase(Personality personality, const ROM::Map &roms) :
|
||||
Storage::Disk::Controller(1000000),
|
||||
m6502_(*this),
|
||||
serial_port_VIA_port_handler_(new SerialPortVIA(serial_port_VIA_)),
|
||||
@ -39,28 +46,21 @@ MachineBase::MachineBase(Personality personality, const ROMMachine::ROMFetcher &
|
||||
emplace_drive(1000000, 300, 2);
|
||||
set_drive(1);
|
||||
|
||||
std::string device_name;
|
||||
uint32_t crc = 0;
|
||||
ROM::Name rom_name;
|
||||
switch(personality) {
|
||||
case Personality::C1540:
|
||||
device_name = "1540";
|
||||
crc = 0x718d42b1;
|
||||
break;
|
||||
case Personality::C1541:
|
||||
device_name = "1541";
|
||||
crc = 0xfb760019;
|
||||
break;
|
||||
case Personality::C1540: rom_name = ROM::Name::Commodore1540; break;
|
||||
case Personality::C1541: rom_name = ROM::Name::Commodore1541; break;
|
||||
}
|
||||
|
||||
auto roms = rom_fetcher({ {"Commodore1540", "the " + device_name + " ROM", device_name + ".bin", 16*1024, crc} });
|
||||
if(!roms[0]) {
|
||||
auto rom = roms.find(rom_name);
|
||||
if(rom == roms.end()) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
std::memcpy(rom_, roms[0]->data(), std::min(sizeof(rom_), roms[0]->size()));
|
||||
std::memcpy(rom_, roms.find(rom_name)->second.data(), std::min(sizeof(rom_), roms.find(rom_name)->second.size()));
|
||||
}
|
||||
|
||||
Machine::Machine(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
MachineBase(personality, rom_fetcher) {}
|
||||
Machine::Machine(Personality personality, const ROM::Map &roms) :
|
||||
MachineBase(personality, roms) {}
|
||||
|
||||
void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus) {
|
||||
Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus);
|
||||
|
@ -127,7 +127,7 @@ class MachineBase:
|
||||
public Storage::Disk::Controller {
|
||||
|
||||
public:
|
||||
MachineBase(Personality personality, const ROMMachine::ROMFetcher &rom_fetcher);
|
||||
MachineBase(Personality personality, const ROM::Map &roms);
|
||||
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
|
@ -316,53 +316,48 @@ class ConcreteMachine:
|
||||
// Install a joystick.
|
||||
joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_));
|
||||
|
||||
const std::string machine_name = "Vic20";
|
||||
std::vector<ROMMachine::ROM> rom_names = {
|
||||
{machine_name, "the VIC-20 BASIC ROM", "basic.bin", 8*1024, 0xdb4c43c1}
|
||||
};
|
||||
ROM::Request request(ROM::Name::Vic20BASIC);
|
||||
ROM::Name kernel, character;
|
||||
switch(target.region) {
|
||||
default:
|
||||
rom_names.emplace_back(machine_name, "the English-language VIC-20 character ROM", "characters-english.bin", 4*1024, 0x83e032a6);
|
||||
rom_names.emplace_back(machine_name, "the English-language PAL VIC-20 kernel ROM", "kernel-pal.bin", 8*1024, 0x4be07cb4);
|
||||
character = ROM::Name::Vic20EnglishCharacters;
|
||||
kernel = ROM::Name::Vic20EnglishPALKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::American:
|
||||
rom_names.emplace_back(machine_name, "the English-language VIC-20 character ROM", "characters-english.bin", 4*1024, 0x83e032a6);
|
||||
rom_names.emplace_back(machine_name, "the English-language NTSC VIC-20 kernel ROM", "kernel-ntsc.bin", 8*1024, 0xe5e7c174);
|
||||
character = ROM::Name::Vic20EnglishCharacters;
|
||||
kernel = ROM::Name::Vic20EnglishNTSCKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::Danish:
|
||||
rom_names.emplace_back(machine_name, "the Danish VIC-20 character ROM", "characters-danish.bin", 4*1024, 0x7fc11454);
|
||||
rom_names.emplace_back(machine_name, "the Danish VIC-20 kernel ROM", "kernel-danish.bin", 8*1024, 0x02adaf16);
|
||||
character = ROM::Name::Vic20DanishCharacters;
|
||||
kernel = ROM::Name::Vic20DanishKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::Japanese:
|
||||
rom_names.emplace_back(machine_name, "the Japanese VIC-20 character ROM", "characters-japanese.bin", 4*1024, 0xfcfd8a4b);
|
||||
rom_names.emplace_back(machine_name, "the Japanese VIC-20 kernel ROM", "kernel-japanese.bin", 8*1024, 0x336900d7);
|
||||
character = ROM::Name::Vic20JapaneseCharacters;
|
||||
kernel = ROM::Name::Vic20JapaneseKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::Swedish:
|
||||
rom_names.emplace_back(machine_name, "the Swedish VIC-20 character ROM", "characters-swedish.bin", 4*1024, 0xd808551d);
|
||||
rom_names.emplace_back(machine_name, "the Swedish VIC-20 kernel ROM", "kernel-swedish.bin", 8*1024, 0xb2a60662);
|
||||
character = ROM::Name::Vic20SwedishCharacters;
|
||||
kernel = ROM::Name::Vic20SwedishKernel;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto roms = rom_fetcher(rom_names);
|
||||
if(target.has_c1540) {
|
||||
request = request && Commodore::C1540::Machine::rom_request(Commodore::C1540::Personality::C1540);
|
||||
}
|
||||
request = request && ROM::Request(character) && ROM::Request(kernel);
|
||||
|
||||
for(const auto &rom: roms) {
|
||||
if(!rom) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
basic_rom_ = std::move(*roms[0]);
|
||||
character_rom_ = std::move(*roms[1]);
|
||||
kernel_rom_ = std::move(*roms[2]);
|
||||
|
||||
// Characters ROMs should be 4kb.
|
||||
character_rom_.resize(4096);
|
||||
// Kernel ROMs and the BASIC ROM should be 8kb.
|
||||
kernel_rom_.resize(8192);
|
||||
basic_rom_ = std::move(roms.find(ROM::Name::Vic20BASIC)->second);
|
||||
character_rom_ = std::move(roms.find(character)->second);
|
||||
kernel_rom_ = std::move(roms.find(kernel)->second);
|
||||
|
||||
if(target.has_c1540) {
|
||||
// construct the 1540
|
||||
c1540_ = std::make_unique<::Commodore::C1540::Machine>(Commodore::C1540::Personality::C1540, rom_fetcher);
|
||||
c1540_ = std::make_unique<::Commodore::C1540::Machine>(Commodore::C1540::Personality::C1540, roms);
|
||||
|
||||
// attach it to the serial bus
|
||||
c1540_->set_serial_bus(serial_bus_);
|
||||
|
@ -69,37 +69,25 @@ template <bool has_scsi_bus> class ConcreteMachine:
|
||||
speaker_.set_input_rate(2000000 / SoundGenerator::clock_rate_divider);
|
||||
speaker_.set_high_frequency_cutoff(6000);
|
||||
|
||||
const std::string machine_name = "Electron";
|
||||
std::vector<ROMMachine::ROM> required_roms = {
|
||||
{machine_name, "the Acorn BASIC II ROM", "basic.rom", 16*1024, 0x79434781},
|
||||
{machine_name, "the Electron MOS ROM", "os.rom", 16*1024, 0xbf63fb1f}
|
||||
};
|
||||
const size_t pres_adfs_rom_position = required_roms.size();
|
||||
::ROM::Request request = ::ROM::Request(::ROM::Name::AcornBASICII) && ::ROM::Request(::ROM::Name::AcornElectronMOS100);
|
||||
if(target.has_pres_adfs) {
|
||||
required_roms.emplace_back(machine_name, "the E00 ADFS ROM, first slot", "ADFS-E00_1.rom", 16*1024, 0x51523993);
|
||||
required_roms.emplace_back(machine_name, "the E00 ADFS ROM, second slot", "ADFS-E00_2.rom", 16*1024, 0x8d17de0e);
|
||||
request = request && ::ROM::Request(::ROM::Name::PRESADFSSlot1) && ::ROM::Request(::ROM::Name::PRESADFSSlot2);
|
||||
}
|
||||
const size_t acorn_adfs_rom_position = required_roms.size();
|
||||
if(target.has_acorn_adfs) {
|
||||
required_roms.emplace_back(machine_name, "the Acorn ADFS ROM", "adfs.rom", 16*1024, 0x3289bdc6);
|
||||
request = request && ::ROM::Request(::ROM::Name::AcornADFS);
|
||||
}
|
||||
const size_t dfs_rom_position = required_roms.size();
|
||||
if(target.has_dfs) {
|
||||
required_roms.emplace_back(machine_name, "the 1770 DFS ROM", "DFS-1770-2.20.rom", 16*1024, 0xf3dc9bc5);
|
||||
request = request && ::ROM::Request(::ROM::Name::Acorn1770DFS);
|
||||
}
|
||||
const size_t ap6_rom_position = required_roms.size();
|
||||
if(target.has_ap6_rom) {
|
||||
required_roms.emplace_back(machine_name, "the 8kb Advanced Plus 6 ROM", "AP6v133.rom", 8*1024, 0xe0013cfc);
|
||||
request = request && ::ROM::Request(::ROM::Name::PRESAdvancedPlus6);
|
||||
}
|
||||
const auto roms = rom_fetcher(required_roms);
|
||||
|
||||
for(const auto &rom: roms) {
|
||||
if(!rom) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
set_rom(ROM::BASIC, *roms[0], false);
|
||||
set_rom(ROM::OS, *roms[1], false);
|
||||
set_rom(ROM::BASIC, roms.find(::ROM::Name::AcornBASICII)->second, false);
|
||||
set_rom(ROM::OS, roms.find(::ROM::Name::AcornElectronMOS100)->second, false);
|
||||
|
||||
/*
|
||||
ROM slot mapping applied:
|
||||
@ -115,19 +103,18 @@ template <bool has_scsi_bus> class ConcreteMachine:
|
||||
plus3_ = std::make_unique<Plus3>();
|
||||
|
||||
if(target.has_dfs) {
|
||||
set_rom(ROM::Slot0, *roms[dfs_rom_position], true);
|
||||
set_rom(ROM::Slot0, roms.find(::ROM::Name::Acorn1770DFS)->second, true);
|
||||
}
|
||||
if(target.has_pres_adfs) {
|
||||
set_rom(ROM::Slot4, *roms[pres_adfs_rom_position], true);
|
||||
set_rom(ROM::Slot5, *roms[pres_adfs_rom_position+1], true);
|
||||
set_rom(ROM::Slot4, roms.find(::ROM::Name::PRESADFSSlot1)->second, true);
|
||||
set_rom(ROM::Slot5, roms.find(::ROM::Name::PRESADFSSlot2)->second, true);
|
||||
}
|
||||
if(target.has_acorn_adfs) {
|
||||
set_rom(ROM::Slot6, *roms[acorn_adfs_rom_position], true);
|
||||
set_rom(ROM::Slot6, roms.find(::ROM::Name::AcornADFS)->second, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(target.has_ap6_rom) {
|
||||
set_rom(ROM::Slot15, *roms[ap6_rom_position], true);
|
||||
set_rom(ROM::Slot15, roms.find(::ROM::Name::PRESAdvancedPlus6)->second, true);
|
||||
}
|
||||
|
||||
if(target.has_sideways_ram) {
|
||||
|
@ -169,19 +169,21 @@ class ConcreteMachine:
|
||||
|
||||
// Install the proper TV standard and select an ideal BIOS name.
|
||||
const std::string machine_name = "MSX";
|
||||
std::vector<ROMMachine::ROM> required_roms = {
|
||||
{machine_name, "any MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3}
|
||||
};
|
||||
ROM::Request bios_request = ROM::Request(ROM::Name::MSXGenericBIOS);
|
||||
// std::vector<ROMMachine::ROM> required_roms = {
|
||||
// {machine_name, "any MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3u}
|
||||
// };
|
||||
|
||||
bool is_ntsc = true;
|
||||
uint8_t character_generator = 1; /* 0 = Japan, 1 = USA, etc, 2 = USSR */
|
||||
uint8_t date_format = 1; /* 0 = Y/M/D, 1 = M/D/Y, 2 = D/M/Y */
|
||||
uint8_t keyboard = 1; /* 0 = Japan, 1 = USA, 2 = France, 3 = UK, 4 = Germany, 5 = USSR, 6 = Spain */
|
||||
ROM::Name regional_bios_name;
|
||||
|
||||
// TODO: CRCs below are incomplete, at best.
|
||||
switch(target.region) {
|
||||
case Target::Region::Japan:
|
||||
required_roms.emplace_back(machine_name, "a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390);
|
||||
regional_bios_name = ROM::Name::MSXJapaneseBIOS;
|
||||
vdp_->set_tv_standard(TI::TMS::TVStandard::NTSC);
|
||||
|
||||
is_ntsc = true;
|
||||
@ -189,7 +191,7 @@ class ConcreteMachine:
|
||||
date_format = 0;
|
||||
break;
|
||||
case Target::Region::USA:
|
||||
required_roms.emplace_back(machine_name, "an American MSX BIOS", "msx-american.rom", 32*1024, 0);
|
||||
regional_bios_name = ROM::Name::MSXAmericanBIOS;
|
||||
vdp_->set_tv_standard(TI::TMS::TVStandard::NTSC);
|
||||
|
||||
is_ntsc = true;
|
||||
@ -197,7 +199,7 @@ class ConcreteMachine:
|
||||
date_format = 1;
|
||||
break;
|
||||
case Target::Region::Europe:
|
||||
required_roms.emplace_back(machine_name, "a European MSX BIOS", "msx-european.rom", 32*1024, 0);
|
||||
regional_bios_name = ROM::Name::MSXEuropeanBIOS;
|
||||
vdp_->set_tv_standard(TI::TMS::TVStandard::PAL);
|
||||
|
||||
is_ntsc = false;
|
||||
@ -205,27 +207,30 @@ class ConcreteMachine:
|
||||
date_format = 2;
|
||||
break;
|
||||
}
|
||||
bios_request = bios_request || ROM::Request(regional_bios_name);
|
||||
|
||||
// Fetch the necessary ROMs; try the region-specific ROM first,
|
||||
// but failing that fall back on patching the main one.
|
||||
size_t disk_index = 0;
|
||||
ROM::Request request;
|
||||
if(target.has_disk_drive) {
|
||||
disk_index = required_roms.size();
|
||||
required_roms.emplace_back(machine_name, "the MSX-DOS ROM", "disk.rom", 16*1024, 0x721f61df);
|
||||
request = ROM::Request(ROM::Name::MSXDOS) && bios_request;
|
||||
} else {
|
||||
request = bios_request;
|
||||
}
|
||||
const auto roms = rom_fetcher(required_roms);
|
||||
|
||||
if((!roms[0] && !roms[1]) || (target.has_disk_drive && !roms[2])) {
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
// Figure out which BIOS to use, either a specific one or the generic
|
||||
// one appropriately patched.
|
||||
if(roms[1]) {
|
||||
memory_slots_[0].source = std::move(*roms[1]);
|
||||
const auto regional_bios = roms.find(regional_bios_name);
|
||||
if(regional_bios != roms.end()) {
|
||||
memory_slots_[0].source = std::move(regional_bios->second);
|
||||
memory_slots_[0].source.resize(32768);
|
||||
} else {
|
||||
memory_slots_[0].source = std::move(*roms[0]);
|
||||
memory_slots_[0].source = std::move(roms.find(ROM::Name::MSXGenericBIOS)->second);
|
||||
memory_slots_[0].source.resize(32768);
|
||||
|
||||
memory_slots_[0].source[0x2b] = uint8_t(
|
||||
@ -252,7 +257,7 @@ class ConcreteMachine:
|
||||
// Add a disk cartridge if any disks were supplied.
|
||||
if(target.has_disk_drive) {
|
||||
memory_slots_[2].set_handler(new DiskROM(memory_slots_[2].source));
|
||||
memory_slots_[2].source = std::move(*roms[disk_index]);
|
||||
memory_slots_[2].source = std::move(roms.find(ROM::Name::MSXDOS)->second);
|
||||
memory_slots_[2].source.resize(16384);
|
||||
|
||||
map(2, 0, 0x4000, 0x2000);
|
||||
|
@ -141,23 +141,19 @@ class ConcreteMachine:
|
||||
// 0072ed54 = US/European BIOS 1.3
|
||||
// 48d44a13 = Japanese BIOS 2.1
|
||||
const bool is_japanese = target.region == Target::Region::Japan;
|
||||
const auto roms = rom_fetcher(
|
||||
{ {"MasterSystem",
|
||||
is_japanese ? "the Japanese Master System BIOS" : "the European/US Master System BIOS",
|
||||
is_japanese ? "japanese-bios.sms" : "bios.sms",
|
||||
8*1024,
|
||||
{ is_japanese ? 0x48d44a13u : 0x0072ed54u }
|
||||
} }
|
||||
);
|
||||
if(!roms[0]) {
|
||||
const ROM::Name bios_name = is_japanese ? ROM::Name::MasterSystemJapaneseBIOS : ROM::Name::MasterSystemWesternBIOS;
|
||||
ROM::Request request(bios_name, true);
|
||||
const auto roms = rom_fetcher(request);
|
||||
|
||||
const auto rom = roms.find(bios_name);
|
||||
if(rom == roms.end()) {
|
||||
// No BIOS found; attempt to boot as though it has already disabled itself.
|
||||
has_bios_ = false;
|
||||
memory_control_ |= 0x08;
|
||||
std::cerr << "No BIOS found; attempting to start cartridge directly" << std::endl;
|
||||
} else {
|
||||
has_bios_ = true;
|
||||
roms[0]->resize(8*1024);
|
||||
memcpy(&bios_, roms[0]->data(), roms[0]->size());
|
||||
memcpy(&bios_, rom->second.data(), std::min(sizeof(bios_), rom->second.size()));
|
||||
}
|
||||
page_cartridge();
|
||||
|
||||
|
@ -304,73 +304,63 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
|
||||
ram_[c] |= 0x40;
|
||||
}
|
||||
|
||||
const std::string machine_name = "Oric";
|
||||
std::vector<ROMMachine::ROM> rom_names = { {machine_name, "the Oric colour ROM", "colour.rom", 128, 0xd50fca65} };
|
||||
::ROM::Request request = ::ROM::Request(::ROM::Name::OricColourROM, true);
|
||||
::ROM::Name basic;
|
||||
switch(target.rom) {
|
||||
case Analyser::Static::Oric::Target::ROM::BASIC10:
|
||||
rom_names.emplace_back(machine_name, "Oric BASIC 1.0", "basic10.rom", 16*1024, 0xf18710b4);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::ROM::BASIC11:
|
||||
rom_names.emplace_back(machine_name, "Oric BASIC 1.1", "basic11.rom", 16*1024, 0xc3a92bef);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::ROM::Pravetz:
|
||||
rom_names.emplace_back(machine_name, "Pravetz BASIC", "pravetz.rom", 16*1024, 0x58079502);
|
||||
break;
|
||||
case Analyser::Static::Oric::Target::ROM::BASIC10: basic = ::ROM::Name::OricBASIC10; break;
|
||||
case Analyser::Static::Oric::Target::ROM::BASIC11: basic = ::ROM::Name::OricBASIC11; break;
|
||||
case Analyser::Static::Oric::Target::ROM::Pravetz: basic = ::ROM::Name::OricPravetzBASIC; break;
|
||||
}
|
||||
size_t diskii_state_machine_index = 0;
|
||||
request = request && ::ROM::Request(basic);
|
||||
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case DiskInterface::BD500:
|
||||
rom_names.emplace_back(machine_name, "the Oric Byte Drive 500 ROM", "bd500.rom", 8*1024, 0x61952e34);
|
||||
request = request && ::ROM::Request(::ROM::Name::OricByteDrive500);
|
||||
break;
|
||||
case DiskInterface::Jasmin:
|
||||
rom_names.emplace_back(machine_name, "the Oric Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89);
|
||||
request = request && ::ROM::Request(::ROM::Name::OricJasmin);
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
rom_names.emplace_back(machine_name, "the Oric Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9c);
|
||||
request = request && ::ROM::Request(::ROM::Name::OricMicrodisc);
|
||||
break;
|
||||
case DiskInterface::Pravetz:
|
||||
rom_names.emplace_back(machine_name, "the 8DOS boot ROM", "8dos.rom", 512, 0x49a74c06);
|
||||
// These ROM details are coupled with those in the DiskIICard.
|
||||
diskii_state_machine_index = rom_names.size();
|
||||
rom_names.push_back({"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 }});
|
||||
request = request && ::ROM::Request(::ROM::Name::Oric8DOSBoot) && ::ROM::Request(::ROM::Name::DiskIIStateMachine16Sector);
|
||||
break;
|
||||
}
|
||||
|
||||
const auto roms = rom_fetcher(rom_names);
|
||||
|
||||
for(std::size_t index = 0; index < roms.size(); ++index) {
|
||||
if(!roms[index]) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
video_->set_colour_rom(*roms[0]);
|
||||
rom_ = std::move(*roms[1]);
|
||||
// The colour ROM is optional; an alternative composite encoding can be used if
|
||||
// it is absent.
|
||||
const auto colour_rom = roms.find(::ROM::Name::OricColourROM);
|
||||
if(colour_rom != roms.end()) {
|
||||
video_->set_colour_rom(colour_rom->second);
|
||||
}
|
||||
rom_ = std::move(roms.find(basic)->second);
|
||||
|
||||
switch(disk_interface) {
|
||||
default: break;
|
||||
case DiskInterface::BD500:
|
||||
disk_rom_ = std::move(*roms[2]);
|
||||
disk_rom_.resize(8192);
|
||||
disk_rom_ = std::move(roms.find(::ROM::Name::OricByteDrive500)->second);
|
||||
break;
|
||||
case DiskInterface::Jasmin:
|
||||
disk_rom_ = std::move(*roms[2]);
|
||||
disk_rom_.resize(2048);
|
||||
disk_rom_ = std::move(roms.find(::ROM::Name::OricJasmin)->second);
|
||||
break;
|
||||
case DiskInterface::Microdisc:
|
||||
disk_rom_ = std::move(*roms[2]);
|
||||
disk_rom_.resize(8192);
|
||||
disk_rom_ = std::move(roms.find(::ROM::Name::OricMicrodisc)->second);
|
||||
break;
|
||||
case DiskInterface::Pravetz: {
|
||||
pravetz_rom_ = std::move(*roms[2]);
|
||||
pravetz_rom_ = std::move(roms.find(::ROM::Name::Oric8DOSBoot)->second);
|
||||
pravetz_rom_.resize(512);
|
||||
|
||||
diskii_->set_state_machine(*roms[diskii_state_machine_index]);
|
||||
diskii_->set_state_machine(roms.find(::ROM::Name::DiskIIStateMachine16Sector)->second);
|
||||
} break;
|
||||
}
|
||||
|
||||
rom_.resize(16384);
|
||||
paged_rom_ = rom_.data();
|
||||
|
||||
switch(target.disk_interface) {
|
||||
|
@ -10,38 +10,16 @@
|
||||
#define ROMMachine_hpp
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Utility/ROMCatalogue.hpp"
|
||||
|
||||
namespace ROMMachine {
|
||||
|
||||
/*!
|
||||
Describes a ROM image; this term is used in this emulator strictly in the sense of firmware —
|
||||
system software that is an inherent part of a machine.
|
||||
*/
|
||||
struct ROM {
|
||||
/// The machine with which this ROM is associated, in a form that is safe for using as
|
||||
/// part of a file name.
|
||||
std::string machine_name;
|
||||
/// A descriptive name for this ROM, suitable for use in a bullet-point list, a bracket
|
||||
/// clause, etc, e.g. "the Electron MOS 1.0".
|
||||
std::string descriptive_name;
|
||||
/// An idiomatic file name for this ROM, e.g. "os10.rom".
|
||||
std::string file_name;
|
||||
/// The expected size of this ROM in bytes, e.g. 32768.
|
||||
size_t size = 0;
|
||||
/// CRC32s for all known acceptable copies of this ROM; intended to allow a host platform
|
||||
/// to test user-provided ROMs of unknown provenance. **Not** intended to be used
|
||||
/// to exclude ROMs where the user's intent is otherwise clear.
|
||||
std::vector<uint32_t> crc32s;
|
||||
|
||||
ROM(std::string machine_name, std::string descriptive_name, std::string file_name, size_t size, uint32_t crc32) :
|
||||
machine_name(machine_name), descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s({crc32}) {}
|
||||
ROM(std::string machine_name, std::string descriptive_name, std::string file_name, size_t size, std::initializer_list<uint32_t> crc32s) :
|
||||
machine_name(machine_name), descriptive_name(descriptive_name), file_name(file_name), size(size), crc32s(crc32s) {}
|
||||
};
|
||||
|
||||
/*!
|
||||
Defines the signature for a function that must be supplied by the host environment in order to give machines
|
||||
a route for fetching any system ROMs they might need.
|
||||
@ -50,7 +28,7 @@ struct ROM {
|
||||
return a vector of unique_ptrs that either contain the contents of the ROM from @c names that corresponds by
|
||||
index, or else are @c nullptr.
|
||||
*/
|
||||
typedef std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::vector<ROM> &roms)> ROMFetcher;
|
||||
typedef std::function<ROM::Map(const ROM::Request &request)> ROMFetcher;
|
||||
|
||||
enum class Error {
|
||||
MissingROMs
|
||||
|
@ -74,15 +74,13 @@ template<bool is_zx81> class ConcreteMachine:
|
||||
speaker_.set_input_rate(float(ZX8081ClockRate) / 2.0f);
|
||||
|
||||
const bool use_zx81_rom = target.is_ZX81 || target.ZX80_uses_ZX81_ROM;
|
||||
const auto roms =
|
||||
use_zx81_rom ?
|
||||
rom_fetcher({ {"ZX8081", "the ZX81 BASIC ROM", "zx81.rom", 8 * 1024, 0x4b1dd6eb} }) :
|
||||
rom_fetcher({ {"ZX8081", "the ZX80 BASIC ROM", "zx80.rom", 4 * 1024, 0x4c7fc597} });
|
||||
|
||||
if(!roms[0]) throw ROMMachine::Error::MissingROMs;
|
||||
|
||||
rom_ = std::move(*roms[0]);
|
||||
rom_.resize(use_zx81_rom ? 8192 : 4096);
|
||||
const ROM::Name rom_name = use_zx81_rom ? ROM::Name::ZX81 : ROM::Name::ZX80;
|
||||
const ROM::Request request(rom_name);
|
||||
auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
rom_ = std::move(roms.find(rom_name)->second);
|
||||
|
||||
rom_mask_ = uint16_t(rom_.size() - 1);
|
||||
|
||||
|
@ -146,33 +146,24 @@ template<Model model> class ConcreteMachine:
|
||||
set_clock_rate(clock_rate());
|
||||
speaker_.set_input_rate(float(clock_rate()) / 2.0f);
|
||||
|
||||
// With only the +2a and +3 currently supported, the +3 ROM is always
|
||||
// the one required.
|
||||
std::vector<ROMMachine::ROM> rom_names;
|
||||
const std::string machine = "ZXSpectrum";
|
||||
ROM::Name rom_name;
|
||||
switch(model) {
|
||||
case Model::SixteenK:
|
||||
case Model::FortyEightK:
|
||||
rom_names.emplace_back(machine, "the 48kb ROM", "48.rom", 16 * 1024, 0xddee531f);
|
||||
break;
|
||||
|
||||
case Model::OneTwoEightK:
|
||||
rom_names.emplace_back(machine, "the 128kb ROM", "128.rom", 32 * 1024, 0x2cbe8995);
|
||||
break;
|
||||
|
||||
case Model::Plus2:
|
||||
rom_names.emplace_back(machine, "the +2 ROM", "plus2.rom", 32 * 1024, 0xe7a517dc);
|
||||
break;
|
||||
|
||||
case Model::FortyEightK: rom_name = ROM::Name::Spectrum48k; break;
|
||||
case Model::OneTwoEightK: rom_name = ROM::Name::Spectrum128k; break;
|
||||
case Model::Plus2: rom_name = ROM::Name::SpecrumPlus2; break;
|
||||
case Model::Plus2a:
|
||||
case Model::Plus3: {
|
||||
const std::initializer_list<uint32_t> crc32s = { 0x96e3c17a, 0xbe0d9ec4 };
|
||||
rom_names.emplace_back(machine, "the +2a/+3 ROM", "plus3.rom", 64 * 1024, crc32s);
|
||||
} break;
|
||||
case Model::Plus3: rom_name = ROM::Name::SpectrumPlus3; break;
|
||||
// TODO: possibly accept the +3 ROM in multiple parts?
|
||||
}
|
||||
const auto roms = rom_fetcher(rom_names);
|
||||
if(!roms[0]) throw ROMMachine::Error::MissingROMs;
|
||||
memcpy(rom_.data(), roms[0]->data(), std::min(rom_.size(), roms[0]->size()));
|
||||
const auto request = ROM::Request(rom_name);
|
||||
const auto roms = rom_fetcher(request);
|
||||
if(!request.validate(roms)) {
|
||||
throw ROMMachine::Error::MissingROMs;
|
||||
}
|
||||
|
||||
const auto &rom = roms.find(rom_name)->second;
|
||||
memcpy(rom_.data(), rom.data(), std::min(rom_.size(), rom.size()));
|
||||
|
||||
// Register for sleeping notifications.
|
||||
tape_player_.set_clocking_hint_observer(this);
|
||||
|
379
Machines/Utility/ROMCatalogue.cpp
Normal file
379
Machines/Utility/ROMCatalogue.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
//
|
||||
// ROMCatalogue.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 01/06/2021.
|
||||
// Copyright © 2021 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "ROMCatalogue.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace ROM;
|
||||
|
||||
Request::Request(Name name, bool optional) :
|
||||
node.name(name), node.is_optional(optional) {}
|
||||
|
||||
Request::Request() {}
|
||||
|
||||
Request Request::operator &&(const Request &rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Request Request::operator ||(const Request &rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Request::validate(const Map &) const {
|
||||
/* TODO. */
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<ROM::Description> Request::all_descriptions() const {
|
||||
std::vector<Description>() result;
|
||||
node.add_descriptions(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Request::Node::add_descriptions(std::vector<Description> &result) {
|
||||
if(type == Type::One) {
|
||||
result.push_back(name);
|
||||
return;
|
||||
}
|
||||
|
||||
for(const auto &node: children) {
|
||||
node.add_descriptions(result);
|
||||
}
|
||||
}
|
||||
|
||||
Description::Description(Name name) {
|
||||
switch(name) {
|
||||
default: assert(false); break;
|
||||
|
||||
case Name::AMSDOS:
|
||||
*this = Request("AmstradCPC", "the Amstrad Disk Operating System", "amsdos.rom", 16*1024, 0x1fe22ecdu);
|
||||
break;
|
||||
case Name::CPC464Firmware:
|
||||
*this = Request("AmstradCPC", "the CPC 464 firmware", "os464.rom", 16*1024, 0x815752dfu);
|
||||
break;
|
||||
case Name::CPC464BASIC:
|
||||
*this = Request("AmstradCPC", "the CPC 464 BASIC ROM", "basic464.rom", 16*1024, 0x7d9a3bacu);
|
||||
break;
|
||||
case Name::CPC664Firmware:
|
||||
*this = Request("AmstradCPC", "the CPC 664 firmware", "os664.rom", 16*1024, 0x3f5a6dc4u);
|
||||
break;
|
||||
case Name::CPC664BASIC:
|
||||
*this = Request("AmstradCPC", "the CPC 664 BASIC ROM", "basic664.rom", 16*1024, 0x32fee492u);
|
||||
break;
|
||||
case Name::CPC6128Firmware:
|
||||
*this = Request("AmstradCPC", "the CPC 6128 firmware", "os664.rom", 16*1024, 0x0219bb74u);
|
||||
break;
|
||||
case Name::CPC6128BASIC:
|
||||
*this = Request("AmstradCPC", "the CPC 6128 BASIC ROM", "basic664.rom", 16*1024, 0xca6af63du);
|
||||
break;
|
||||
|
||||
//"AppleII"
|
||||
AppleIIOriginal,
|
||||
AppleIIPlus,
|
||||
AppleIICharacter,
|
||||
AppleIIe,
|
||||
AppleIIeCharacter,
|
||||
AppleIIEnhancedE,
|
||||
AppleIIEnhancedECharacter,
|
||||
}
|
||||
|
||||
// rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::EnhancedIIe));
|
||||
// rom_descriptions.emplace_back(machine_name, "the Enhanced Apple IIe ROM", "apple2e.rom", 32*1024, 0x65989942u);
|
||||
// rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::IIe));
|
||||
// rom_descriptions.emplace_back(machine_name, "the Apple IIe ROM", "apple2eu.rom", 32*1024, 0xe12be18du);
|
||||
// rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::II));
|
||||
// rom_descriptions.emplace_back(machine_name, "the Apple II+ ROM", "apple2.rom", 12*1024, 0xf66f9c26u);
|
||||
// rom_descriptions.push_back(video_.rom_description(Video::VideoBase::CharacterROM::II));
|
||||
// rom_descriptions.emplace_back(machine_name, "the original Apple II ROM", "apple2o.rom", 12*1024, 0xba210588u);
|
||||
|
||||
// roms = rom_fetcher({
|
||||
// {"DiskII", "the Disk II 16-sector boot ROM", "boot-16.rom", 256, 0xce7144f6},
|
||||
// {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 } }
|
||||
// });
|
||||
// roms = rom_fetcher({
|
||||
// {"DiskII", "the Disk II 13-sector boot ROM", "boot-13.rom", 256, 0xd34eb2ff},
|
||||
// {"DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, { 0x9796a238, 0xb72a2c70 } }
|
||||
//// {"DiskII", "the Disk II 13-sector state machine ROM", "state-machine-13.rom", 256, 0x62e22620 }
|
||||
// });
|
||||
|
||||
|
||||
// enum class CharacterROM {
|
||||
// /// The ROM that shipped with both the Apple II and the II+.
|
||||
// II,
|
||||
// /// The ROM that shipped with the original IIe.
|
||||
// IIe,
|
||||
// /// The ROM that shipped with the Enhanced IIe.
|
||||
// EnhancedIIe,
|
||||
// /// The ROM that shipped with the IIgs.
|
||||
// IIgs
|
||||
// };
|
||||
//
|
||||
// /// @returns A file-level description of @c rom.
|
||||
// static ROM::Name rom_name(CharacterROM rom) {
|
||||
// const std::string machine_name = "AppleII";
|
||||
// switch(rom) {
|
||||
// case CharacterROM::II:
|
||||
// return ROMMachine::ROM(machine_name, "the basic Apple II character ROM", "apple2-character.rom", 2*1024, 0x64f415c6);
|
||||
//
|
||||
// case CharacterROM::IIe:
|
||||
// return ROMMachine::ROM(machine_name, "the Apple IIe character ROM", "apple2eu-character.rom", 4*1024, 0x816a86f1);
|
||||
//
|
||||
// default: // To appease GCC.
|
||||
// case CharacterROM::EnhancedIIe:
|
||||
// return ROMMachine::ROM(machine_name, "the Enhanced Apple IIe character ROM", "apple2e-character.rom", 4*1024, 0x2651014d);
|
||||
//
|
||||
// case CharacterROM::IIgs:
|
||||
// return ROMMachine::ROM(machine_name, "the Apple IIgs character ROM", "apple2gs.chr", 4*1024, 0x91e53cd8);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// const std::string machine_name = "AppleIIgs";
|
||||
// switch(target.model) {
|
||||
// case Target::Model::ROM00:
|
||||
// /* TODO */
|
||||
// case Target::Model::ROM01:
|
||||
// rom_descriptions.emplace_back(machine_name, "the Apple IIgs ROM01", "apple2gs.rom", 128*1024, 0x42f124b0u);
|
||||
// break;
|
||||
//
|
||||
// case Target::Model::ROM03:
|
||||
// rom_descriptions.emplace_back(machine_name, "the Apple IIgs ROM03", "apple2gs.rom2", 256*1024, 0xde7ddf29u);
|
||||
// break;
|
||||
// }
|
||||
// rom_descriptions.push_back(video_->rom_description(Video::Video::CharacterROM::EnhancedIIe));
|
||||
//
|
||||
// // TODO: pick a different ADB ROM for earlier machine revisions?
|
||||
// rom_descriptions.emplace_back(machine_name, "the Apple IIgs ADB microcontroller ROM", "341s0632-2", 4*1024, 0xe1c11fb0u);
|
||||
|
||||
|
||||
// switch(model) {
|
||||
// default:
|
||||
// case Model::Mac128k:
|
||||
// ram_size = 128*1024;
|
||||
// rom_size = 64*1024;
|
||||
// rom_descriptions.emplace_back(machine_name, "the Macintosh 128k ROM", "mac128k.rom", 64*1024, 0x6d0c8a28);
|
||||
// break;
|
||||
// case Model::Mac512k:
|
||||
// ram_size = 512*1024;
|
||||
// rom_size = 64*1024;
|
||||
// rom_descriptions.emplace_back(machine_name, "the Macintosh 512k ROM", "mac512k.rom", 64*1024, 0xcf759e0d);
|
||||
// break;
|
||||
// case Model::Mac512ke:
|
||||
// case Model::MacPlus: {
|
||||
// ram_size = ((model == Model::MacPlus) ? 4096 : 512)*1024;
|
||||
// rom_size = 128*1024;
|
||||
// const std::initializer_list<uint32_t> crc32s = { 0x4fa5b399, 0x7cacd18f, 0xb2102e8e };
|
||||
// rom_descriptions.emplace_back(machine_name, "the Macintosh Plus ROM", "macplus.rom", 128*1024, crc32s);
|
||||
// } break;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// std::vector<ROMMachine::ROM> rom_descriptions = {
|
||||
// {"AtariST", "the UK TOS 1.00 ROM", "tos100.img", 192*1024, 0x1a586c64}
|
||||
//// {"AtariST", "the UK TOS 1.04 ROM", "tos104.img", 192*1024, 0xa50d1d43}
|
||||
// };
|
||||
|
||||
|
||||
// rom_list.emplace_back(new ROMMachine::ROM("ColecoVision", "the ColecoVision BIOS", std::vector<std::string>{ "coleco.rom" }, 8*1024, 0x3aa93ef3u));
|
||||
|
||||
|
||||
// if(use_zx81_rom) {
|
||||
// rom_list.emplace_back(new ROMMachine::ROM("ZX8081", "the ZX81 BASIC ROM", std::vector<std::string>{ "zx81.rom" }, 8 * 1024, 0x4b1dd6ebu));
|
||||
// } else {
|
||||
// rom_list.emplace_back(new ROMMachine::ROM("ZX8081", "the ZX80 BASIC ROM", std::vector<std::string>{ "zx80.rom" }, 4 * 1024, 0x4c7fc597u));
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// const std::string machine = "ZXSpectrum";
|
||||
// switch(model) {
|
||||
// case Model::SixteenK:
|
||||
// case Model::FortyEightK:
|
||||
// rom_names.emplace_back(machine, "the 48kb ROM", "48.rom", 16 * 1024, 0xddee531fu);
|
||||
// break;
|
||||
//
|
||||
// case Model::OneTwoEightK:
|
||||
// rom_names.emplace_back(machine, "the 128kb ROM", "128.rom", 32 * 1024, 0x2cbe8995u);
|
||||
// break;
|
||||
//
|
||||
// case Model::Plus2:
|
||||
// rom_names.emplace_back(machine, "the +2 ROM", "plus2.rom", 32 * 1024, 0xe7a517dcu);
|
||||
// break;
|
||||
//
|
||||
// case Model::Plus2a:
|
||||
// case Model::Plus3: {
|
||||
// const std::initializer_list<uint32_t> crc32s = { 0x96e3c17a, 0xbe0d9ec4 };
|
||||
// rom_names.emplace_back(machine, "the +2a/+3 ROM", "plus3.rom", 64 * 1024, crc32s);
|
||||
// } break;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// const std::string machine_name = "Electron";
|
||||
// std::vector<ROMMachine::ROM> required_roms = {
|
||||
// {machine_name, "the Acorn BASIC II ROM", "basic.rom", 16*1024, 0x79434781},
|
||||
// {machine_name, "the Electron MOS ROM", "os.rom", 16*1024, 0xbf63fb1f}
|
||||
// };
|
||||
// const size_t pres_adfs_rom_position = required_roms.size();
|
||||
// if(target.has_pres_adfs) {
|
||||
// required_roms.emplace_back(machine_name, "the E00 ADFS ROM, first slot", "ADFS-E00_1.rom", 16*1024, 0x51523993);
|
||||
// required_roms.emplace_back(machine_name, "the E00 ADFS ROM, second slot", "ADFS-E00_2.rom", 16*1024, 0x8d17de0e);
|
||||
// }
|
||||
// const size_t acorn_adfs_rom_position = required_roms.size();
|
||||
// if(target.has_acorn_adfs) {
|
||||
// required_roms.emplace_back(machine_name, "the Acorn ADFS ROM", "adfs.rom", 16*1024, 0x3289bdc6);
|
||||
// }
|
||||
// const size_t dfs_rom_position = required_roms.size();
|
||||
// if(target.has_dfs) {
|
||||
// required_roms.emplace_back(machine_name, "the 1770 DFS ROM", "DFS-1770-2.20.rom", 16*1024, 0xf3dc9bc5);
|
||||
// }
|
||||
// const size_t ap6_rom_position = required_roms.size();
|
||||
// if(target.has_ap6_rom) {
|
||||
// required_roms.emplace_back(machine_name, "the 8kb Advanced Plus 6 ROM", "AP6v133.rom", 8*1024, 0xe0013cfc);
|
||||
// }
|
||||
|
||||
|
||||
// new ROMMachine::ROM("MasterSystem",
|
||||
// is_japanese ? "the Japanese Master System BIOS" : "the European/US Master System BIOS",
|
||||
// is_japanese ? "japanese-bios.sms" : "bios.sms",
|
||||
// 8*1024,
|
||||
// is_japanese ? 0x48d44a13u : 0x0072ed54u,
|
||||
// true
|
||||
// )
|
||||
|
||||
|
||||
// switch(personality) {
|
||||
// case Personality::C1540:
|
||||
// device_name = "1540";
|
||||
// crc = 0x718d42b1;
|
||||
// break;
|
||||
// case Personality::C1541:
|
||||
// device_name = "1541";
|
||||
// crc = 0xfb760019;
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// auto roms = rom_fetcher({ {"Commodore1540", "the " + device_name + " ROM", device_name + ".bin", 16*1024, crc} });
|
||||
|
||||
|
||||
// const std::string machine_name = "Vic20";
|
||||
// std::vector<ROMMachine::ROM> rom_names = {
|
||||
// {machine_name, "the VIC-20 BASIC ROM", "basic.bin", 8*1024, 0xdb4c43c1u}
|
||||
// };
|
||||
// switch(target.region) {
|
||||
// default:
|
||||
// rom_names.emplace_back(machine_name, "the English-language VIC-20 character ROM", "characters-english.bin", 4*1024, 0x83e032a6u);
|
||||
// rom_names.emplace_back(machine_name, "the English-language PAL VIC-20 kernel ROM", "kernel-pal.bin", 8*1024, 0x4be07cb4u);
|
||||
// break;
|
||||
// case Analyser::Static::Commodore::Target::Region::American:
|
||||
// rom_names.emplace_back(machine_name, "the English-language VIC-20 character ROM", "characters-english.bin", 4*1024, 0x83e032a6u);
|
||||
// rom_names.emplace_back(machine_name, "the English-language NTSC VIC-20 kernel ROM", "kernel-ntsc.bin", 8*1024, 0xe5e7c174u);
|
||||
// break;
|
||||
// case Analyser::Static::Commodore::Target::Region::Danish:
|
||||
// rom_names.emplace_back(machine_name, "the Danish VIC-20 character ROM", "characters-danish.bin", 4*1024, 0x7fc11454u);
|
||||
// rom_names.emplace_back(machine_name, "the Danish VIC-20 kernel ROM", "kernel-danish.bin", 8*1024, 0x02adaf16u);
|
||||
// break;
|
||||
// case Analyser::Static::Commodore::Target::Region::Japanese:
|
||||
// rom_names.emplace_back(machine_name, "the Japanese VIC-20 character ROM", "characters-japanese.bin", 4*1024, 0xfcfd8a4bu);
|
||||
// rom_names.emplace_back(machine_name, "the Japanese VIC-20 kernel ROM", "kernel-japanese.bin", 8*1024, 0x336900d7u);
|
||||
// break;
|
||||
// case Analyser::Static::Commodore::Target::Region::Swedish:
|
||||
// rom_names.emplace_back(machine_name, "the Swedish VIC-20 character ROM", "characters-swedish.bin", 4*1024, 0xd808551du);
|
||||
// rom_names.emplace_back(machine_name, "the Swedish VIC-20 kernel ROM", "kernel-swedish.bin", 8*1024, 0xb2a60662u);
|
||||
// break;
|
||||
// }
|
||||
|
||||
|
||||
// const std::string machine_name = "Oric";
|
||||
// std::vector<ROMMachine::ROM> rom_names = { {machine_name, "the Oric colour ROM", "colour.rom", 128, 0xd50fca65u, true} };
|
||||
// switch(target.rom) {
|
||||
// case Analyser::Static::Oric::Target::ROM::BASIC10:
|
||||
// rom_names.emplace_back(machine_name, "Oric BASIC 1.0", "basic10.rom", 16*1024, 0xf18710b4u);
|
||||
// break;
|
||||
// case Analyser::Static::Oric::Target::ROM::BASIC11:
|
||||
// rom_names.emplace_back(machine_name, "Oric BASIC 1.1", "basic11.rom", 16*1024, 0xc3a92befu);
|
||||
// break;
|
||||
// case Analyser::Static::Oric::Target::ROM::Pravetz:
|
||||
// rom_names.emplace_back(machine_name, "Pravetz BASIC", "pravetz.rom", 16*1024, 0x58079502u);
|
||||
// break;
|
||||
// }
|
||||
// size_t diskii_state_machine_index = 0;
|
||||
// switch(disk_interface) {
|
||||
// default: break;
|
||||
// case DiskInterface::BD500:
|
||||
// rom_names.emplace_back(machine_name, "the Oric Byte Drive 500 ROM", "bd500.rom", 8*1024, 0x61952e34u);
|
||||
// break;
|
||||
// case DiskInterface::Jasmin:
|
||||
// rom_names.emplace_back(machine_name, "the Oric Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89u);
|
||||
// break;
|
||||
// case DiskInterface::Microdisc:
|
||||
// rom_names.emplace_back(machine_name, "the Oric Microdisc ROM", "microdisc.rom", 8*1024, 0xa9664a9cu);
|
||||
// break;
|
||||
// case DiskInterface::Pravetz:
|
||||
// rom_names.emplace_back(machine_name, "the 8DOS boot ROM", "8dos.rom", 512, 0x49a74c06u);
|
||||
// // These ROM details are coupled with those in the DiskIICard.
|
||||
// diskii_state_machine_index = rom_names.size();
|
||||
// rom_names.emplace_back("DiskII", "the Disk II 16-sector state machine ROM", "state-machine-16.rom", 256, std::initializer_list<uint32_t>{ 0x9796a238u, 0xb72a2c70u });
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// const auto collection = ROMMachine::ROMCollection(rom_names);
|
||||
|
||||
|
||||
// const std::string machine_name = "MSX";
|
||||
// std::vector<ROMMachine::ROM> required_roms = {
|
||||
// {machine_name, "any MSX BIOS", "msx.rom", 32*1024, 0x94ee12f3u}
|
||||
// };
|
||||
//
|
||||
// bool is_ntsc = true;
|
||||
// uint8_t character_generator = 1; /* 0 = Japan, 1 = USA, etc, 2 = USSR */
|
||||
// uint8_t date_format = 1; /* 0 = Y/M/D, 1 = M/D/Y, 2 = D/M/Y */
|
||||
// uint8_t keyboard = 1; /* 0 = Japan, 1 = USA, 2 = France, 3 = UK, 4 = Germany, 5 = USSR, 6 = Spain */
|
||||
//
|
||||
// // TODO: CRCs below are incomplete, at best.
|
||||
// switch(target.region) {
|
||||
// case Target::Region::Japan:
|
||||
// required_roms.emplace_back(machine_name, "a Japanese MSX BIOS", "msx-japanese.rom", 32*1024, 0xee229390u);
|
||||
// vdp_->set_tv_standard(TI::TMS::TVStandard::NTSC);
|
||||
//
|
||||
// is_ntsc = true;
|
||||
// character_generator = 0;
|
||||
// date_format = 0;
|
||||
// break;
|
||||
// case Target::Region::USA:
|
||||
// required_roms.emplace_back(machine_name, "an American MSX BIOS", "msx-american.rom", 32*1024, 0u);
|
||||
// vdp_->set_tv_standard(TI::TMS::TVStandard::NTSC);
|
||||
//
|
||||
// is_ntsc = true;
|
||||
// character_generator = 1;
|
||||
// date_format = 1;
|
||||
// break;
|
||||
// case Target::Region::Europe:
|
||||
// required_roms.emplace_back(machine_name, "a European MSX BIOS", "msx-european.rom", 32*1024, 0u);
|
||||
// vdp_->set_tv_standard(TI::TMS::TVStandard::PAL);
|
||||
//
|
||||
// is_ntsc = false;
|
||||
// character_generator = 1;
|
||||
// date_format = 2;
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// ROMMachine::ROMVector rom_list;
|
||||
// ROMMachine::ROMCollection *bios = new ROMMachine::ROMCollection(required_roms, ROMMachine::ROMCollection::Type::Any);
|
||||
// rom_list.emplace_back(bios);
|
||||
//
|
||||
// // Fetch the necessary ROMs; try the region-specific ROM first,
|
||||
// // but failing that fall back on patching the main one.
|
||||
// size_t disk_index = 0;
|
||||
// if(target.has_disk_drive) {
|
||||
// disk_index = required_roms.size();
|
||||
// rom_list.emplace_back(new ROMMachine::ROM(machine_name, "the MSX-DOS ROM", "disk.rom", 16*1024, 0x721f61dfu));
|
||||
// }
|
172
Machines/Utility/ROMCatalogue.hpp
Normal file
172
Machines/Utility/ROMCatalogue.hpp
Normal file
@ -0,0 +1,172 @@
|
||||
//
|
||||
// ROMCatalogue.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 01/06/2021.
|
||||
// Copyright © 2021 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef ROMCatalogue_hpp
|
||||
#define ROMCatalogue_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ROM {
|
||||
|
||||
enum Name {
|
||||
Invalid,
|
||||
|
||||
// Acorn.
|
||||
AcornBASICII,
|
||||
AcornElectronMOS100,
|
||||
PRESADFSSlot1,
|
||||
PRESADFSSlot2,
|
||||
AcornADFS,
|
||||
PRESAdvancedPlus6,
|
||||
Acorn1770DFS,
|
||||
|
||||
// Amstrad CPC.
|
||||
AMSDOS,
|
||||
CPC464Firmware, CPC464BASIC,
|
||||
CPC664Firmware, CPC664BASIC,
|
||||
CPC6128Firmware, CPC6128BASIC,
|
||||
|
||||
// Apple II.
|
||||
AppleIIOriginal,
|
||||
AppleIIPlus,
|
||||
AppleIICharacter,
|
||||
AppleIIe,
|
||||
AppleIIeCharacter,
|
||||
AppleIIEnhancedE,
|
||||
AppleIIEnhancedECharacter,
|
||||
|
||||
// Apple IIgs.
|
||||
AppleIIgsROM00,
|
||||
AppleIIgsROM01,
|
||||
AppleIIgsROM03,
|
||||
AppleIIgsMicrocontrollerROM03,
|
||||
|
||||
// Atari ST.
|
||||
AtariSTTOS100,
|
||||
AtariSTTOS104,
|
||||
|
||||
// ColecoVision.
|
||||
ColecoVisionBIOS,
|
||||
|
||||
// Commodore 1540/1541.
|
||||
Commodore1540,
|
||||
Commodore1541,
|
||||
|
||||
// Disk II.
|
||||
DiskIIStateMachine16Sector,
|
||||
DiskIIBoot16Sector,
|
||||
DiskIIStateMachine13Sector,
|
||||
DiskIIBoot13Sector,
|
||||
|
||||
// Macintosh.
|
||||
Macintosh128k,
|
||||
Macintosh512k,
|
||||
MacintoshPlus,
|
||||
|
||||
// Master System.
|
||||
MasterSystemJapaneseBIOS,
|
||||
MasterSystemWesternBIOS,
|
||||
|
||||
// MSX.
|
||||
MSXGenericBIOS,
|
||||
MSXJapaneseBIOS,
|
||||
MSXAmericanBIOS,
|
||||
MSXEuropeanBIOS,
|
||||
MSXDOS,
|
||||
|
||||
// Oric.
|
||||
OricColourROM,
|
||||
OricBASIC10,
|
||||
OricBASIC11,
|
||||
OricPravetzBASIC,
|
||||
OricByteDrive500,
|
||||
OricJasmin,
|
||||
OricMicrodisc,
|
||||
Oric8DOSBoot,
|
||||
|
||||
// Vic-20.
|
||||
Vic20BASIC,
|
||||
Vic20EnglishCharacters,
|
||||
Vic20EnglishPALKernel,
|
||||
Vic20EnglishNTSCKernel,
|
||||
Vic20DanishCharacters,
|
||||
Vic20DanishKernel,
|
||||
Vic20JapaneseCharacters,
|
||||
Vic20JapaneseKernel,
|
||||
Vic20SwedishCharacters,
|
||||
Vic20SwedishKernel,
|
||||
|
||||
// ZX80/81.
|
||||
ZX80,
|
||||
ZX81,
|
||||
|
||||
// ZX Spectrum.
|
||||
Spectrum48k,
|
||||
Spectrum128k,
|
||||
SpecrumPlus2,
|
||||
SpectrumPlus3,
|
||||
};
|
||||
|
||||
using Map = std::map<ROM::Name, std::vector<uint8_t>>;
|
||||
|
||||
struct Description {
|
||||
/// The ROM's enum name.
|
||||
Name name = Name::Invalid;
|
||||
/// The machine with which this ROM is associated, in a form that is safe for using as
|
||||
/// part of a file name.
|
||||
std::string machine_name;
|
||||
/// A descriptive name for this ROM, suitable for use in a bullet-point list, a bracket
|
||||
/// clause, etc, e.g. "the Electron MOS 1.0".
|
||||
std::string descriptive_name;
|
||||
/// All idiomatic file name for this ROM, e.g. "os10.rom".
|
||||
std::vector<std::string> file_names;
|
||||
/// The expected size of this ROM in bytes, e.g. 32768.
|
||||
size_t size = 0;
|
||||
/// CRC32s for all known acceptable copies of this ROM; intended to allow a host platform
|
||||
/// to test user-provided ROMs of unknown provenance. **Not** intended to be used
|
||||
/// to exclude ROMs where the user's intent is otherwise clear.
|
||||
std::vector<uint32_t> crc32s;
|
||||
|
||||
/// Constructs the @c Description that correlates to @c name.
|
||||
Description(Name name);
|
||||
};
|
||||
|
||||
struct Request {
|
||||
Request(Name name, bool optional = false);
|
||||
Request();
|
||||
|
||||
Request operator &&(const Request &);
|
||||
Request operator ||(const Request &);
|
||||
|
||||
/// Inspects the ROMMap to ensure that it satisfies this @c Request.
|
||||
/// @c returns @c true if the request is satisfied; @c false otherwise.
|
||||
bool validate(const Map &) const;
|
||||
|
||||
std::vector<Description> all_descriptions() const;
|
||||
|
||||
private:
|
||||
struct Node {
|
||||
enum class Type {
|
||||
Any, All, One
|
||||
};
|
||||
Type type = Type::One;
|
||||
Name name = Name::Invalid;
|
||||
/// @c true if this ROM is optional for machine startup. Generally indicates something
|
||||
/// that would make emulation more accurate, but not sufficiently so to make it
|
||||
/// a necessity.
|
||||
bool is_optional = false;
|
||||
std::vector<Node> children;
|
||||
|
||||
void add_descriptions(std::vector<Description> &);
|
||||
};
|
||||
Node node;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ROMCatalogue_hpp */
|
@ -1019,6 +1019,8 @@
|
||||
4B047075201ABC180047AB0D /* Cartridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
|
||||
4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = "<group>"; };
|
||||
4B04B65622A58CB40006AB58 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
|
||||
4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ROMCatalogue.cpp; sourceTree = "<group>"; };
|
||||
4B051C5926670A9300CA44E8 /* ROMCatalogue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMCatalogue.hpp; sourceTree = "<group>"; };
|
||||
4B05401D219D1618001BF69C /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
|
||||
4B055A6A1FAE763F0060FFFF /* Clock Signal Kiosk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Clock Signal Kiosk"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
4B055A771FAE78210060FFFF /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = ../../../../Library/Frameworks/SDL2.framework; sourceTree = SOURCE_ROOT; };
|
||||
@ -2415,11 +2417,13 @@
|
||||
4B055ABE1FAE98000060FFFF /* MachineForTarget.cpp */,
|
||||
4B2B3A481F9B8FA70062DABF /* MemoryFuzzer.cpp */,
|
||||
4BCE005B227D30CC000CA200 /* MemoryPacker.cpp */,
|
||||
4B051C5826670A9300CA44E8 /* ROMCatalogue.cpp */,
|
||||
4B17B58920A8A9D9007CCA8F /* StringSerialiser.cpp */,
|
||||
4B2B3A471F9B8FA70062DABF /* Typer.cpp */,
|
||||
4B055ABF1FAE98000060FFFF /* MachineForTarget.hpp */,
|
||||
4B2B3A491F9B8FA70062DABF /* MemoryFuzzer.hpp */,
|
||||
4BCE005C227D30CC000CA200 /* MemoryPacker.hpp */,
|
||||
4B051C5926670A9300CA44E8 /* ROMCatalogue.hpp */,
|
||||
4B17B58A20A8A9D9007CCA8F /* StringSerialiser.hpp */,
|
||||
4B79A4FE1FC9082300EEDAD5 /* TypedDynamicMachine.hpp */,
|
||||
4B2B3A4A1F9B8FA70062DABF /* Typer.hpp */,
|
||||
|
Loading…
Reference in New Issue
Block a user