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:
parent
35da3edf60
commit
ddcdd07dd0
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
27
Machines/ROMMachine.hpp
Normal 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 */
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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 */,
|
||||||
|
@ -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());
|
||||||
|
Loading…
Reference in New Issue
Block a user