1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-07-16 00:24:11 +00:00

Modifies the Vic-20 and C1540 to bring them into the realm of self-ROM fetching.

Hence enables Vic-20 support within kiosk mode as currently drafted.
This commit is contained in:
Thomas Harte
2017-11-07 21:19:51 -05:00
parent 35da3edf60
commit ddcdd07dd0
15 changed files with 252 additions and 139 deletions

View File

@@ -919,21 +919,23 @@ class ConcreteMachine:
} }
// See header; provides the system ROMs. // See header; provides the system ROMs.
void set_rom(ROMType type, std::vector<uint8_t> data) override final { void set_rom(ROMType type, const std::vector<uint8_t> &data) override final {
roms_[static_cast<int>(type)] = data; roms_[static_cast<int>(type)] = data;
} }
// Obtains the system ROMs. // Obtains the system ROMs.
bool install_roms(const std::function<std::unique_ptr<std::vector<uint8_t>>(const std::string &machine, const std::string &name)> &rom_with_name) override { bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) override {
const char *os_files[] = { auto roms = roms_with_names(
"os464.rom", "basic464.rom", "AmstradCPC",
"os664.rom", "basic664.rom", {
"os6128.rom", "basic6128.rom", "os464.rom", "basic464.rom",
"amsdos.rom" "os664.rom", "basic664.rom",
}; "os6128.rom", "basic6128.rom",
"amsdos.rom"
});
for(size_t index = 0; index < sizeof(os_files) / sizeof(*os_files); ++index) { for(size_t index = 0; index < roms.size(); ++index) {
auto data = rom_with_name("AmstradCPC", os_files[index]); auto &data = roms[index];
if(!data) return false; if(!data) return false;
set_rom(static_cast<ROMType>(index), *data); set_rom(static_cast<ROMType>(index), *data);
} }

View File

@@ -39,7 +39,7 @@ class Machine:
static Machine *AmstradCPC(); static Machine *AmstradCPC();
/// Sets the contents of rom @c type to @c data. Assumed to be a setup step; has no effect once a machine is running. /// Sets the contents of rom @c type to @c data. Assumed to be a setup step; has no effect once a machine is running.
virtual void set_rom(ROMType type, std::vector<uint8_t> data) = 0; virtual void set_rom(ROMType type, const std::vector<uint8_t> &data) = 0;
}; };
} }

View File

