1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +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());