mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-19 07:31:15 +00:00
Fix serialiser ownership, Commodore analyser.
This commit is contained in:
parent
bde2047184
commit
0f545608c4
@ -160,163 +160,195 @@ std::optional<BASICAnalysis> analyse(const File &file) {
|
||||
return analysis;
|
||||
}
|
||||
|
||||
template <typename TargetT>
|
||||
void set_loading_command(TargetT &target) {
|
||||
if(target.media.disks.empty()) {
|
||||
target.loading_command = "LOAD\"\",1,1\nRUN\n";
|
||||
} else {
|
||||
target.loading_command = "LOAD\"*\",8,1\nRUN\n";
|
||||
}
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &file_name,
|
||||
TargetPlatform::IntType platforms,
|
||||
bool is_confident
|
||||
) {
|
||||
TargetList destination;
|
||||
auto target = std::make_unique<Target>();
|
||||
bool obviously_uses_ted(const File &file) {
|
||||
const auto analysis = analyse(file);
|
||||
if(!analysis) return false;
|
||||
|
||||
// Disassemble.
|
||||
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
|
||||
file.data,
|
||||
Analyser::Static::Disassembler::OffsetMapper(file.starting_address),
|
||||
analysis->machine_code_addresses
|
||||
);
|
||||
|
||||
// If FF3E or FF3F is touched, this is for the +4.
|
||||
// TODO: probably require a very early touch.
|
||||
for(const auto address: {0xff3e, 0xff3f}) {
|
||||
for(const auto &collection: {
|
||||
disassembly.external_loads,
|
||||
disassembly.external_stores,
|
||||
disassembly.external_modifies
|
||||
}) {
|
||||
if(collection.find(uint16_t(address)) != collection.end()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct FileAnalysis {
|
||||
int device = 0;
|
||||
std::vector<File> files;
|
||||
bool is_disk = false;
|
||||
Analyser::Static::Media media;
|
||||
};
|
||||
|
||||
template <TargetPlatform::IntType platform>
|
||||
FileAnalysis analyse_files(const Analyser::Static::Media &media) {
|
||||
FileAnalysis analysis;
|
||||
|
||||
// Find all valid Commodore files on disks.
|
||||
for(auto &disk : media.disks) {
|
||||
std::vector<File> disk_files = GetFiles(disk);
|
||||
if(!disk_files.empty()) {
|
||||
analysis.is_disk = true;
|
||||
analysis.files.insert(
|
||||
analysis.files.end(),
|
||||
std::make_move_iterator(disk_files.begin()),
|
||||
std::make_move_iterator(disk_files.end())
|
||||
);
|
||||
analysis.media.disks.push_back(disk);
|
||||
if(!analysis.device) analysis.device = 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Find all valid Commodore files on tapes.
|
||||
for(auto &tape : media.tapes) {
|
||||
auto serialiser = tape->serialiser();
|
||||
std::vector<File> tape_files = GetFiles(*serialiser);
|
||||
if(!tape_files.empty()) {
|
||||
analysis.files.insert(
|
||||
analysis.files.end(),
|
||||
std::make_move_iterator(tape_files.begin()),
|
||||
std::make_move_iterator(tape_files.end())
|
||||
);
|
||||
analysis.media.tapes.push_back(tape);
|
||||
if(!analysis.device) analysis.device = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return analysis;
|
||||
}
|
||||
|
||||
std::string loading_command(const FileAnalysis &file_analysis) {
|
||||
std::ostringstream string_stream;
|
||||
string_stream << "LOAD\"" << (file_analysis.is_disk ? "*" : "") << "\"," << file_analysis.device;
|
||||
|
||||
const auto analysis = analyse(file_analysis.files[0]);
|
||||
if(analysis && !analysis->machine_code_addresses.empty()) {
|
||||
string_stream << ",1";
|
||||
}
|
||||
string_stream << "\nRUN\n";
|
||||
return string_stream.str();
|
||||
}
|
||||
|
||||
std::pair<TargetPlatform::IntType, std::optional<Vic20Target::MemoryModel>>
|
||||
analyse_starting_address(uint16_t starting_address) {
|
||||
switch(starting_address) {
|
||||
case 0x1c01:
|
||||
// TODO: assume C128.
|
||||
default:
|
||||
Log::Logger<Log::Source::CommodoreStaticAnalyser>().error().append(
|
||||
"Unrecognised loading address for Commodore program: %04x", starting_address);
|
||||
[[fallthrough]];
|
||||
case 0x1001:
|
||||
return std::make_pair(TargetPlatform::Vic20 | TargetPlatform::Plus4, Vic20Target::MemoryModel::Unexpanded);
|
||||
|
||||
case 0x1201: return std::make_pair(TargetPlatform::Vic20, Vic20Target::MemoryModel::ThirtyTwoKB);
|
||||
case 0x0401: return std::make_pair(TargetPlatform::Vic20, Vic20Target::MemoryModel::EightKB);
|
||||
case 0x0801: return std::make_pair(TargetPlatform::C64, std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
template <TargetPlatform::IntType platform>
|
||||
std::unique_ptr<Analyser::Static::Target> get_target(
|
||||
const Analyser::Static::Media &media,
|
||||
const std::string &file_name,
|
||||
bool is_confident
|
||||
);
|
||||
|
||||
template<>
|
||||
std::unique_ptr<Analyser::Static::Target> get_target<TargetPlatform::Plus4>(
|
||||
const Analyser::Static::Media &media,
|
||||
const std::string &,
|
||||
bool is_confident
|
||||
) {
|
||||
auto target = std::make_unique<Plus4Target>();
|
||||
if(is_confident) {
|
||||
target->media = media;
|
||||
set_loading_command(*target);
|
||||
} else {
|
||||
const auto files = analyse_files<TargetPlatform::Plus4>(media);
|
||||
if(!files.files.empty()) {
|
||||
target->loading_command = loading_command(files);
|
||||
}
|
||||
}
|
||||
|
||||
// Attach a 1541 if there are any disks here.
|
||||
target->has_c1541 = !target->media.disks.empty();
|
||||
return std::move(target);
|
||||
}
|
||||
|
||||
template<>
|
||||
std::unique_ptr<Analyser::Static::Target> get_target<TargetPlatform::Vic20>(
|
||||
const Analyser::Static::Media &media,
|
||||
const std::string &file_name,
|
||||
bool is_confident
|
||||
) {
|
||||
auto target = std::make_unique<Vic20Target>();
|
||||
const auto files = analyse_files<TargetPlatform::Vic20>(media);
|
||||
if(!files.files.empty()) {
|
||||
target->loading_command = loading_command(files);
|
||||
|
||||
const auto model = analyse_starting_address(files.files[0].starting_address);
|
||||
if(model.second.has_value()) {
|
||||
target->set_memory_model(*model.second);
|
||||
}
|
||||
}
|
||||
|
||||
if(is_confident) {
|
||||
target->media = media;
|
||||
if(target->media.disks.empty()) {
|
||||
target->loading_command = "LOAD\"\",1,1\nRUN\n";
|
||||
} else {
|
||||
target->loading_command = "LOAD\"*\",8,1\nRUN\n";
|
||||
}
|
||||
|
||||
if(platforms & TargetPlatform::C64) {
|
||||
return {}; // C64 not yet implemented.
|
||||
} else if(platforms & TargetPlatform::Vic20) {
|
||||
target->machine = Machine::Vic20;
|
||||
// TODO: pick a memory model.
|
||||
} else {
|
||||
target->machine = Machine::Plus4;
|
||||
}
|
||||
set_loading_command(*target);
|
||||
} else {
|
||||
// Strip out inappropriate cartridges.
|
||||
target->media.cartridges = Vic20CartridgesFrom(media.cartridges);
|
||||
|
||||
// Find all valid Commodore files on disks.
|
||||
for(auto &disk : media.disks) {
|
||||
std::vector<File> disk_files = GetFiles(disk);
|
||||
if(!disk_files.empty()) {
|
||||
is_disk = true;
|
||||
files.insert(
|
||||
files.end(),
|
||||
std::make_move_iterator(disk_files.begin()),
|
||||
std::make_move_iterator(disk_files.end())
|
||||
);
|
||||
target->media.disks.push_back(disk);
|
||||
if(!device) device = 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Find all valid Commodore files on tapes.
|
||||
for(auto &tape : media.tapes) {
|
||||
auto serialiser = tape->serialiser();
|
||||
std::vector<File> tape_files = GetFiles(*serialiser);
|
||||
if(!tape_files.empty()) {
|
||||
files.insert(
|
||||
files.end(),
|
||||
std::make_move_iterator(tape_files.begin()),
|
||||
std::make_move_iterator(tape_files.end())
|
||||
);
|
||||
target->media.tapes.push_back(tape);
|
||||
if(!device) device = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect discovered files to try to divine machine and memory model.
|
||||
auto vic_memory_model = Target::MemoryModel::Unexpanded;
|
||||
|
||||
auto it = files.begin();
|
||||
while(it != files.end()) {
|
||||
const auto &file = *it;
|
||||
|
||||
std::ostringstream string_stream;
|
||||
string_stream << "LOAD\"" << (is_disk ? "*" : "") << "\"," << device;
|
||||
|
||||
const auto analysis = analyse(file);
|
||||
if(analysis && !analysis->machine_code_addresses.empty()) {
|
||||
string_stream << ",1";
|
||||
|
||||
// Disassemble.
|
||||
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
|
||||
file.data,
|
||||
Analyser::Static::Disassembler::OffsetMapper(file.starting_address),
|
||||
analysis->machine_code_addresses
|
||||
);
|
||||
|
||||
// If FF3E or FF3F is touched, this is for the +4.
|
||||
// TODO: probably require a very early touch.
|
||||
for(const auto address: {0xff3e, 0xff3f}) {
|
||||
for(const auto &collection: {
|
||||
disassembly.external_loads,
|
||||
disassembly.external_stores,
|
||||
disassembly.external_modifies
|
||||
}) {
|
||||
if(collection.find(uint16_t(address)) != collection.end()) {
|
||||
target->machine = Machine::Plus4; // TODO: use a better target?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_stream << "\nRUN\n";
|
||||
if(it == files.begin()) {
|
||||
target->loading_command = string_stream.str();
|
||||
|
||||
// Make a guess for the Vic-20, if ultimately selected, based on loading address.
|
||||
// TODO: probably also discount other machines if starting address isn't 0x1001?
|
||||
switch(files.front().starting_address) {
|
||||
default:
|
||||
Log::Logger<Log::Source::CommodoreStaticAnalyser>().error().append(
|
||||
"Unrecognised loading address for Commodore program: %04x", files.front().starting_address);
|
||||
[[fallthrough]];
|
||||
case 0x1001:
|
||||
vic_memory_model = Target::MemoryModel::Unexpanded;
|
||||
// TODO: could be Vic-20 or Plus4.
|
||||
break;
|
||||
|
||||
case 0x1201:
|
||||
vic_memory_model = Target::MemoryModel::ThirtyTwoKB;
|
||||
target->machine = Machine::Vic20;
|
||||
break;
|
||||
case 0x0401:
|
||||
vic_memory_model = Target::MemoryModel::EightKB;
|
||||
target->machine = Machine::Vic20;
|
||||
break;
|
||||
|
||||
case 0x0801:
|
||||
// TODO: assume C64.
|
||||
break;
|
||||
case 0x1c01:
|
||||
// TODO: assume C128.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto &file : files.files) {
|
||||
// The Vic-20 never has RAM after 0x8000.
|
||||
if(file.ending_address >= 0x8000) {
|
||||
target->machine = Machine::Plus4;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
target->set_memory_model(vic_memory_model);
|
||||
|
||||
++it;
|
||||
if(obviously_uses_ted(file)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect filename for configuration hints.
|
||||
if(!target->media.empty()) {
|
||||
// Inspect filename for configuration hints.
|
||||
using Region = Analyser::Static::Commodore::Vic20Target::Region;
|
||||
|
||||
std::string lowercase_name = file_name;
|
||||
std::transform(lowercase_name.begin(), lowercase_name.end(), lowercase_name.begin(), ::tolower);
|
||||
|
||||
// Hint 1: 'ntsc' anywhere in the name implies America.
|
||||
if(lowercase_name.find("ntsc") != std::string::npos) {
|
||||
target->region = Analyser::Static::Commodore::Target::Region::American;
|
||||
target->region = Region::American;
|
||||
}
|
||||
|
||||
// Potential additional hints: check for TheC64 tags.
|
||||
// Potential additional hints: check for TheC64 tags; these are Vic-20 exclusive.
|
||||
auto final_underscore = lowercase_name.find_last_of('_');
|
||||
if(final_underscore != std::string::npos) {
|
||||
auto iterator = lowercase_name.begin() + ssize_t(final_underscore) + 1;
|
||||
@ -338,10 +370,10 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(
|
||||
target->enabled_ram.bank3 |= !strcmp(next_tag, "b3");
|
||||
target->enabled_ram.bank5 |= !strcmp(next_tag, "b5");
|
||||
if(!strcmp(next_tag, "tn")) { // i.e. NTSC.
|
||||
target->region = Analyser::Static::Commodore::Target::Region::American;
|
||||
target->region = Region::American;
|
||||
}
|
||||
if(!strcmp(next_tag, "tp")) { // i.e. PAL.
|
||||
target->region = Analyser::Static::Commodore::Target::Region::European;
|
||||
target->region = Region::European;
|
||||
}
|
||||
|
||||
// Unhandled:
|
||||
@ -352,11 +384,36 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(
|
||||
// RO: this disk image should be treated as read-only.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attach a 1540 if there are any disks here.
|
||||
target->has_c1540 = !target->media.disks.empty();
|
||||
// Attach a 1540 if there are any disks here.
|
||||
target->has_c1540 = !target->media.disks.empty();
|
||||
return std::move(target);
|
||||
}
|
||||
|
||||
destination.push_back(std::move(target));
|
||||
}
|
||||
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &file_name,
|
||||
TargetPlatform::IntType platforms,
|
||||
bool is_confident
|
||||
) {
|
||||
TargetList destination;
|
||||
|
||||
if(platforms & TargetPlatform::Vic20) {
|
||||
auto vic20 = get_target<TargetPlatform::Vic20>(media, file_name, is_confident);
|
||||
if(vic20) {
|
||||
destination.push_back(std::move(vic20));
|
||||
}
|
||||
}
|
||||
|
||||
if(platforms & TargetPlatform::Plus4) {
|
||||
auto plus4 = get_target<TargetPlatform::Plus4>(media, file_name, is_confident);
|
||||
if(plus4) {
|
||||
destination.push_back(std::move(plus4));
|
||||
}
|
||||
}
|
||||
|
||||
return destination;
|
||||
|
@ -15,7 +15,21 @@
|
||||
|
||||
namespace Analyser::Static::Commodore {
|
||||
|
||||
struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Target> {
|
||||
struct Plus4Target: public Analyser::Static::Target, public Reflection::StructImpl<Plus4Target> {
|
||||
// TODO: region, etc.
|
||||
std::string loading_command;
|
||||
bool has_c1541 = false;
|
||||
|
||||
Plus4Target() : Analyser::Static::Target(Machine::Plus4) {}
|
||||
|
||||
private:
|
||||
friend Reflection::StructImpl<Plus4Target>;
|
||||
void declare_fields() {
|
||||
DeclareField(has_c1541);
|
||||
}
|
||||
};
|
||||
|
||||
struct Vic20Target: public Analyser::Static::Target, public Reflection::StructImpl<Vic20Target> {
|
||||
enum class MemoryModel {
|
||||
Unexpanded,
|
||||
EightKB,
|
||||
@ -54,10 +68,10 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
|
||||
bool has_c1540 = false;
|
||||
std::string loading_command;
|
||||
|
||||
Target() : Analyser::Static::Target(Machine::Vic20) {}
|
||||
Vic20Target() : Analyser::Static::Target(Machine::Vic20) {}
|
||||
|
||||
private:
|
||||
friend Reflection::StructImpl<Target>;
|
||||
friend Reflection::StructImpl<Vic20Target>;
|
||||
void declare_fields() {
|
||||
DeclareField(enabled_ram.bank0);
|
||||
DeclareField(enabled_ram.bank1);
|
||||
|
@ -38,20 +38,6 @@ struct Media {
|
||||
return disks.empty() && tapes.empty() && cartridges.empty() && mass_storage_devices.empty();
|
||||
}
|
||||
|
||||
void set_target_platforms(const TargetPlatform::Type target) {
|
||||
const auto propagate = [&](const auto &list) {
|
||||
for(const auto &item: list) {
|
||||
if(auto *recipient = dynamic_cast<TargetPlatform::Recipient *>(item.get())) {
|
||||
recipient->set_target_platforms(target);
|
||||
}
|
||||
}
|
||||
};
|
||||
propagate(disks);
|
||||
propagate(tapes);
|
||||
propagate(cartridges);
|
||||
propagate(mass_storage_devices);
|
||||
}
|
||||
|
||||
Media &operator +=(const Media &rhs) {
|
||||
const auto append = [&](auto &destination, auto &source) {
|
||||
destination.insert(destination.end(), source.begin(), source.end());
|
||||
|
@ -173,7 +173,7 @@ class ConcreteMachine:
|
||||
public Machine,
|
||||
public Utility::TypeRecipient<CharacterMapper> {
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
ConcreteMachine(const Analyser::Static::Commodore::Plus4Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
m6502_(*this),
|
||||
interrupts_(*this),
|
||||
timers_(interrupts_),
|
||||
@ -731,7 +731,7 @@ std::unique_ptr<Machine> Machine::Plus4(
|
||||
const Analyser::Static::Target *target,
|
||||
const ROMMachine::ROMFetcher &rom_fetcher
|
||||
) {
|
||||
using Target = Analyser::Static::Commodore::Target;
|
||||
using Target = Analyser::Static::Commodore::Plus4Target;
|
||||
const Target *const commodore_target = dynamic_cast<const Target *>(target);
|
||||
return std::make_unique<ConcreteMachine>(*commodore_target, rom_fetcher);
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ class ConcreteMachine:
|
||||
public ClockingHint::Observer,
|
||||
public Activity::Source {
|
||||
public:
|
||||
ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
ConcreteMachine(const Analyser::Static::Commodore::Vic20Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
|
||||
m6502_(*this),
|
||||
mos6560_(mos6560_bus_handler_),
|
||||
user_port_via_(user_port_via_port_handler_),
|
||||
@ -313,24 +313,25 @@ public:
|
||||
|
||||
ROM::Request request(ROM::Name::Vic20BASIC);
|
||||
ROM::Name kernel, character;
|
||||
using Region = Analyser::Static::Commodore::Vic20Target::Region;
|
||||
switch(target.region) {
|
||||
default:
|
||||
character = ROM::Name::Vic20EnglishCharacters;
|
||||
kernel = ROM::Name::Vic20EnglishPALKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::American:
|
||||
case Region::American:
|
||||
character = ROM::Name::Vic20EnglishCharacters;
|
||||
kernel = ROM::Name::Vic20EnglishNTSCKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::Danish:
|
||||
case Region::Danish:
|
||||
character = ROM::Name::Vic20DanishCharacters;
|
||||
kernel = ROM::Name::Vic20DanishKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::Japanese:
|
||||
case Region::Japanese:
|
||||
character = ROM::Name::Vic20JapaneseCharacters;
|
||||
kernel = ROM::Name::Vic20JapaneseKernel;
|
||||
break;
|
||||
case Analyser::Static::Commodore::Target::Region::Swedish:
|
||||
case Region::Swedish:
|
||||
character = ROM::Name::Vic20SwedishCharacters;
|
||||
kernel = ROM::Name::Vic20SwedishKernel;
|
||||
break;
|
||||
@ -362,7 +363,7 @@ public:
|
||||
}
|
||||
|
||||
// Determine PAL/NTSC
|
||||
if(target.region == Analyser::Static::Commodore::Target::Region::American || target.region == Analyser::Static::Commodore::Target::Region::Japanese) {
|
||||
if(target.region == Region::American || target.region == Region::Japanese) {
|
||||
// NTSC
|
||||
set_clock_rate(1022727);
|
||||
mos6560_.set_output_mode(MOS::MOS6560::OutputMode::NTSC);
|
||||
@ -762,7 +763,7 @@ std::unique_ptr<Machine> Machine::Vic20(
|
||||
const Analyser::Static::Target *const target,
|
||||
const ROMMachine::ROMFetcher &rom_fetcher
|
||||
) {
|
||||
using Target = Analyser::Static::Commodore::Target;
|
||||
using Target = Analyser::Static::Commodore::Vic20Target;
|
||||
const Target *const commodore_target = dynamic_cast<const Target *>(target);
|
||||
return std::make_unique<Vic20::ConcreteMachine>(*commodore_target, rom_fetcher);
|
||||
}
|
||||
|
@ -264,9 +264,9 @@ std::map<std::string, std::unique_ptr<Analyser::Static::Target>> Machine::Target
|
||||
Add(Macintosh);
|
||||
Add(MSX);
|
||||
Add(Oric);
|
||||
AddMapped(Plus4, Commodore);
|
||||
options.emplace(LongNameForTargetMachine(Analyser::Machine::Plus4), std::make_unique<Analyser::Static::Commodore::Plus4Target>());
|
||||
Add(PCCompatible);
|
||||
AddMapped(Vic20, Commodore);
|
||||
options.emplace(LongNameForTargetMachine(Analyser::Machine::Vic20), std::make_unique<Analyser::Static::Commodore::Vic20Target>());
|
||||
Add(ZX8081);
|
||||
Add(ZXSpectrum);
|
||||
|
||||
|
@ -163,8 +163,8 @@
|
||||
- (instancetype)initWithCommodoreTEDModel:(CSMachineCommodoreTEDModel)model {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::Target;
|
||||
auto target = std::make_unique<Target>(Analyser::Machine::Plus4);
|
||||
using Target = Analyser::Static::Commodore::Plus4Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
_targets.push_back(std::move(target));
|
||||
}
|
||||
return self;
|
||||
@ -330,7 +330,7 @@
|
||||
- (instancetype)initWithVic20Region:(CSMachineVic20Region)region memorySize:(Kilobytes)memorySize hasC1540:(BOOL)hasC1540 {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
using Target = Analyser::Static::Commodore::Target;
|
||||
using Target = Analyser::Static::Commodore::Vic20Target;
|
||||
auto target = std::make_unique<Target>();
|
||||
switch(region) {
|
||||
case CSMachineVic20RegionDanish: target->region = Target::Region::Danish; break;
|
||||
|
@ -21,7 +21,7 @@ CommodoreTAP::CommodoreTAP(const std::string &file_name) : file_name_(file_name)
|
||||
if(!is_c64 && !is_c16) {
|
||||
throw ErrorNotCommodoreTAP;
|
||||
}
|
||||
const FileType type = is_c16 ? FileType::C16 : FileType::C64;
|
||||
// const FileType type = is_c16 ? FileType::C16 : FileType::C64;
|
||||
|
||||
// Get and check the file version.
|
||||
const uint8_t version = file.get8();
|
||||
|
@ -16,12 +16,18 @@ TapePlayer::TapePlayer(const int input_clock_rate) :
|
||||
TimedEventLoop(input_clock_rate)
|
||||
{}
|
||||
|
||||
TapeSerialiser::TapeSerialiser(std::unique_ptr<FormatSerialiser> &&serialiser) : serialiser_(serialiser) {}
|
||||
TapeSerialiser::TapeSerialiser(std::unique_ptr<FormatSerialiser> &&serialiser) : serialiser_(std::move(serialiser)) {}
|
||||
|
||||
std::unique_ptr<TapeSerialiser> Tape::serialiser() const {
|
||||
return std::make_unique<TapeSerialiser>(format_serialiser());
|
||||
std::unique_ptr<TapeSerialiser> Tape::serialiser(const TargetPlatform::Type platform) const {
|
||||
auto serialiser = format_serialiser();
|
||||
if(auto *recipient = dynamic_cast<TargetPlatform::Recipient *>(serialiser.get())) {
|
||||
recipient->set_target_platforms(platform);
|
||||
}
|
||||
|
||||
return std::make_unique<TapeSerialiser>(std::move(serialiser));
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Seeking
|
||||
|
||||
void TapeSerialiser::seek(const Time seek_time) {
|
||||
@ -46,7 +52,7 @@ Storage::Time TapeSerialiser::current_time() {
|
||||
|
||||
void TapeSerialiser::reset() {
|
||||
offset_ = 0;
|
||||
serialiser_.reset();
|
||||
serialiser_->reset();
|
||||
}
|
||||
|
||||
Pulse TapeSerialiser::next_pulse() {
|
||||
@ -80,10 +86,7 @@ ClockingHint::Preference TapePlayer::preferred_clocking() const {
|
||||
|
||||
void TapePlayer::set_tape(std::shared_ptr<Storage::Tape::Tape> tape, TargetPlatform::Type platform) {
|
||||
tape_ = tape;
|
||||
serialiser_ = tape->serialiser();
|
||||
if(auto recipient = dynamic_cast<TargetPlatform::Recipient *>(serialiser_.get()); recipient) {
|
||||
recipient->set_target_platforms(platform);
|
||||
}
|
||||
serialiser_ = tape->serialiser(platform);
|
||||
|
||||
reset_timer();
|
||||
next_pulse();
|
||||
|
@ -36,6 +36,10 @@ struct Pulse {
|
||||
class FormatSerialiser {
|
||||
public:
|
||||
virtual ~FormatSerialiser() = default;
|
||||
FormatSerialiser() = default;
|
||||
|
||||
FormatSerialiser(FormatSerialiser &) = delete;
|
||||
|
||||
virtual Pulse next_pulse() = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual bool is_at_end() const = 0;
|
||||
@ -43,9 +47,12 @@ public:
|
||||
|
||||
class TapeSerialiser {
|
||||
public:
|
||||
TapeSerialiser(std::unique_ptr<FormatSerialiser> &&);
|
||||
explicit TapeSerialiser(std::unique_ptr<FormatSerialiser> &&);
|
||||
TapeSerialiser(TapeSerialiser &) = delete;
|
||||
virtual ~TapeSerialiser() = default;
|
||||
|
||||
void set_target_platforms(TargetPlatform::IntType);
|
||||
|
||||
/*!
|
||||
If at the start of the tape returns the first stored pulse. Otherwise advances past
|
||||
the last-returned pulse and returns the next.
|
||||
@ -85,7 +92,7 @@ public:
|
||||
private:
|
||||
uint64_t offset_{};
|
||||
Pulse pulse_;
|
||||
std::unique_ptr<FormatSerialiser> &serialiser_;
|
||||
std::unique_ptr<FormatSerialiser> serialiser_;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -97,7 +104,7 @@ private:
|
||||
*/
|
||||
class Tape {
|
||||
public:
|
||||
std::unique_ptr<TapeSerialiser> serialiser() const;
|
||||
std::unique_ptr<TapeSerialiser> serialiser(TargetPlatform::Type platform = TargetPlatform::All) const;
|
||||
|
||||
protected:
|
||||
virtual std::unique_ptr<FormatSerialiser> format_serialiser() const = 0;
|
||||
|
@ -55,6 +55,8 @@ enum Type: IntType {
|
||||
AllCartridge = Atari2600 | AcornElectron | Coleco | MSX,
|
||||
AllDisk = Acorn | Commodore | AmstradCPC | C64 | Oric | MSX | ZXSpectrum | Macintosh | AtariST | DiskII | PCCompatible | FAT12,
|
||||
AllTape = Acorn | AmstradCPC | Commodore8bit | Oric | ZX8081 | MSX | ZXSpectrum,
|
||||
|
||||
All = ~0,
|
||||
};
|
||||
|
||||
class Distinguisher {
|
||||
|
Loading…
x
Reference in New Issue
Block a user