@@ -12,6 +12,7 @@
#include "../Outputs/CRT/CRT.hpp" #include "../Outputs/CRT/CRT.hpp"
#include "../Outputs/Speaker.hpp" #include "../Outputs/Speaker.hpp"
#include "../ClockReceiver/ClockReceiver.hpp" #include "../ClockReceiver/ClockReceiver.hpp"
#include "ROMMachine.hpp"
namespace CRTMachine { namespace CRTMachine {
@@ -20,7 +21,7 @@ namespace CRTMachine {
that optionally provide a speaker, and that nominate a clock rate and can announce to a delegate that optionally provide a speaker, and that nominate a clock rate and can announce to a delegate
should that clock rate change. should that clock rate change.
*/ */
class Machine { class Machine: public ROMMachine::Machine {
public: public:
Machine() : clock_is_unlimited_(false), delegate_(nullptr) {} Machine() : clock_is_unlimited_(false), delegate_(nullptr) {}
@@ -36,11 +37,6 @@ class Machine {
*/ */
virtual void close_output() = 0; virtual void close_output() = 0;
/*!
Provides the machine with a way to obtain such ROMs as it needs.
*/
virtual bool install_roms(const std::function<std::unique_ptr<std::vector<uint8_t>>(const std::string &machine, const std::string &name)> &rom_with_name) { return true; }
/// @returns The CRT this machine is drawing to. Should not be @c nullptr. /// @returns The CRT this machine is drawing to. Should not be @c nullptr.
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() = 0; virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() = 0;

View File

@@ -10,6 +10,7 @@
#define Commodore1540_hpp #define Commodore1540_hpp
#include "../SerialBus.hpp" #include "../SerialBus.hpp"
#include "../../ROMMachine.hpp"
#include "../../../Storage/Disk/Disk.hpp" #include "../../../Storage/Disk/Disk.hpp"
#include "Implementation/C1540Base.hpp" #include "Implementation/C1540Base.hpp"
@@ -19,12 +20,18 @@ namespace C1540 {
/*! /*!
Provides an emulation of the C1540. Provides an emulation of the C1540.
*/ */
class Machine: public MachineBase { class Machine: public MachineBase, public ROMMachine::Machine {
public: public:
enum Personality {
C1540,
C1541
};
Machine(Personality p);
/*! /*!
Sets the ROM image to use for this drive; it is asserted that the buffer provided is 16 kb in size. Sets the source for this drive's ROM image.
*/ */
void set_rom(const std::vector<uint8_t> &rom); bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names);
/*! /*!
Sets the serial bus to which this drive should attach itself. Sets the serial bus to which this drive should attach itself.
@@ -36,6 +43,9 @@ class Machine: public MachineBase {
/// Inserts @c disk into the drive. /// Inserts @c disk into the drive.
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk); void set_disk(std::shared_ptr<Storage::Disk::Disk> disk);
private:
Personality personality_;
}; };
} }

View File

@@ -40,6 +40,8 @@ MachineBase::MachineBase() :
set_drive(drive_); set_drive(drive_);
} }
Machine::Machine(Commodore::C1540::Machine::Personality personality) : personality_(personality) {}
void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus) { void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus) {
Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus); Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus);
} }
@@ -80,9 +82,17 @@ Cycles MachineBase::perform_bus_operation(CPU::MOS6502::BusOperation operation,
return Cycles(1); return Cycles(1);
} }
void Machine::set_rom(const std::vector<uint8_t> &rom) { bool Machine::set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) {
assert(rom.size() == sizeof(rom_)); std::string rom_name;
memcpy(rom_, rom.data(), std::min(sizeof(rom_), rom.size())); switch(personality_) {
case Personality::C1540: rom_name = "1540.bin"; break;
case Personality::C1541: rom_name = "1541.bin"; break;
}
auto roms = roms_with_names("Commodore1540", {rom_name});
if(!roms[0]) return false;
memcpy(rom_, roms[0]->data(), std::min(sizeof(rom_), roms[0]->size()));
return true;
} }
void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk) { void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk) {

View File

@@ -37,6 +37,18 @@ enum JoystickInput {
Fire = 0x20 Fire = 0x20
}; };
enum ROM {
CharactersDanish = 0,
CharactersEnglish,
CharactersJapanese,
CharactersSwedish,
KernelDanish,
KernelJapanese,
KernelNTSC,
KernelPAL,
KernelSwedish
};
/*! /*!
Models the user-port VIA, which is the Vic's connection point for controlling its tape recorder — Models the user-port VIA, which is the Vic's connection point for controlling its tape recorder —
sensing the presence or absence of a tape and controlling the tape motor — and reading the current sensing the presence or absence of a tape and controlling the tape motor — and reading the current
@@ -280,12 +292,6 @@ class ConcreteMachine:
keyboard_via_port_handler_->set_interrupt_delegate(this); keyboard_via_port_handler_->set_interrupt_delegate(this);
tape_->set_delegate(this); tape_->set_delegate(this);
// establish the memory maps
set_memory_size(MemorySize::Default);
// set the NTSC clock rate
set_region(NTSC);
// install a joystick // install a joystick
joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_));
} }
@@ -294,24 +300,32 @@ class ConcreteMachine:
delete[] rom_; delete[] rom_;
} }
void set_rom(ROMSlot slot, size_t length, const uint8_t *data) override final { void set_rom(ROMSlot slot, const std::vector<uint8_t> &data) override final {
uint8_t *target = nullptr; }
size_t max_length = 0x2000;
switch(slot) {
case Kernel: target = kernel_rom_; break;
case Characters: target = character_rom_; max_length = 0x1000; break;
case BASIC: target = basic_rom_; break;
case Drive:
drive_rom_.resize(length);
memcpy(drive_rom_.data(), data, length);
install_disk_rom();
return;
}
if(target) { // Obtains the system ROMs.
size_t length_to_copy = std::min(max_length, length); bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) override {
memcpy(target, data, length_to_copy); auto roms = roms_with_names(
"Vic20",
{
"characters-danish.bin",
"characters-english.bin",
"characters-japanese.bin",
"characters-swedish.bin",
"kernel-danish.bin",
"kernel-japanese.bin",
"kernel-ntsc.bin",
"kernel-pal.bin",
"kernel-swedish.bin",
"basic.bin"
});
for(size_t index = 0; index < roms.size(); ++index) {
auto &data = roms[index];
if(!data) return false;
if(index < 9) roms_[index] = *data; else basic_rom_ = *data;
} }
return true;
} }
void configure_as_target(const StaticAnalyser::Target &target) override final { void configure_as_target(const StaticAnalyser::Target &target) override final {
@@ -333,13 +347,13 @@ class ConcreteMachine:
if(target.media.disks.size()) { if(target.media.disks.size()) {
// construct the 1540 // construct the 1540
c1540_.reset(new ::Commodore::C1540::Machine); c1540_.reset(new ::Commodore::C1540::Machine(Commodore::C1540::Machine::C1540));
// attach it to the serial bus // attach it to the serial bus
c1540_->set_serial_bus(serial_bus_); c1540_->set_serial_bus(serial_bus_);
// install the ROM if it was previously set // give it a means to obtain its ROM
install_disk_rom(); c1540_->set_rom_fetcher(rom_fetcher_);
} }
insert_media(target.media); insert_media(target.media);
@@ -383,10 +397,38 @@ class ConcreteMachine:
} }
void set_memory_size(MemorySize size) override final { void set_memory_size(MemorySize size) override final {
memory_size_ = size;
needs_configuration_ = true;
}
void set_region(Region region) override final {
region_ = region;
needs_configuration_ = true;
}
void configure_memory() {
// Determine PAL/NTSC
if(region_ == American || region_ == Japanese) {
// NTSC
set_clock_rate(1022727);
if(mos6560_) {
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
mos6560_->set_clock_rate(1022727);
}
} else {
// PAL
set_clock_rate(1108404);
if(mos6560_) {
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
mos6560_->set_clock_rate(1108404);
}
}
memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_)); memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_));
memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_)); memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_));
memset(mos6560_->video_memory_map, 0, sizeof(mos6560_->video_memory_map));
switch(size) { switch(memory_size_) {
default: break; default: break;
case ThreeKB: case ThreeKB:
write_to_map(processor_read_memory_map_, expansion_ram_, 0x0000, 0x1000); write_to_map(processor_read_memory_map_, expansion_ram_, 0x0000, 0x1000);
@@ -402,40 +444,52 @@ class ConcreteMachine:
write_to_map(processor_read_memory_map_, user_basic_memory_, 0x0000, sizeof(user_basic_memory_)); write_to_map(processor_read_memory_map_, user_basic_memory_, 0x0000, sizeof(user_basic_memory_));
write_to_map(processor_read_memory_map_, screen_memory_, 0x1000, sizeof(screen_memory_)); write_to_map(processor_read_memory_map_, screen_memory_, 0x1000, sizeof(screen_memory_));
write_to_map(processor_read_memory_map_, colour_memory_, 0x9400, sizeof(colour_memory_)); write_to_map(processor_read_memory_map_, colour_memory_, 0x9400, sizeof(colour_memory_));
write_to_map(processor_read_memory_map_, character_rom_, 0x8000, sizeof(character_rom_));
write_to_map(processor_read_memory_map_, basic_rom_, 0xc000, sizeof(basic_rom_));
write_to_map(processor_read_memory_map_, kernel_rom_, 0xe000, sizeof(kernel_rom_));
write_to_map(processor_write_memory_map_, user_basic_memory_, 0x0000, sizeof(user_basic_memory_)); write_to_map(processor_write_memory_map_, user_basic_memory_, 0x0000, sizeof(user_basic_memory_));
write_to_map(processor_write_memory_map_, screen_memory_, 0x1000, sizeof(screen_memory_)); write_to_map(processor_write_memory_map_, screen_memory_, 0x1000, sizeof(screen_memory_));
write_to_map(processor_write_memory_map_, colour_memory_, 0x9400, sizeof(colour_memory_)); write_to_map(processor_write_memory_map_, colour_memory_, 0x9400, sizeof(colour_memory_));
write_to_map(mos6560_->video_memory_map, user_basic_memory_, 0x2000, sizeof(user_basic_memory_));
write_to_map(mos6560_->video_memory_map, screen_memory_, 0x3000, sizeof(screen_memory_));
mos6560_->colour_memory = colour_memory_;
write_to_map(processor_read_memory_map_, basic_rom_.data(), 0xc000, basic_rom_.size());
ROM character_rom;
ROM kernel_rom;
switch(region_) {
case American:
character_rom = CharactersEnglish;
kernel_rom = KernelNTSC;
break;
case Danish:
character_rom = CharactersDanish;
kernel_rom = KernelDanish;
break;
case Japanese:
character_rom = CharactersJapanese;
kernel_rom = KernelJapanese;
break;
case European:
character_rom = CharactersEnglish;
kernel_rom = KernelPAL;
break;
case Swedish:
character_rom = CharactersSwedish;
kernel_rom = KernelSwedish;
break;
}
write_to_map(processor_read_memory_map_, roms_[character_rom].data(), 0x8000, roms_[character_rom].size());
write_to_map(mos6560_->video_memory_map, roms_[character_rom].data(), 0x0000, roms_[character_rom].size());
write_to_map(processor_read_memory_map_, roms_[kernel_rom].data(), 0xe000, roms_[kernel_rom].size());
// install the inserted ROM if there is one // install the inserted ROM if there is one
if(rom_) { if(rom_) {
write_to_map(processor_read_memory_map_, rom_, rom_address_, rom_length_); write_to_map(processor_read_memory_map_, rom_, rom_address_, rom_length_);
} }
} }
void set_region(Region region) override final {
region_ = region;
switch(region) {
case PAL:
set_clock_rate(1108404);
if(mos6560_) {
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
mos6560_->set_clock_rate(1108404);
}
break;
case NTSC:
set_clock_rate(1022727);
if(mos6560_) {
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
mos6560_->set_clock_rate(1022727);
}
break;
}
}
void set_use_fast_tape_hack(bool activate) override final { void set_use_fast_tape_hack(bool activate) override final {
use_fast_tape_hack_ = activate; use_fast_tape_hack_ = activate;
} }
@@ -542,19 +596,16 @@ class ConcreteMachine:
} }
void run_for(const Cycles cycles) override final { void run_for(const Cycles cycles) override final {
if(needs_configuration_) {
needs_configuration_ = false;
configure_memory();
}
m6502_.run_for(cycles); m6502_.run_for(cycles);
} }
void setup_output(float aspect_ratio) override final { void setup_output(float aspect_ratio) override final {
mos6560_.reset(new Vic6560()); mos6560_.reset(new Vic6560());
mos6560_->get_speaker()->set_high_frequency_cut_off(1600); // There is a 1.6Khz low-pass filter in the Vic-20. mos6560_->get_speaker()->set_high_frequency_cut_off(1600); // There is a 1.6Khz low-pass filter in the Vic-20.
set_region(region_);
memset(mos6560_->video_memory_map, 0, sizeof(mos6560_->video_memory_map));
write_to_map(mos6560_->video_memory_map, character_rom_, 0x0000, sizeof(character_rom_));
write_to_map(mos6560_->video_memory_map, user_basic_memory_, 0x2000, sizeof(user_basic_memory_));
write_to_map(mos6560_->video_memory_map, screen_memory_, 0x3000, sizeof(screen_memory_));
mos6560_->colour_memory = colour_memory_;
} }
void close_output() override final { void close_output() override final {
@@ -590,9 +641,11 @@ class ConcreteMachine:
private: private:
CPU::MOS6502::Processor<ConcreteMachine, false> m6502_; CPU::MOS6502::Processor<ConcreteMachine, false> m6502_;
uint8_t character_rom_[0x1000]; std::vector<uint8_t> roms_[9];
uint8_t basic_rom_[0x2000];
uint8_t kernel_rom_[0x2000]; std::vector<uint8_t> character_rom_;
std::vector<uint8_t> basic_rom_;
std::vector<uint8_t> kernel_rom_;
uint8_t expansion_ram_[0x8000]; uint8_t expansion_ram_[0x8000];
uint8_t *rom_; uint8_t *rom_;
@@ -601,7 +654,8 @@ class ConcreteMachine:
uint8_t user_basic_memory_[0x0400]; uint8_t user_basic_memory_[0x0400];
uint8_t screen_memory_[0x1000]; uint8_t screen_memory_[0x1000];
uint8_t colour_memory_[0x0400]; uint8_t colour_memory_[0x0400];
std::vector<uint8_t> drive_rom_;
std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> rom_fetcher_;
uint8_t *processor_read_memory_map_[64]; uint8_t *processor_read_memory_map_[64];
uint8_t *processor_write_memory_map_[64]; uint8_t *processor_write_memory_map_[64];
@@ -615,7 +669,10 @@ class ConcreteMachine:
} }
} }
Region region_; Region region_ = European;
MemorySize memory_size_ = MemorySize::Default;
bool needs_configuration_ = true;
Commodore::Vic20::KeyboardMapper keyboard_mapper_; Commodore::Vic20::KeyboardMapper keyboard_mapper_;
std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_; std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_;
@@ -635,13 +692,6 @@ class ConcreteMachine:
// Disk // Disk
std::shared_ptr<::Commodore::C1540::Machine> c1540_; std::shared_ptr<::Commodore::C1540::Machine> c1540_;
void install_disk_rom() {
if(!drive_rom_.empty() && c1540_) {
c1540_->set_rom(drive_rom_);
c1540_->run_for(Cycles(2000000));
drive_rom_.clear();
}
}
}; };
} }

View File

@@ -20,7 +20,7 @@ namespace Commodore {
namespace Vic20 { namespace Vic20 {
enum ROMSlot { enum ROMSlot {
Kernel, Kernel = 0,
BASIC, BASIC,
Characters, Characters,
Drive Drive
@@ -33,8 +33,11 @@ enum MemorySize {
}; };
enum Region { enum Region {
NTSC, American,
PAL Danish,
Japanese,
European,
Swedish
}; };
class Machine: class Machine:
@@ -49,8 +52,7 @@ class Machine:
static Machine *Vic20(); static Machine *Vic20();
/// Sets the contents of the rom in @c slot to the buffer @c data of length @c length. /// Sets the contents of the rom in @c slot to the buffer @c data of length @c length.
virtual void set_rom(ROMSlot slot, size_t length, const uint8_t *data) = 0; virtual void set_rom(ROMSlot slot, const std::vector<uint8_t> &data) = 0;
// TODO: take a std::vector<uint8_t> to collapse length and data.
/// Sets the memory size of this Vic-20. /// Sets the memory size of this Vic-20.
virtual void set_memory_size(MemorySize size) = 0; virtual void set_memory_size(MemorySize size) = 0;

View File

@@ -39,7 +39,7 @@ class ConcreteMachine:
set_clock_rate(2000000); set_clock_rate(2000000);
} }
void set_rom(ROMSlot slot, std::vector<uint8_t> data, bool is_writeable) override final { void set_rom(ROMSlot slot, const std::vector<uint8_t> &data, bool is_writeable) override final {
uint8_t *target = nullptr; uint8_t *target = nullptr;
switch(slot) { switch(slot) {
case ROMSlotDFS: dfs_ = data; return; case ROMSlotDFS: dfs_ = data; return;
@@ -57,20 +57,22 @@ class ConcreteMachine:
} }
// Obtains the system ROMs. // Obtains the system ROMs.
bool install_roms(const std::function<std::unique_ptr<std::vector<uint8_t>>(const std::string &machine, const std::string &name)> &rom_with_name) override { bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) override {
auto roms = roms_with_names(
"Electron",
{
"DFS-1770-2.20.rom",
"ADFS-E00_1.rom", "ADFS-E00_2.rom",
"basic.rom", "os.rom"
});
ROMSlot slots[] = { ROMSlot slots[] = {
ROMSlotDFS, ROMSlotDFS,
ROMSlotADFS1, ROMSlotADFS2, ROMSlotADFS1, ROMSlotADFS2,
ROMSlotBASIC, ROMSlotOS ROMSlotBASIC, ROMSlotOS
}; };
const char *os_files[] = {
"DFS-1770-2.20.rom",
"ADFS-E00_1.rom", "ADFS-E00_2.rom",
"basic.rom", "os.rom"
};
for(size_t index = 0; index < sizeof(os_files) / sizeof(*os_files); ++index) { for(size_t index = 0; index < roms.size(); ++index) {
auto data = rom_with_name("Electron", os_files[index]); auto &data = roms[index];
if(!data) return false; if(!data) return false;
set_rom(slots[index], *data, false); set_rom(slots[index], *data, false);
} }

View File

@@ -52,7 +52,7 @@ class Machine:
Sets the contents of @c slot to @c data. If @c is_writeable is @c true then writing to the slot Sets the contents of @c slot to @c data. If @c is_writeable is @c true then writing to the slot
is enabled — it acts as if it were sideways RAM. Otherwise the slot is modelled as containing ROM. is enabled — it acts as if it were sideways RAM. Otherwise the slot is modelled as containing ROM.
*/ */
virtual void set_rom(ROMSlot slot, std::vector<uint8_t> data, bool is_writeable) = 0; virtual void set_rom(ROMSlot slot, const std::vector<uint8_t> &data, bool is_writeable) = 0;
/// Enables or disables turbo-speed tape loading. /// Enables or disables turbo-speed tape loading.
virtual void set_use_fast_tape_hack(bool activate) = 0; virtual void set_use_fast_tape_hack(bool activate) = 0;

View File

@@ -204,14 +204,16 @@ class ConcreteMachine:
} }
// Obtains the system ROMs. // Obtains the system ROMs.
bool install_roms(const std::function<std::unique_ptr<std::vector<uint8_t>>(const std::string &machine, const std::string &name)> &rom_with_name) override { bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) override {
const char *os_files[] = { auto roms = roms_with_names(
"basic10.rom", "basic11.rom", "Oric",
"microdisc.rom", "colour.rom" {
}; "basic10.rom", "basic11.rom",
"microdisc.rom", "colour.rom"
});
for(size_t index = 0; index < sizeof(os_files) / sizeof(*os_files); ++index) { for(size_t index = 0; index < roms.size(); ++index) {
auto data = rom_with_name("Oric", os_files[index]); auto &data = roms[index];
if(!data) return false; if(!data) return false;
set_rom(static_cast<ROM>(index), *data); set_rom(static_cast<ROM>(index), *data);
} }

27
Machines/ROMMachine.hpp Normal file
View File

@@ -0,0 +1,27 @@
//
// ROMMachine.hpp
// Clock Signal
//
// Created by Thomas Harte on 07/11/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#ifndef ROMMachine_hpp
#define ROMMachine_hpp
#include <functional>
#include <memory>
#include <vector>
namespace ROMMachine {
struct Machine {
/*!
Provides the machine with a way to obtain such ROMs as it needs.
*/
virtual bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &rom_with_name) { return true; }
};
}
#endif /* ROMMachine_h */

View File

@@ -290,7 +290,7 @@ template<bool is_zx81> class ConcreteMachine:
Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper)); Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
} }
void set_rom(ROMType type, std::vector<uint8_t> data) override final { void set_rom(ROMType type, const std::vector<uint8_t> &data) override final {
switch(type) { switch(type) {
case ZX80: zx80_rom_ = data; break; case ZX80: zx80_rom_ = data; break;
case ZX81: zx81_rom_ = data; break; case ZX81: zx81_rom_ = data; break;
@@ -298,13 +298,15 @@ template<bool is_zx81> class ConcreteMachine:
} }
// Obtains the system ROMs. // Obtains the system ROMs.
bool install_roms(const std::function<std::unique_ptr<std::vector<uint8_t>>(const std::string &machine, const std::string &name)> &rom_with_name) override { bool set_rom_fetcher(const std::function<std::vector<std::unique_ptr<std::vector<uint8_t>>>(const std::string &machine, const std::vector<std::string> &names)> &roms_with_names) override {
const char *os_files[] = { auto roms = roms_with_names(
"zx80.rom", "zx81.rom", "ZX8081",
}; {
"zx80.rom", "zx81.rom",
});
for(size_t index = 0; index < sizeof(os_files) / sizeof(*os_files); ++index) { for(size_t index = 0; index < roms.size(); ++index) {
auto data = rom_with_name("ZX8081", os_files[index]); auto &data = roms[index];
if(!data) return false; if(!data) return false;
set_rom(static_cast<ROMType>(index), *data); set_rom(static_cast<ROMType>(index), *data);
} }

View File

@@ -30,7 +30,7 @@ class Machine:
static Machine *ZX8081(const StaticAnalyser::Target &target_hint); static Machine *ZX8081(const StaticAnalyser::Target &target_hint);
virtual ~Machine(); virtual ~Machine();
virtual void set_rom(ROMType type, std::vector<uint8_t> data) = 0; virtual void set_rom(ROMType type, const std::vector<uint8_t> &data) = 0;
virtual void set_use_fast_tape_hack(bool activate) = 0; virtual void set_use_fast_tape_hack(bool activate) = 0;
virtual void set_tape_is_playing(bool is_playing) = 0; virtual void set_tape_is_playing(bool is_playing) = 0;

View File

@@ -1210,6 +1210,7 @@
4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = "<group>"; }; 4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = "<group>"; };
4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSBestEffortUpdater.mm; path = Updater/CSBestEffortUpdater.mm; sourceTree = "<group>"; }; 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSBestEffortUpdater.mm; path = Updater/CSBestEffortUpdater.mm; sourceTree = "<group>"; };
4BD9137D1F311BC5009BCF85 /* i8255.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = i8255.hpp; path = 8255/i8255.hpp; sourceTree = "<group>"; }; 4BD9137D1F311BC5009BCF85 /* i8255.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = i8255.hpp; path = 8255/i8255.hpp; sourceTree = "<group>"; };
4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMMachine.hpp; sourceTree = "<group>"; };
4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = "<group>"; }; 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = "<group>"; };
4BE77A2C1D84ADFB00BC3827 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = File.cpp; path = ../../StaticAnalyser/Commodore/File.cpp; sourceTree = "<group>"; }; 4BE77A2C1D84ADFB00BC3827 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = File.cpp; path = ../../StaticAnalyser/Commodore/File.cpp; sourceTree = "<group>"; };
4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = "<group>"; }; 4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = "<group>"; };
@@ -2352,6 +2353,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */, 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */,
4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */,
4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */, 4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */,
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */, 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */,
4B7041271F92C26900735E45 /* JoystickMachine.hpp */, 4B7041271F92C26900735E45 /* JoystickMachine.hpp */,

View File

@@ -179,25 +179,33 @@ int main(int argc, char *argv[]) {
// //
// /usr/local/share/CLK/[system]; or // /usr/local/share/CLK/[system]; or
// /usr/share/CLK/[system] // /usr/share/CLK/[system]
machine->crt_machine()->install_roms( [] (const std::string &machine, const std::string &name) -> std::unique_ptr<std::vector<uint8_t>> { machine->crt_machine()->set_rom_fetcher( [] (const std::string &machine, const std::vector<std::string> &names) -> std::vector<std::unique_ptr<std::vector<uint8_t>>> {
std::string local_path = "/usr/local/share/CLK/" + machine + "/" + name; std::vector<std::unique_ptr<std::vector<uint8_t>>> results;
FILE *file = fopen(local_path.c_str(), "r"); for(auto &name: names) {
if(!file) { std::string local_path = "/usr/local/share/CLK/" + machine + "/" + name;
std::string path = "/usr/share/CLK/" + machine + "/" + name; FILE *file = fopen(local_path.c_str(), "r");
file = fopen(path.c_str(), "r"); if(!file) {
std::string path = "/usr/share/CLK/" + machine + "/" + name;
file = fopen(path.c_str(), "r");
}
if(!file) {
results.emplace_back(nullptr);
continue;
}
std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>);
fseek(file, 0, SEEK_END);
data->resize(ftell(file));
fseek(file, 0, SEEK_SET);
fread(data->data(), 1, data->size(), file);
fclose(file);
results.emplace_back(std::move(data));
} }
if(!file) return nullptr; return results;
std::unique_ptr<std::vector<uint8_t>> data(new std::vector<uint8_t>);
fseek(file, 0, SEEK_END);
data->resize(ftell(file));
fseek(file, 0, SEEK_SET);
fread(data->data(), 1, data->size(), file);
fclose(file);
return data;
}); });
machine->configuration_target()->configure_as_target(targets.front()); machine->configuration_target()->configure_as_target(targets.front());