mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-03 22:33:29 +00:00
Update remainder of 'Analyser'.
This commit is contained in:
parent
bd97fd5973
commit
abfc73299e
@ -49,27 +49,39 @@ std::unique_ptr<Catalogue> Analyser::Static::Acorn::GetDFSCatalogue(const std::s
|
||||
char name[10];
|
||||
snprintf(name, 10, "%c.%.7s", names->samples[0][file_offset + 7] & 0x7f, &names->samples[0][file_offset]);
|
||||
new_file.name = name;
|
||||
new_file.load_address = uint32_t(details->samples[0][file_offset] | (details->samples[0][file_offset+1] << 8) | ((details->samples[0][file_offset+6]&0x0c) << 14));
|
||||
new_file.execution_address = uint32_t(details->samples[0][file_offset+2] | (details->samples[0][file_offset+3] << 8) | ((details->samples[0][file_offset+6]&0xc0) << 10));
|
||||
new_file.load_address = uint32_t(
|
||||
details->samples[0][file_offset] |
|
||||
(details->samples[0][file_offset+1] << 8) |
|
||||
((details->samples[0][file_offset+6]&0x0c) << 14)
|
||||
);
|
||||
new_file.execution_address = uint32_t(
|
||||
details->samples[0][file_offset+2] |
|
||||
(details->samples[0][file_offset+3] << 8) |
|
||||
((details->samples[0][file_offset+6]&0xc0) << 10)
|
||||
);
|
||||
if(names->samples[0][file_offset + 7] & 0x80) {
|
||||
// File is locked; it may not be altered or deleted.
|
||||
new_file.flags |= File::Flags::Locked;
|
||||
}
|
||||
|
||||
long data_length = long(details->samples[0][file_offset+4] | (details->samples[0][file_offset+5] << 8) | ((details->samples[0][file_offset+6]&0x30) << 12));
|
||||
auto data_length = long(
|
||||
details->samples[0][file_offset+4] |
|
||||
(details->samples[0][file_offset+5] << 8) |
|
||||
((details->samples[0][file_offset+6]&0x30) << 12)
|
||||
);
|
||||
int start_sector = details->samples[0][file_offset+7] | ((details->samples[0][file_offset+6]&0x03) << 8);
|
||||
new_file.data.reserve(size_t(data_length));
|
||||
|
||||
if(start_sector < 2) continue;
|
||||
while(data_length > 0) {
|
||||
uint8_t sector = uint8_t(start_sector % 10);
|
||||
uint8_t track = uint8_t(start_sector / 10);
|
||||
start_sector++;
|
||||
const uint8_t sector = uint8_t(start_sector % 10);
|
||||
const uint8_t track = uint8_t(start_sector / 10);
|
||||
++start_sector;
|
||||
|
||||
const Storage::Encodings::MFM::Sector *next_sector = parser.sector(0, track, sector);
|
||||
if(!next_sector) break;
|
||||
|
||||
long length_from_sector = std::min(data_length, 256l);
|
||||
const long length_from_sector = std::min(data_length, 256l);
|
||||
new_file.data.insert(new_file.data.end(), next_sector->samples[0].begin(), next_sector->samples[0].begin() + length_from_sector);
|
||||
data_length -= length_from_sector;
|
||||
}
|
||||
@ -133,7 +145,8 @@ std::unique_ptr<Catalogue> Analyser::Static::Acorn::GetADFSCatalogue(const std::
|
||||
}
|
||||
|
||||
// Parse the root directory, at least.
|
||||
for(std::size_t file_offset = 0x005; file_offset < (catalogue->has_large_sectors ? 0x7d7 : 0x4cb); file_offset += 0x1a) {
|
||||
const std::size_t directory_extent = catalogue->has_large_sectors ? 0x7d7 : 0x4cb;
|
||||
for(std::size_t file_offset = 0x005; file_offset < directory_extent; file_offset += 0x1a) {
|
||||
// Obtain the name, which will be at most ten characters long, and will
|
||||
// be terminated by either a NULL character or a \r.
|
||||
char name[11]{};
|
||||
@ -190,11 +203,16 @@ std::unique_ptr<Catalogue> Analyser::Static::Acorn::GetADFSCatalogue(const std::
|
||||
|
||||
new_file.data.reserve(size);
|
||||
while(new_file.data.size() < size) {
|
||||
const Storage::Encodings::MFM::Sector *const sector = parser.sector(start_sector / (80 * 16), (start_sector / 16) % 80, start_sector % 16);
|
||||
const Storage::Encodings::MFM::Sector *const sector =
|
||||
parser.sector(start_sector / (80 * 16), (start_sector / 16) % 80, start_sector % 16);
|
||||
if(!sector) break;
|
||||
|
||||
const auto length_from_sector = std::min(size - new_file.data.size(), sector->samples[0].size());
|
||||
new_file.data.insert(new_file.data.end(), sector->samples[0].begin(), sector->samples[0].begin() + ssize_t(length_from_sector));
|
||||
new_file.data.insert(
|
||||
new_file.data.end(),
|
||||
sector->samples[0].begin(),
|
||||
sector->samples[0].begin() + ssize_t(length_from_sector)
|
||||
);
|
||||
++start_sector;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ struct Catalogue {
|
||||
} bootOption;
|
||||
};
|
||||
|
||||
std::unique_ptr<Catalogue> GetDFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &disk);
|
||||
std::unique_ptr<Catalogue> GetADFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &disk);
|
||||
std::unique_ptr<Catalogue> GetDFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &);
|
||||
std::unique_ptr<Catalogue> GetADFSCatalogue(const std::shared_ptr<Storage::Disk::Disk> &);
|
||||
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
using namespace Analyser::Static::Acorn;
|
||||
|
||||
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
AcornCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
AcornCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> acorn_cartridges;
|
||||
|
||||
for(const auto &cartridge : cartridges) {
|
||||
@ -62,7 +62,11 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return acorn_cartridges;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &file_name,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
auto target8bit = std::make_unique<ElectronTarget>();
|
||||
auto targetArchimedes = std::make_unique<ArchimedesTarget>();
|
||||
|
||||
@ -121,7 +125,7 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
|
||||
target8bit->has_pres_adfs = bool(adfs_catalogue);
|
||||
|
||||
// Check whether a simple shift+break will do for loading this disk.
|
||||
Catalogue::BootOption bootOption = (dfs_catalogue ?: adfs_catalogue)->bootOption;
|
||||
const auto bootOption = (dfs_catalogue ?: adfs_catalogue)->bootOption;
|
||||
if(bootOption != Catalogue::BootOption::None) {
|
||||
target8bit->should_shift_restart = true;
|
||||
} else {
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Acorn {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,10 @@
|
||||
|
||||
using namespace Analyser::Static::Acorn;
|
||||
|
||||
static std::unique_ptr<File::Chunk> GetNextChunk(const std::shared_ptr<Storage::Tape::Tape> &tape, Storage::Tape::Acorn::Parser &parser) {
|
||||
static std::unique_ptr<File::Chunk> GetNextChunk(
|
||||
const std::shared_ptr<Storage::Tape::Tape> &tape,
|
||||
Storage::Tape::Acorn::Parser &parser
|
||||
) {
|
||||
auto new_chunk = std::make_unique<File::Chunk>();
|
||||
int shift_register = 0;
|
||||
|
||||
@ -56,7 +59,7 @@ static std::unique_ptr<File::Chunk> GetNextChunk(const std::shared_ptr<Storage::
|
||||
new_chunk->block_flag = uint8_t(parser.get_next_byte(tape));
|
||||
new_chunk->next_address = uint32_t(parser.get_next_word(tape));
|
||||
|
||||
uint16_t calculated_header_crc = parser.get_crc();
|
||||
const uint16_t calculated_header_crc = parser.get_crc();
|
||||
uint16_t stored_header_crc = uint16_t(parser.get_next_short(tape));
|
||||
stored_header_crc = uint16_t((stored_header_crc >> 8) | (stored_header_crc << 8));
|
||||
new_chunk->header_crc_matched = stored_header_crc == calculated_header_crc;
|
||||
|
@ -15,6 +15,6 @@
|
||||
|
||||
namespace Analyser::Static::Acorn {
|
||||
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Amiga::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Amiga::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// This analyser can comprehend disks and mass-storage devices only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Amiga {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ std::string RunCommandFor(const Storage::Disk::CPM::File &file) {
|
||||
|
||||
void InspectCatalogue(
|
||||
const Storage::Disk::CPM::Catalogue &catalogue,
|
||||
const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target) {
|
||||
|
||||
const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target
|
||||
) {
|
||||
std::vector<const Storage::Disk::CPM::File *> candidate_files;
|
||||
candidate_files.reserve(catalogue.files.size());
|
||||
for(const auto &file : catalogue.files) {
|
||||
@ -158,7 +158,10 @@ void InspectCatalogue(
|
||||
target->loading_command = "cat\n";
|
||||
}
|
||||
|
||||
bool CheckBootSector(const std::shared_ptr<Storage::Disk::Disk> &disk, const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target) {
|
||||
bool CheckBootSector(
|
||||
const std::shared_ptr<Storage::Disk::Disk> &disk,
|
||||
const std::unique_ptr<Analyser::Static::AmstradCPC::Target> &target
|
||||
) {
|
||||
Storage::Encodings::MFM::Parser parser(Storage::Encodings::MFM::Density::Double, disk);
|
||||
const Storage::Encodings::MFM::Sector *boot_sector = parser.sector(0, 0, 0x41);
|
||||
if(boot_sector != nullptr && !boot_sector->samples.empty() && boot_sector->samples[0].size() == 512) {
|
||||
@ -204,7 +207,11 @@ bool IsAmstradTape(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
TargetList destination;
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
@ -233,7 +240,8 @@ Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Medi
|
||||
|
||||
for(auto &disk: media.disks) {
|
||||
// Check for an ordinary catalogue, making sure this isn't actually a ZX Spectrum disk.
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue = Storage::Disk::CPM::GetCatalogue(disk, data_format, false);
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> data_catalogue =
|
||||
Storage::Disk::CPM::GetCatalogue(disk, data_format, false);
|
||||
if(data_catalogue && !data_catalogue->is_zx_spectrum_booter()) {
|
||||
InspectCatalogue(*data_catalogue, target);
|
||||
target->media.disks.push_back(disk);
|
||||
@ -247,7 +255,8 @@ Analyser::Static::TargetList Analyser::Static::AmstradCPC::GetTargets(const Medi
|
||||
}
|
||||
|
||||
// Failing that check for a system catalogue.
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue = Storage::Disk::CPM::GetCatalogue(disk, system_format, false);
|
||||
std::unique_ptr<Storage::Disk::CPM::Catalogue> system_catalogue =
|
||||
Storage::Disk::CPM::GetCatalogue(disk, system_format, false);
|
||||
if(system_catalogue && !system_catalogue->is_zx_spectrum_booter()) {
|
||||
InspectCatalogue(*system_catalogue, target);
|
||||
target->media.disks.push_back(disk);
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::AmstradCPC {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AppleII::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::AppleII::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->media = media;
|
||||
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::AppleII {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AppleIIgs::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::AppleIIgs::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->media = media;
|
||||
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::AppleIIgs {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -33,11 +33,13 @@ static void DeterminePagingFor2kCartridge(Target &target, const Storage::Cartrid
|
||||
// Assume that any kind of store that looks likely to be intended for large amounts of memory implies
|
||||
// large amounts of memory.
|
||||
bool has_wide_area_store = false;
|
||||
for(std::map<uint16_t, Analyser::Static::MOS6502::Instruction>::value_type &entry : high_location_disassembly.instructions_by_address) {
|
||||
for(const auto &entry : high_location_disassembly.instructions_by_address) {
|
||||
using Instruction = Analyser::Static::MOS6502::Instruction;
|
||||
if(entry.second.operation == Analyser::Static::MOS6502::Instruction::STA) {
|
||||
has_wide_area_store |= entry.second.addressing_mode == Analyser::Static::MOS6502::Instruction::Indirect;
|
||||
has_wide_area_store |= entry.second.addressing_mode == Analyser::Static::MOS6502::Instruction::IndexedIndirectX;
|
||||
has_wide_area_store |= entry.second.addressing_mode == Analyser::Static::MOS6502::Instruction::IndirectIndexedY;
|
||||
has_wide_area_store |=
|
||||
entry.second.addressing_mode == Instruction::Indirect ||
|
||||
entry.second.addressing_mode == Instruction::IndexedIndirectX ||
|
||||
entry.second.addressing_mode == Instruction::IndirectIndexedY;
|
||||
|
||||
if(has_wide_area_store) break;
|
||||
}
|
||||
@ -50,13 +52,21 @@ static void DeterminePagingFor2kCartridge(Target &target, const Storage::Cartrid
|
||||
if(has_wide_area_store) target.paging_model = Target::PagingModel::CommaVid;
|
||||
}
|
||||
|
||||
static void DeterminePagingFor8kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &segment, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
static void DeterminePagingFor8kCartridge(
|
||||
Target &target,
|
||||
const Storage::Cartridge::Cartridge::Segment &segment,
|
||||
const Analyser::Static::MOS6502::Disassembly &disassembly
|
||||
) {
|
||||
// Activision stack titles have their vectors at the top of the low 4k, not the top, and
|
||||
// always list 0xf000 as both vectors; they do not repeat them, and, inexplicably, they all
|
||||
// issue an SEI as their first instruction (maybe some sort of relic of the development environment?).
|
||||
if(
|
||||
segment.data[4095] == 0xf0 && segment.data[4093] == 0xf0 && segment.data[4094] == 0x00 && segment.data[4092] == 0x00 &&
|
||||
(segment.data[8191] != 0xf0 || segment.data[8189] != 0xf0 || segment.data[8190] != 0x00 || segment.data[8188] != 0x00) &&
|
||||
segment.data[4095] == 0xf0 && segment.data[4093] == 0xf0 &&
|
||||
segment.data[4094] == 0x00 && segment.data[4092] == 0x00 &&
|
||||
(
|
||||
segment.data[8191] != 0xf0 || segment.data[8189] != 0xf0 ||
|
||||
segment.data[8190] != 0x00 || segment.data[8188] != 0x00
|
||||
) &&
|
||||
segment.data[0] == 0x78
|
||||
) {
|
||||
target.paging_model = Target::PagingModel::ActivisionStack;
|
||||
@ -88,7 +98,11 @@ static void DeterminePagingFor8kCartridge(Target &target, const Storage::Cartrid
|
||||
else if(tigervision_access_count > atari_access_count) target.paging_model = Target::PagingModel::Tigervision;
|
||||
}
|
||||
|
||||
static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
static void DeterminePagingFor16kCartridge(
|
||||
Target &target,
|
||||
const Storage::Cartridge::Cartridge::Segment &,
|
||||
const Analyser::Static::MOS6502::Disassembly &disassembly
|
||||
) {
|
||||
// Make an assumption that this is the Atari paging model.
|
||||
target.paging_model = Target::PagingModel::Atari16k;
|
||||
|
||||
@ -108,7 +122,11 @@ static void DeterminePagingFor16kCartridge(Target &target, const Storage::Cartri
|
||||
if(mnetwork_access_count > atari_access_count) target.paging_model = Target::PagingModel::MNetwork;
|
||||
}
|
||||
|
||||
static void DeterminePagingFor64kCartridge(Target &target, const Storage::Cartridge::Cartridge::Segment &, const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
static void DeterminePagingFor64kCartridge(
|
||||
Target &target,
|
||||
const Storage::Cartridge::Cartridge::Segment &,
|
||||
const Analyser::Static::MOS6502::Disassembly &disassembly
|
||||
) {
|
||||
// Make an assumption that this is a Tigervision if there is a write to 3F.
|
||||
target.paging_model =
|
||||
(disassembly.external_stores.find(0x3f) != disassembly.external_stores.end()) ?
|
||||
@ -121,8 +139,12 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16_t entry_address = uint16_t(segment.data[segment.data.size() - 4] | (segment.data[segment.data.size() - 3] << 8));
|
||||
const uint16_t break_address = uint16_t(segment.data[segment.data.size() - 2] | (segment.data[segment.data.size() - 1] << 8));
|
||||
const auto word = [](const uint8_t low, const uint8_t high) {
|
||||
return uint16_t(low | (high << 8));
|
||||
};
|
||||
|
||||
const auto entry_address = word(segment.data[segment.data.size() - 4], segment.data[segment.data.size() - 3]);
|
||||
const auto break_address = word(segment.data[segment.data.size() - 2], segment.data[segment.data.size() - 1]);
|
||||
|
||||
std::function<std::size_t(uint16_t address)> address_mapper = [](uint16_t address) {
|
||||
if(!(address & 0x1000)) return size_t(-1);
|
||||
@ -130,27 +152,16 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
|
||||
};
|
||||
|
||||
const std::vector<uint8_t> final_4k(segment.data.end() - 4096, segment.data.end());
|
||||
Analyser::Static::MOS6502::Disassembly disassembly = Analyser::Static::MOS6502::Disassemble(final_4k, address_mapper, {entry_address, break_address});
|
||||
const auto disassembly =
|
||||
Analyser::Static::MOS6502::Disassemble(final_4k, address_mapper, {entry_address, break_address});
|
||||
|
||||
switch(segment.data.size()) {
|
||||
case 8192:
|
||||
DeterminePagingFor8kCartridge(target, segment, disassembly);
|
||||
break;
|
||||
case 10495:
|
||||
target.paging_model = Target::PagingModel::Pitfall2;
|
||||
break;
|
||||
case 12288:
|
||||
target.paging_model = Target::PagingModel::CBSRamPlus;
|
||||
break;
|
||||
case 16384:
|
||||
DeterminePagingFor16kCartridge(target, segment, disassembly);
|
||||
break;
|
||||
case 32768:
|
||||
target.paging_model = Target::PagingModel::Atari32k;
|
||||
break;
|
||||
case 65536:
|
||||
DeterminePagingFor64kCartridge(target, segment, disassembly);
|
||||
break;
|
||||
case 8192: DeterminePagingFor8kCartridge(target, segment, disassembly); break;
|
||||
case 10495: target.paging_model = Target::PagingModel::Pitfall2; break;
|
||||
case 12288: target.paging_model = Target::PagingModel::CBSRamPlus; break;
|
||||
case 16384: DeterminePagingFor16kCartridge(target, segment, disassembly); break;
|
||||
case 32768: target.paging_model = Target::PagingModel::Atari32k; break;
|
||||
case 65536: DeterminePagingFor64kCartridge(target, segment, disassembly); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -177,7 +188,11 @@ static void DeterminePagingForCartridge(Target &target, const Storage::Cartridge
|
||||
}
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Atari2600::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Atari2600::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// TODO: sanity checking; is this image really for an Atari 2600?
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Atari2600 {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::AtariST::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::AtariST::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// This analyser can comprehend disks and mass-storage devices only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::AtariST {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
|
||||
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
ColecoCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
ColecoCartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> coleco_cartridges;
|
||||
|
||||
for(const auto &cartridge : cartridges) {
|
||||
@ -52,7 +52,11 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return coleco_cartridges;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Coleco::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Coleco::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
TargetList targets;
|
||||
auto target = std::make_unique<Target>(Machine::ColecoVision);
|
||||
target->confidence = 1.0f - 1.0f / 32768.0f;
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Coleco {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -18,155 +18,155 @@
|
||||
using namespace Analyser::Static::Commodore;
|
||||
|
||||
class CommodoreGCRParser: public Storage::Disk::Controller {
|
||||
public:
|
||||
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
|
||||
emplace_drive(4000000, 300, 2);
|
||||
set_drive(1);
|
||||
get_drive().set_motor_on(true);
|
||||
}
|
||||
public:
|
||||
CommodoreGCRParser() : Storage::Disk::Controller(4000000), shift_register_(0), track_(1) {
|
||||
emplace_drive(4000000, 300, 2);
|
||||
set_drive(1);
|
||||
get_drive().set_motor_on(true);
|
||||
}
|
||||
|
||||
struct Sector {
|
||||
uint8_t sector, track;
|
||||
std::array<uint8_t, 256> data;
|
||||
bool header_checksum_matched;
|
||||
bool data_checksum_matched;
|
||||
};
|
||||
struct Sector {
|
||||
uint8_t sector, track;
|
||||
std::array<uint8_t, 256> data;
|
||||
bool header_checksum_matched;
|
||||
bool data_checksum_matched;
|
||||
};
|
||||
|
||||
/*!
|
||||
Attempts to read the sector located at @c track and @c sector.
|
||||
/*!
|
||||
Attempts to read the sector located at @c track and @c sector.
|
||||
|
||||
@returns a sector if one was found; @c nullptr otherwise.
|
||||
*/
|
||||
std::shared_ptr<Sector> sector(uint8_t track, uint8_t sector) {
|
||||
int difference = int(track) - int(track_);
|
||||
track_ = track;
|
||||
@returns a sector if one was found; @c nullptr otherwise.
|
||||
*/
|
||||
std::shared_ptr<Sector> sector(const uint8_t track, const uint8_t sector) {
|
||||
int difference = int(track) - int(track_);
|
||||
track_ = track;
|
||||
|
||||
if(difference) {
|
||||
int direction = difference < 0 ? -1 : 1;
|
||||
difference *= direction;
|
||||
if(difference) {
|
||||
const int direction = difference < 0 ? -1 : 1;
|
||||
difference *= direction;
|
||||
|
||||
for(int c = 0; c < difference; c++) {
|
||||
get_drive().step(Storage::Disk::HeadPosition(direction));
|
||||
}
|
||||
|
||||
unsigned int zone = 3;
|
||||
if(track >= 18) zone = 2;
|
||||
else if(track >= 25) zone = 1;
|
||||
else if(track >= 31) zone = 0;
|
||||
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
|
||||
for(int c = 0; c < difference; c++) {
|
||||
get_drive().step(Storage::Disk::HeadPosition(direction));
|
||||
}
|
||||
|
||||
return get_sector(sector);
|
||||
unsigned int zone = 3;
|
||||
if(track >= 18) zone = 2;
|
||||
else if(track >= 25) zone = 1;
|
||||
else if(track >= 31) zone = 0;
|
||||
set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(zone));
|
||||
}
|
||||
|
||||
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
|
||||
get_drive().set_disk(disk);
|
||||
return get_sector(sector);
|
||||
}
|
||||
|
||||
void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
|
||||
get_drive().set_disk(disk);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int shift_register_;
|
||||
int index_count_;
|
||||
int bit_count_;
|
||||
uint8_t track_;
|
||||
std::shared_ptr<Sector> sector_cache_[65536];
|
||||
|
||||
void process_input_bit(const int value) {
|
||||
shift_register_ = ((shift_register_ << 1) | unsigned(value)) & 0x3ff;
|
||||
bit_count_++;
|
||||
}
|
||||
|
||||
unsigned int proceed_to_next_block(const int max_index_count) {
|
||||
// find GCR lead-in
|
||||
proceed_to_shift_value(0x3ff);
|
||||
if(shift_register_ != 0x3ff) return 0xff;
|
||||
|
||||
// find end of lead-in
|
||||
while(shift_register_ == 0x3ff && index_count_ < max_index_count) {
|
||||
run_for(Cycles(1));
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int shift_register_;
|
||||
int index_count_;
|
||||
int bit_count_;
|
||||
uint8_t track_;
|
||||
std::shared_ptr<Sector> sector_cache_[65536];
|
||||
|
||||
void process_input_bit(int value) {
|
||||
shift_register_ = ((shift_register_ << 1) | unsigned(value)) & 0x3ff;
|
||||
bit_count_++;
|
||||
// continue for a further nine bits
|
||||
bit_count_ = 0;
|
||||
while(bit_count_ < 9 && index_count_ < max_index_count) {
|
||||
run_for(Cycles(1));
|
||||
}
|
||||
|
||||
unsigned int proceed_to_next_block(int max_index_count) {
|
||||
// find GCR lead-in
|
||||
proceed_to_shift_value(0x3ff);
|
||||
if(shift_register_ != 0x3ff) return 0xff;
|
||||
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
|
||||
}
|
||||
|
||||
// find end of lead-in
|
||||
while(shift_register_ == 0x3ff && index_count_ < max_index_count) {
|
||||
run_for(Cycles(1));
|
||||
}
|
||||
unsigned int get_next_byte() {
|
||||
bit_count_ = 0;
|
||||
while(bit_count_ < 10) run_for(Cycles(1));
|
||||
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
|
||||
}
|
||||
|
||||
// continue for a further nine bits
|
||||
bit_count_ = 0;
|
||||
while(bit_count_ < 9 && index_count_ < max_index_count) {
|
||||
run_for(Cycles(1));
|
||||
}
|
||||
|
||||
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
|
||||
void proceed_to_shift_value(const unsigned int shift_value) {
|
||||
const int max_index_count = index_count_ + 2;
|
||||
while(shift_register_ != shift_value && index_count_ < max_index_count) {
|
||||
run_for(Cycles(1));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int get_next_byte() {
|
||||
bit_count_ = 0;
|
||||
while(bit_count_ < 10) run_for(Cycles(1));
|
||||
return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
|
||||
void process_index_hole() {
|
||||
index_count_++;
|
||||
}
|
||||
|
||||
std::shared_ptr<Sector> get_sector(const uint8_t sector) {
|
||||
const uint16_t sector_address = uint16_t((track_ << 8) | sector);
|
||||
if(sector_cache_[sector_address]) return sector_cache_[sector_address];
|
||||
|
||||
const std::shared_ptr<Sector> first_sector = get_next_sector();
|
||||
if(!first_sector) return first_sector;
|
||||
if(first_sector->sector == sector) return first_sector;
|
||||
|
||||
while(1) {
|
||||
const std::shared_ptr<Sector> next_sector = get_next_sector();
|
||||
if(next_sector->sector == first_sector->sector) return nullptr;
|
||||
if(next_sector->sector == sector) return next_sector;
|
||||
}
|
||||
}
|
||||
|
||||
void proceed_to_shift_value(unsigned int shift_value) {
|
||||
const int max_index_count = index_count_ + 2;
|
||||
while(shift_register_ != shift_value && index_count_ < max_index_count) {
|
||||
run_for(Cycles(1));
|
||||
}
|
||||
}
|
||||
|
||||
void process_index_hole() {
|
||||
index_count_++;
|
||||
}
|
||||
|
||||
std::shared_ptr<Sector> get_sector(uint8_t sector) {
|
||||
const uint16_t sector_address = uint16_t((track_ << 8) | sector);
|
||||
if(sector_cache_[sector_address]) return sector_cache_[sector_address];
|
||||
|
||||
const std::shared_ptr<Sector> first_sector = get_next_sector();
|
||||
if(!first_sector) return first_sector;
|
||||
if(first_sector->sector == sector) return first_sector;
|
||||
std::shared_ptr<Sector> get_next_sector() {
|
||||
auto sector = std::make_shared<Sector>();
|
||||
const int max_index_count = index_count_ + 2;
|
||||
|
||||
while(index_count_ < max_index_count) {
|
||||
// look for a sector header
|
||||
while(1) {
|
||||
const std::shared_ptr<Sector> next_sector = get_next_sector();
|
||||
if(next_sector->sector == first_sector->sector) return nullptr;
|
||||
if(next_sector->sector == sector) return next_sector;
|
||||
if(proceed_to_next_block(max_index_count) == 0x08) break;
|
||||
if(index_count_ >= max_index_count) return nullptr;
|
||||
}
|
||||
|
||||
// get sector details, skip if this looks malformed
|
||||
uint8_t checksum = uint8_t(get_next_byte());
|
||||
sector->sector = uint8_t(get_next_byte());
|
||||
sector->track = uint8_t(get_next_byte());
|
||||
uint8_t disk_id[2];
|
||||
disk_id[0] = uint8_t(get_next_byte());
|
||||
disk_id[1] = uint8_t(get_next_byte());
|
||||
if(checksum != (sector->sector ^ sector->track ^ disk_id[0] ^ disk_id[1])) continue;
|
||||
|
||||
// look for the following data
|
||||
while(1) {
|
||||
if(proceed_to_next_block(max_index_count) == 0x07) break;
|
||||
if(index_count_ >= max_index_count) return nullptr;
|
||||
}
|
||||
|
||||
checksum = 0;
|
||||
for(std::size_t c = 0; c < 256; c++) {
|
||||
sector->data[c] = uint8_t(get_next_byte());
|
||||
checksum ^= sector->data[c];
|
||||
}
|
||||
|
||||
if(checksum == get_next_byte()) {
|
||||
uint16_t sector_address = uint16_t((sector->track << 8) | sector->sector);
|
||||
sector_cache_[sector_address] = sector;
|
||||
return sector;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Sector> get_next_sector() {
|
||||
auto sector = std::make_shared<Sector>();
|
||||
const int max_index_count = index_count_ + 2;
|
||||
|
||||
while(index_count_ < max_index_count) {
|
||||
// look for a sector header
|
||||
while(1) {
|
||||
if(proceed_to_next_block(max_index_count) == 0x08) break;
|
||||
if(index_count_ >= max_index_count) return nullptr;
|
||||
}
|
||||
|
||||
// get sector details, skip if this looks malformed
|
||||
uint8_t checksum = uint8_t(get_next_byte());
|
||||
sector->sector = uint8_t(get_next_byte());
|
||||
sector->track = uint8_t(get_next_byte());
|
||||
uint8_t disk_id[2];
|
||||
disk_id[0] = uint8_t(get_next_byte());
|
||||
disk_id[1] = uint8_t(get_next_byte());
|
||||
if(checksum != (sector->sector ^ sector->track ^ disk_id[0] ^ disk_id[1])) continue;
|
||||
|
||||
// look for the following data
|
||||
while(1) {
|
||||
if(proceed_to_next_block(max_index_count) == 0x07) break;
|
||||
if(index_count_ >= max_index_count) return nullptr;
|
||||
}
|
||||
|
||||
checksum = 0;
|
||||
for(std::size_t c = 0; c < 256; c++) {
|
||||
sector->data[c] = uint8_t(get_next_byte());
|
||||
checksum ^= sector->data[c];
|
||||
}
|
||||
|
||||
if(checksum == get_next_byte()) {
|
||||
uint16_t sector_address = uint16_t((sector->track << 8) | sector->sector);
|
||||
sector_cache_[sector_address] = sector;
|
||||
return sector;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk) {
|
||||
@ -181,7 +181,7 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
|
||||
std::vector<uint8_t> directory;
|
||||
uint8_t next_track = 18;
|
||||
uint8_t next_sector = 1;
|
||||
while(1) {
|
||||
while(true) {
|
||||
sector = parser.sector(next_track, next_sector);
|
||||
if(!sector) break;
|
||||
directory.insert(directory.end(), sector->data.begin(), sector->data.end());
|
||||
@ -216,7 +216,9 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
|
||||
}
|
||||
new_file.name = Storage::Data::Commodore::petscii_from_bytes(&new_file.raw_name[0], 16, false);
|
||||
|
||||
std::size_t number_of_sectors = size_t(directory[header_pointer + 0x1e]) + (size_t(directory[header_pointer + 0x1f]) << 8);
|
||||
std::size_t number_of_sectors =
|
||||
size_t(directory[header_pointer + 0x1e]) +
|
||||
(size_t(directory[header_pointer + 0x1f]) << 8);
|
||||
new_file.data.reserve((number_of_sectors - 1) * 254 + 252);
|
||||
|
||||
bool is_first_sector = true;
|
||||
@ -229,9 +231,17 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
|
||||
|
||||
if(is_first_sector) new_file.starting_address = uint16_t(sector->data[2]) | uint16_t(sector->data[3] << 8);
|
||||
if(next_track)
|
||||
new_file.data.insert(new_file.data.end(), sector->data.begin() + (is_first_sector ? 4 : 2), sector->data.end());
|
||||
new_file.data.insert(
|
||||
new_file.data.end(),
|
||||
sector->data.begin() + (is_first_sector ? 4 : 2),
|
||||
sector->data.end()
|
||||
);
|
||||
else
|
||||
new_file.data.insert(new_file.data.end(), sector->data.begin() + 2, sector->data.begin() + next_sector);
|
||||
new_file.data.insert(
|
||||
new_file.data.end(),
|
||||
sector->data.begin() + 2,
|
||||
sector->data.begin() + next_sector
|
||||
);
|
||||
|
||||
is_first_sector = false;
|
||||
}
|
||||
|
@ -15,6 +15,6 @@
|
||||
|
||||
namespace Analyser::Static::Commodore {
|
||||
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Disk::Disk> &disk);
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Disk::Disk> &);
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
using namespace Analyser::Static::Commodore;
|
||||
|
||||
static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
Vic20CartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
Vic20CartridgesFrom(const std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> &cartridges) {
|
||||
std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>> vic20_cartridges;
|
||||
|
||||
for(const auto &cartridge : cartridges) {
|
||||
@ -42,7 +42,11 @@ static std::vector<std::shared_ptr<Storage::Cartridge::Cartridge>>
|
||||
return vic20_cartridges;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &file_name,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
TargetList destination;
|
||||
|
||||
auto target = std::make_unique<Target>();
|
||||
@ -93,7 +97,8 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
||||
// make a first guess based on loading address
|
||||
switch(files.front().starting_address) {
|
||||
default:
|
||||
Log::Logger<Log::Source::CommodoreStaticAnalyser>().error().append("Unrecognised loading address for Commodore program: %04x", files.front().starting_address);
|
||||
Log::Logger<Log::Source::CommodoreStaticAnalyser>().error().append(
|
||||
"Unrecognised loading address for Commodore program: %04x", files.front().starting_address);
|
||||
[[fallthrough]];
|
||||
case 0x1001:
|
||||
memory_model = Target::MemoryModel::Unexpanded;
|
||||
@ -142,7 +147,8 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
||||
// region 0x0400 to 0x1000 is touched and this is an unexpanded machine, mark as 3kb.
|
||||
// if(starting_address + file_size > 0x2000)
|
||||
// target->memory_model = Target::MemoryModel::ThirtyTwoKB;
|
||||
// else if(target->memory_model == Target::MemoryModel::Unexpanded && !(starting_address >= 0x1000 || starting_address+file_size < 0x0400))
|
||||
// else if(target->memory_model == Target::MemoryModel::Unexpanded &&
|
||||
// !(starting_address >= 0x1000 || starting_address+file_size < 0x0400))
|
||||
// target->memory_model = Target::MemoryModel::ThirtyTwoKB;
|
||||
// }
|
||||
// }
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Commodore {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -55,7 +55,9 @@ std::vector<File> Analyser::Static::Commodore::GetFiles(const std::shared_ptr<St
|
||||
new_file.starting_address = header->starting_address;
|
||||
new_file.ending_address = header->ending_address;
|
||||
new_file.data.swap(data->data);
|
||||
new_file.type = (header->type == Storage::Tape::Commodore::Header::RelocatableProgram) ? File::RelocatableProgram : File::NonRelocatableProgram;
|
||||
new_file.type =
|
||||
header->type == Storage::Tape::Commodore::Header::RelocatableProgram
|
||||
? File::RelocatableProgram : File::NonRelocatableProgram;
|
||||
|
||||
file_list.push_back(new_file);
|
||||
}
|
||||
|
@ -13,6 +13,6 @@
|
||||
|
||||
namespace Analyser::Static::Commodore {
|
||||
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &);
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,12 @@ using PartialDisassembly = Analyser::Static::Disassembly::PartialDisassembly<Dis
|
||||
|
||||
struct MOS6502Disassembler {
|
||||
|
||||
static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<uint8_t> &memory, const std::function<std::size_t(uint16_t)> &address_mapper, uint16_t entry_point) {
|
||||
static void AddToDisassembly(
|
||||
PartialDisassembly &disassembly,
|
||||
const std::vector<uint8_t> &memory,
|
||||
const std::function<std::size_t(uint16_t)> &address_mapper,
|
||||
uint16_t entry_point
|
||||
) {
|
||||
disassembly.disassembly.internal_calls.insert(entry_point);
|
||||
uint16_t address = entry_point;
|
||||
while(true) {
|
||||
@ -75,23 +80,25 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
|
||||
}
|
||||
|
||||
// Decode operation.
|
||||
#define RM_INSTRUCTION(base, op) \
|
||||
case base+0x09: case base+0x05: case base+0x15: case base+0x01: case base+0x11: case base+0x0d: case base+0x1d: case base+0x19: \
|
||||
instruction.operation = op; \
|
||||
#define RM_INSTRUCTION(base, op) \
|
||||
case base+0x09: case base+0x05: case base+0x15: case base+0x01: \
|
||||
case base+0x11: case base+0x0d: case base+0x1d: case base+0x19: \
|
||||
instruction.operation = op; \
|
||||
break;
|
||||
|
||||
#define URM_INSTRUCTION(base, op) \
|
||||
#define URM_INSTRUCTION(base, op) \
|
||||
case base+0x07: case base+0x17: case base+0x03: case base+0x13: case base+0x0f: case base+0x1f: case base+0x1b: \
|
||||
instruction.operation = op; \
|
||||
instruction.operation = op; \
|
||||
break;
|
||||
|
||||
#define M_INSTRUCTION(base, op) \
|
||||
#define M_INSTRUCTION(base, op) \
|
||||
case base+0x0a: case base+0x06: case base+0x16: case base+0x0e: case base+0x1e: \
|
||||
instruction.operation = op; \
|
||||
instruction.operation = op; \
|
||||
break;
|
||||
|
||||
#define IM_INSTRUCTION(base, op) \
|
||||
#define IM_INSTRUCTION(base, op) \
|
||||
case base: instruction.operation = op; break;
|
||||
|
||||
switch(operation) {
|
||||
default:
|
||||
instruction.operation = Instruction::KIL;
|
||||
@ -259,7 +266,10 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
|
||||
disassembly.disassembly.instructions_by_address[instruction.address] = instruction;
|
||||
|
||||
// TODO: something wider-ranging than this
|
||||
if(instruction.addressing_mode == Instruction::Absolute || instruction.addressing_mode == Instruction::ZeroPage) {
|
||||
if(
|
||||
instruction.addressing_mode == Instruction::Absolute ||
|
||||
instruction.addressing_mode == Instruction::ZeroPage
|
||||
) {
|
||||
const size_t mapped_address = address_mapper(instruction.operand);
|
||||
const bool is_external = mapped_address >= memory.size();
|
||||
|
||||
@ -272,20 +282,23 @@ static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<
|
||||
case Instruction::ADC: case Instruction::SBC:
|
||||
case Instruction::LAS:
|
||||
case Instruction::CMP: case Instruction::CPX: case Instruction::CPY:
|
||||
(is_external ? disassembly.disassembly.external_loads : disassembly.disassembly.internal_loads).insert(instruction.operand);
|
||||
(is_external ? disassembly.disassembly.external_loads : disassembly.disassembly.internal_loads)
|
||||
.insert(instruction.operand);
|
||||
break;
|
||||
|
||||
case Instruction::STY: case Instruction::STX: case Instruction::STA:
|
||||
case Instruction::AXS: case Instruction::AHX: case Instruction::SHX: case Instruction::SHY:
|
||||
case Instruction::TAS:
|
||||
(is_external ? disassembly.disassembly.external_stores : disassembly.disassembly.internal_stores).insert(instruction.operand);
|
||||
(is_external ? disassembly.disassembly.external_stores : disassembly.disassembly.internal_stores)
|
||||
.insert(instruction.operand);
|
||||
break;
|
||||
|
||||
case Instruction::SLO: case Instruction::RLA: case Instruction::SRE: case Instruction::RRA:
|
||||
case Instruction::DCP: case Instruction::ISC:
|
||||
case Instruction::INC: case Instruction::DEC:
|
||||
case Instruction::ASL: case Instruction::ROL: case Instruction::LSR: case Instruction::ROR:
|
||||
(is_external ? disassembly.disassembly.external_modifies : disassembly.disassembly.internal_modifies).insert(instruction.operand);
|
||||
(is_external ? disassembly.disassembly.external_modifies : disassembly.disassembly.internal_modifies)
|
||||
.insert(instruction.operand);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -330,5 +343,10 @@ Disassembly Analyser::Static::MOS6502::Disassemble(
|
||||
const std::vector<uint8_t> &memory,
|
||||
const std::function<std::size_t(uint16_t)> &address_mapper,
|
||||
std::vector<uint16_t> entry_points) {
|
||||
return Analyser::Static::Disassembly::Disassemble<Disassembly, uint16_t, MOS6502Disassembler>(memory, address_mapper, entry_points, false);
|
||||
return Analyser::Static::Disassembly::Disassemble<Disassembly, uint16_t, MOS6502Disassembler>(
|
||||
memory,
|
||||
address_mapper,
|
||||
entry_points,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace Analyser::Static::Disassembler {
|
||||
Provides an address mapper that relocates a chunk of memory so that it starts at
|
||||
address @c start_address.
|
||||
*/
|
||||
template <typename T> std::function<std::size_t(T)> OffsetMapper(T start_address) {
|
||||
template <typename T> std::function<std::size_t(T)> OffsetMapper(const T start_address) {
|
||||
return [start_address](T argument) {
|
||||
return size_t(argument - start_address);
|
||||
};
|
||||
|
@ -16,44 +16,48 @@ namespace {
|
||||
using PartialDisassembly = Analyser::Static::Disassembly::PartialDisassembly<Disassembly, uint16_t>;
|
||||
|
||||
class Accessor {
|
||||
public:
|
||||
Accessor(const std::vector<uint8_t> &memory, const std::function<std::size_t(uint16_t)> &address_mapper, uint16_t address) :
|
||||
memory_(memory), address_mapper_(address_mapper), address_(address) {}
|
||||
public:
|
||||
Accessor(
|
||||
const std::vector<uint8_t> &memory,
|
||||
const std::function<std::size_t(uint16_t)> &address_mapper,
|
||||
uint16_t address
|
||||
) :
|
||||
memory_(memory), address_mapper_(address_mapper), address_(address) {}
|
||||
|
||||
uint8_t byte() {
|
||||
std::size_t mapped_address = address_mapper_(address_);
|
||||
address_++;
|
||||
if(mapped_address >= memory_.size()) {
|
||||
overrun_ = true;
|
||||
return 0xff;
|
||||
}
|
||||
return memory_[mapped_address];
|
||||
uint8_t byte() {
|
||||
std::size_t mapped_address = address_mapper_(address_);
|
||||
++address_;
|
||||
if(mapped_address >= memory_.size()) {
|
||||
overrun_ = true;
|
||||
return 0xff;
|
||||
}
|
||||
return memory_[mapped_address];
|
||||
}
|
||||
|
||||
uint16_t word() {
|
||||
uint8_t low = byte();
|
||||
uint8_t high = byte();
|
||||
return uint16_t(low | (high << 8));
|
||||
}
|
||||
uint16_t word() {
|
||||
uint8_t low = byte();
|
||||
uint8_t high = byte();
|
||||
return uint16_t(low | (high << 8));
|
||||
}
|
||||
|
||||
bool overrun() {
|
||||
return overrun_;
|
||||
}
|
||||
bool overrun() const {
|
||||
return overrun_;
|
||||
}
|
||||
|
||||
bool at_end() {
|
||||
std::size_t mapped_address = address_mapper_(address_);
|
||||
return mapped_address >= memory_.size();
|
||||
}
|
||||
bool at_end() const {
|
||||
std::size_t mapped_address = address_mapper_(address_);
|
||||
return mapped_address >= memory_.size();
|
||||
}
|
||||
|
||||
uint16_t address() {
|
||||
return address_;
|
||||
}
|
||||
uint16_t address() const {
|
||||
return address_;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<uint8_t> &memory_;
|
||||
const std::function<std::size_t(uint16_t)> &address_mapper_;
|
||||
uint16_t address_;
|
||||
bool overrun_ = false;
|
||||
private:
|
||||
const std::vector<uint8_t> &memory_;
|
||||
const std::function<std::size_t(uint16_t)> &address_mapper_;
|
||||
uint16_t address_;
|
||||
bool overrun_ = false;
|
||||
};
|
||||
|
||||
constexpr uint8_t x(uint8_t v) { return v >> 6; }
|
||||
@ -83,8 +87,12 @@ Instruction::Location register_pair_table2[] = {
|
||||
Instruction::Location::AF
|
||||
};
|
||||
|
||||
Instruction::Location RegisterTableEntry(int offset, Accessor &accessor, Instruction &instruction, bool needs_indirect_offset) {
|
||||
Instruction::Location register_table[] = {
|
||||
Instruction::Location RegisterTableEntry(
|
||||
const int offset, Accessor &accessor,
|
||||
Instruction &instruction,
|
||||
const bool needs_indirect_offset
|
||||
) {
|
||||
constexpr Instruction::Location register_table[] = {
|
||||
Instruction::Location::B, Instruction::Location::C,
|
||||
Instruction::Location::D, Instruction::Location::E,
|
||||
Instruction::Location::H, Instruction::Location::L,
|
||||
@ -92,7 +100,7 @@ Instruction::Location RegisterTableEntry(int offset, Accessor &accessor, Instruc
|
||||
Instruction::Location::A
|
||||
};
|
||||
|
||||
Instruction::Location location = register_table[offset];
|
||||
const Instruction::Location location = register_table[offset];
|
||||
if(location == Instruction::Location::HL_Indirect && needs_indirect_offset) {
|
||||
instruction.offset = accessor.byte() - 128;
|
||||
}
|
||||
@ -100,7 +108,7 @@ Instruction::Location RegisterTableEntry(int offset, Accessor &accessor, Instruc
|
||||
return location;
|
||||
}
|
||||
|
||||
Instruction::Operation alu_table[] = {
|
||||
constexpr Instruction::Operation alu_table[] = {
|
||||
Instruction::Operation::ADD,
|
||||
Instruction::Operation::ADC,
|
||||
Instruction::Operation::SUB,
|
||||
@ -111,7 +119,7 @@ Instruction::Operation alu_table[] = {
|
||||
Instruction::Operation::CP
|
||||
};
|
||||
|
||||
Instruction::Operation rotation_table[] = {
|
||||
constexpr Instruction::Operation rotation_table[] = {
|
||||
Instruction::Operation::RLC,
|
||||
Instruction::Operation::RRC,
|
||||
Instruction::Operation::RL,
|
||||
@ -122,19 +130,32 @@ Instruction::Operation rotation_table[] = {
|
||||
Instruction::Operation::SRL
|
||||
};
|
||||
|
||||
Instruction::Operation block_table[][4] = {
|
||||
{Instruction::Operation::LDI, Instruction::Operation::CPI, Instruction::Operation::INI, Instruction::Operation::OUTI},
|
||||
{Instruction::Operation::LDD, Instruction::Operation::CPD, Instruction::Operation::IND, Instruction::Operation::OUTD},
|
||||
{Instruction::Operation::LDIR, Instruction::Operation::CPIR, Instruction::Operation::INIR, Instruction::Operation::OTIR},
|
||||
{Instruction::Operation::LDDR, Instruction::Operation::CPDR, Instruction::Operation::INDR, Instruction::Operation::OTDR},
|
||||
constexpr Instruction::Operation block_table[][4] = {
|
||||
{
|
||||
Instruction::Operation::LDI, Instruction::Operation::CPI,
|
||||
Instruction::Operation::INI, Instruction::Operation::OUTI
|
||||
},
|
||||
{
|
||||
Instruction::Operation::LDD, Instruction::Operation::CPD,
|
||||
Instruction::Operation::IND, Instruction::Operation::OUTD
|
||||
},
|
||||
{
|
||||
Instruction::Operation::LDIR, Instruction::Operation::CPIR,
|
||||
Instruction::Operation::INIR, Instruction::Operation::OTIR
|
||||
},
|
||||
{
|
||||
Instruction::Operation::LDDR, Instruction::Operation::CPDR,
|
||||
Instruction::Operation::INDR, Instruction::Operation::OTDR
|
||||
},
|
||||
};
|
||||
|
||||
void DisassembleCBPage(Accessor &accessor, Instruction &instruction, bool needs_indirect_offset) {
|
||||
void DisassembleCBPage(Accessor &accessor, Instruction &instruction, const bool needs_indirect_offset) {
|
||||
const uint8_t operation = accessor.byte();
|
||||
|
||||
if(!x(operation)) {
|
||||
instruction.operation = rotation_table[y(operation)];
|
||||
instruction.source = instruction.destination = RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source = instruction.destination =
|
||||
RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
|
||||
} else {
|
||||
instruction.destination = RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source = Instruction::Location::Operand;
|
||||
@ -148,7 +169,7 @@ void DisassembleCBPage(Accessor &accessor, Instruction &instruction, bool needs_
|
||||
}
|
||||
}
|
||||
|
||||
void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_indirect_offset) {
|
||||
void DisassembleEDPage(Accessor &accessor, Instruction &instruction, const bool needs_indirect_offset) {
|
||||
const uint8_t operation = accessor.byte();
|
||||
|
||||
switch(x(operation)) {
|
||||
@ -170,7 +191,8 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
|
||||
if(y(operation) == 6) {
|
||||
instruction.destination = Instruction::Location::None;
|
||||
} else {
|
||||
instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.destination =
|
||||
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@ -179,7 +201,8 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
|
||||
if(y(operation) == 6) {
|
||||
instruction.source = Instruction::Location::None;
|
||||
} else {
|
||||
instruction.source = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source =
|
||||
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@ -190,11 +213,13 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
|
||||
case 3:
|
||||
instruction.operation = Instruction::Operation::LD;
|
||||
if(q(operation)) {
|
||||
instruction.destination = RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.destination =
|
||||
RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source = Instruction::Location::Operand_Indirect;
|
||||
} else {
|
||||
instruction.destination = Instruction::Location::Operand_Indirect;
|
||||
instruction.source = RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source =
|
||||
RegisterTableEntry(p(operation), accessor, instruction, needs_indirect_offset);
|
||||
}
|
||||
instruction.operand = accessor.word();
|
||||
break;
|
||||
@ -202,7 +227,8 @@ void DisassembleEDPage(Accessor &accessor, Instruction &instruction, bool needs_
|
||||
instruction.operation = Instruction::Operation::NEG;
|
||||
break;
|
||||
case 5:
|
||||
instruction.operation = (y(operation) == 1) ? Instruction::Operation::RETI : Instruction::Operation::RETN;
|
||||
instruction.operation =
|
||||
y(operation) == 1 ? Instruction::Operation::RETI : Instruction::Operation::RETN;
|
||||
break;
|
||||
case 6:
|
||||
instruction.operation = Instruction::Operation::IM;
|
||||
@ -253,7 +279,7 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
|
||||
} hl_substitution = None;
|
||||
|
||||
while(true) {
|
||||
uint8_t operation = accessor.byte();
|
||||
const uint8_t operation = accessor.byte();
|
||||
|
||||
switch(x(operation)) {
|
||||
case 0:
|
||||
@ -343,15 +369,18 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
|
||||
break;
|
||||
case 4:
|
||||
instruction.operation = Instruction::Operation::INC;
|
||||
instruction.source = instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source = instruction.destination =
|
||||
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
break;
|
||||
case 5:
|
||||
instruction.operation = Instruction::Operation::DEC;
|
||||
instruction.source = instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source = instruction.destination =
|
||||
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
break;
|
||||
case 6:
|
||||
instruction.operation = Instruction::Operation::LD;
|
||||
instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.destination =
|
||||
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source = Instruction::Location::Operand;
|
||||
instruction.operand = accessor.byte();
|
||||
break;
|
||||
@ -374,8 +403,10 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
|
||||
instruction.operation = Instruction::Operation::HALT;
|
||||
} else {
|
||||
instruction.operation = Instruction::Operation::LD;
|
||||
instruction.source = RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.destination = RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.source =
|
||||
RegisterTableEntry(z(operation), accessor, instruction, needs_indirect_offset);
|
||||
instruction.destination =
|
||||
RegisterTableEntry(y(operation), accessor, instruction, needs_indirect_offset);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
@ -517,10 +548,14 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
|
||||
instruction.destination == Instruction::Location::HL_Indirect) {
|
||||
|
||||
if(instruction.source == Instruction::Location::HL_Indirect) {
|
||||
instruction.source = (hl_substitution == IX) ? Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
|
||||
instruction.source =
|
||||
hl_substitution == IX ?
|
||||
Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
|
||||
}
|
||||
if(instruction.destination == Instruction::Location::HL_Indirect) {
|
||||
instruction.destination = (hl_substitution == IX) ? Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
|
||||
instruction.destination =
|
||||
hl_substitution == IX ?
|
||||
Instruction::Location::IX_Indirect_Offset : Instruction::Location::IY_Indirect_Offset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -542,7 +577,12 @@ void DisassembleMainPage(Accessor &accessor, Instruction &instruction) {
|
||||
}
|
||||
|
||||
struct Z80Disassembler {
|
||||
static void AddToDisassembly(PartialDisassembly &disassembly, const std::vector<uint8_t> &memory, const std::function<std::size_t(uint16_t)> &address_mapper, uint16_t entry_point) {
|
||||
static void AddToDisassembly(
|
||||
PartialDisassembly &disassembly,
|
||||
const std::vector<uint8_t> &memory,
|
||||
const std::function<std::size_t(uint16_t)> &address_mapper,
|
||||
const uint16_t entry_point
|
||||
) {
|
||||
disassembly.disassembly.internal_calls.insert(entry_point);
|
||||
Accessor accessor(memory, address_mapper, entry_point);
|
||||
|
||||
|
@ -47,7 +47,11 @@ Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector
|
||||
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// This analyser can comprehend disks only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
@ -62,7 +66,8 @@ Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &m
|
||||
}
|
||||
|
||||
// Grab track 0, sector 0: the boot sector.
|
||||
const auto track_zero = disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
|
||||
const auto track_zero =
|
||||
disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
|
||||
const auto sector_map = Storage::Encodings::AppleGCR::sectors_from_segment(
|
||||
Storage::Disk::track_serialisation(*track_zero, Storage::Time(1, 50000)));
|
||||
|
||||
@ -89,7 +94,8 @@ Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &m
|
||||
// If the boot sector looks like it's intended for the Oric, create an Oric.
|
||||
// Otherwise go with the Apple II.
|
||||
|
||||
const auto disassembly = Analyser::Static::MOS6502::Disassemble(sector_zero->data, Analyser::Static::Disassembler::OffsetMapper(0xb800), {0xb800});
|
||||
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
|
||||
sector_zero->data, Analyser::Static::Disassembler::OffsetMapper(0xb800), {0xb800});
|
||||
|
||||
bool did_read_shift_register = false;
|
||||
bool is_oric = false;
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::DiskII {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,11 @@ bool insensitive_equal(const std::string &lhs, const std::string &rhs) {
|
||||
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// This analyser can comprehend disks only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
@ -72,7 +76,8 @@ Analyser::Static::TargetList Analyser::Static::Enterprise::GetTargets(const Medi
|
||||
|
||||
if(!has_exdos_ini) {
|
||||
if(did_pick_file) {
|
||||
target->loading_command = std::string("run \"") + selected_file->name + "." + selected_file->extension + "\"\n";
|
||||
target->loading_command =
|
||||
std::string("run \"") + selected_file->name + "." + selected_file->extension + "\"\n";
|
||||
} else {
|
||||
target->loading_command = ":dir\n";
|
||||
}
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Enterprise {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,11 @@
|
||||
#include "../../../Storage/Disk/Encodings/MFM/SegmentParser.hpp"
|
||||
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &file_name,
|
||||
TargetPlatform::IntType platforms
|
||||
) {
|
||||
// This analyser can comprehend disks only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
@ -39,7 +43,8 @@ Analyser::Static::TargetList Analyser::Static::FAT12::GetTargets(const Media &me
|
||||
}
|
||||
|
||||
// Attempt to grab MFM track 0, sector 1: the boot sector.
|
||||
const auto track_zero = disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
|
||||
const auto track_zero =
|
||||
disk->get_track_at_position(Storage::Disk::Track::Address(0, Storage::Disk::HeadPosition(0)));
|
||||
const auto sector_map = Storage::Encodings::MFM::sectors_from_segment(
|
||||
Storage::Disk::track_serialisation(
|
||||
*track_zero,
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::FAT12 {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ struct Cartridge: public ::Storage::Cartridge::Cartridge {
|
||||
};
|
||||
const Type type;
|
||||
|
||||
Cartridge(const std::vector<Segment> &segments, Type type) :
|
||||
Cartridge(const std::vector<Segment> &segments, const Type type) :
|
||||
Storage::Cartridge::Cartridge(segments), type(type) {}
|
||||
};
|
||||
|
||||
|
@ -27,7 +27,8 @@ static std::unique_ptr<Analyser::Static::Target> CartridgeTarget(
|
||||
std::vector<Storage::Cartridge::Cartridge::Segment> output_segments;
|
||||
if(segment.data.size() & 0x1fff) {
|
||||
std::vector<uint8_t> truncated_data;
|
||||
std::vector<uint8_t>::difference_type truncated_size = std::vector<uint8_t>::difference_type(segment.data.size()) & ~0x1fff;
|
||||
const auto truncated_size =
|
||||
std::vector<uint8_t>::difference_type(segment.data.size()) & ~0x1fff;
|
||||
truncated_data.insert(truncated_data.begin(), segment.data.begin(), segment.data.begin() + truncated_size);
|
||||
output_segments.emplace_back(start_address, truncated_data);
|
||||
} else {
|
||||
@ -82,7 +83,7 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
|
||||
if(segments.size() != 1) continue;
|
||||
|
||||
// Which must be no more than 63 bytes larger than a multiple of 8 kb in size.
|
||||
Storage::Cartridge::Cartridge::Segment segment = segments.front();
|
||||
const Storage::Cartridge::Cartridge::Segment &segment = segments.front();
|
||||
const size_t data_size = segment.data.size();
|
||||
if(data_size < 0x2000 || (data_size & 0x1fff) > 64) continue;
|
||||
|
||||
@ -101,7 +102,7 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
|
||||
// Reject cartridge if the ROM header wasn't found.
|
||||
if(!found_start) continue;
|
||||
|
||||
uint16_t init_address = uint16_t(segment.data[2] | (segment.data[3] << 8));
|
||||
const uint16_t init_address = uint16_t(segment.data[2] | (segment.data[3] << 8));
|
||||
// TODO: check for a rational init address?
|
||||
|
||||
// If this ROM is less than 48kb in size then it's an ordinary ROM. Just emplace it and move on.
|
||||
@ -137,10 +138,12 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
|
||||
}
|
||||
|
||||
// Weight confidences by number of observed hits; if any is above 60% confidence, just use it.
|
||||
const auto ascii_8kb_total = address_counts[0x6000] + address_counts[0x6800] + address_counts[0x7000] + address_counts[0x7800];
|
||||
const auto ascii_8kb_total =
|
||||
address_counts[0x6000] + address_counts[0x6800] + address_counts[0x7000] + address_counts[0x7800];
|
||||
const auto ascii_16kb_total = address_counts[0x6000] + address_counts[0x7000] + address_counts[0x77ff];
|
||||
const auto konami_total = address_counts[0x6000] + address_counts[0x8000] + address_counts[0xa000];
|
||||
const auto konami_with_scc_total = address_counts[0x5000] + address_counts[0x7000] + address_counts[0x9000] + address_counts[0xb000];
|
||||
const auto konami_with_scc_total =
|
||||
address_counts[0x5000] + address_counts[0x7000] + address_counts[0x9000] + address_counts[0xb000];
|
||||
|
||||
const auto total_hits = ascii_8kb_total + ascii_16kb_total + konami_total + konami_with_scc_total;
|
||||
|
||||
@ -182,7 +185,11 @@ static Analyser::Static::TargetList CartridgeTargetsFrom(
|
||||
return targets;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
TargetList destination;
|
||||
|
||||
// Append targets for any cartridges that look correct.
|
||||
@ -194,7 +201,7 @@ Analyser::Static::TargetList Analyser::Static::MSX::GetTargets(const Media &medi
|
||||
|
||||
// Check tapes for loadable files.
|
||||
for(auto &tape : media.tapes) {
|
||||
std::vector<File> files_on_tape = GetFiles(tape);
|
||||
const std::vector<File> files_on_tape = GetFiles(tape);
|
||||
if(!files_on_tape.empty()) {
|
||||
switch(files_on_tape.front().type) {
|
||||
case File::Type::ASCII: target->loading_command = "RUN\"CAS:\r"; break;
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::MSX {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,6 @@ struct File {
|
||||
File();
|
||||
};
|
||||
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Macintosh::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// This analyser can comprehend disks and mass-storage devices only.
|
||||
if(media.disks.empty() && media.mass_storage_devices.empty()) return {};
|
||||
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Macintosh {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -22,12 +22,22 @@ using namespace Analyser::Static::Oric;
|
||||
|
||||
namespace {
|
||||
|
||||
int score(const Analyser::Static::MOS6502::Disassembly &disassembly, const std::set<uint16_t> &rom_functions, const std::set<uint16_t> &variable_locations) {
|
||||
int score(
|
||||
const Analyser::Static::MOS6502::Disassembly &disassembly,
|
||||
const std::set<uint16_t> &rom_functions,
|
||||
const std::set<uint16_t> &variable_locations
|
||||
) {
|
||||
int score = 0;
|
||||
|
||||
for(const auto address : disassembly.outward_calls) score += (rom_functions.find(address) != rom_functions.end()) ? 1 : -1;
|
||||
for(const auto address : disassembly.external_stores) score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
|
||||
for(const auto address : disassembly.external_loads) score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
|
||||
for(const auto address : disassembly.outward_calls) {
|
||||
score += (rom_functions.find(address) != rom_functions.end()) ? 1 : -1;
|
||||
}
|
||||
for(const auto address : disassembly.external_stores) {
|
||||
score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
|
||||
}
|
||||
for(const auto address : disassembly.external_loads) {
|
||||
score += (variable_locations.find(address) != variable_locations.end()) ? 1 : -1;
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
@ -35,19 +45,32 @@ int score(const Analyser::Static::MOS6502::Disassembly &disassembly, const std::
|
||||
int basic10_score(const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
const std::set<uint16_t> rom_functions = {
|
||||
0x0228, 0x022b,
|
||||
0xc3ca, 0xc3f8, 0xc448, 0xc47c, 0xc4b5, 0xc4e3, 0xc4e0, 0xc524, 0xc56f, 0xc5a2, 0xc5f8, 0xc60a, 0xc6a5, 0xc6de, 0xc719, 0xc738,
|
||||
0xc773, 0xc824, 0xc832, 0xc841, 0xc8c1, 0xc8fe, 0xc91f, 0xc93f, 0xc941, 0xc91e, 0xc98b, 0xc996, 0xc9b3, 0xc9e0, 0xca0a, 0xca1c,
|
||||
0xca1f, 0xca3e, 0xca61, 0xca78, 0xca98, 0xcad2, 0xcb61, 0xcb9f, 0xcc59, 0xcbed, 0xcc0a, 0xcc8c, 0xcc8f, 0xccba, 0xccc9, 0xccfd,
|
||||
0xce0c, 0xce77, 0xce8b, 0xcfac, 0xcf74, 0xd03c, 0xd059, 0xcff0, 0xd087, 0xd0f2, 0xd0fc, 0xd361, 0xd3eb, 0xd47e, 0xd4a6, 0xd401,
|
||||
0xd593, 0xd5a3, 0xd4fa, 0xd595, 0xd730, 0xd767, 0xd816, 0xd82a, 0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd80a, 0xd867, 0xd938, 0xd894,
|
||||
0xd89d, 0xd8ac, 0xd983, 0xd993, 0xd9b5, 0xd93d, 0xd965, 0xda3f, 0xd9c6, 0xda16, 0xdaab, 0xdada, 0xda6b, 0xdb92, 0xdbb9, 0xdc79,
|
||||
0xdd4d, 0xdda3, 0xddbf, 0xd0d0, 0xde77, 0xdef4, 0xdf0b, 0xdf0f, 0xdf04, 0xdf12, 0xdf31, 0xdf4c, 0xdf8c, 0xdfa5, 0xdfcf, 0xe076,
|
||||
0xe0c1, 0xe22a, 0xe27c, 0xe2a6, 0xe313, 0xe34b, 0xe387, 0xe38e, 0xe3d7, 0xe407, 0xe43b, 0xe46f, 0xe4a8, 0xe4f2, 0xe554, 0xe57d,
|
||||
0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab, 0xe5b6, 0xe5ea, 0xe563, 0xe5c6, 0xe630, 0xe696, 0xe6ba, 0xe6ca, 0xe725, 0xe7aa, 0xe903,
|
||||
0xe7db, 0xe80d, 0xe987, 0xe9d1, 0xe87d, 0xe905, 0xe965, 0xe974, 0xe994, 0xe9a9, 0xe9bb, 0xec45, 0xeccc, 0xedc4, 0xecc7, 0xed01,
|
||||
0xed09, 0xed70, 0xed81, 0xed8f, 0xe0ad, 0xeee8, 0xeef8, 0xebdf, 0xebe2, 0xebe5, 0xebeb, 0xebee, 0xebf4, 0xebf7, 0xebfa, 0xebe8,
|
||||
0xf43c, 0xf4ef, 0xf523, 0xf561, 0xf535, 0xf57b, 0xf5d3, 0xf71a, 0xf73f, 0xf7e4, 0xf7e0, 0xf82f, 0xf88f, 0xf8af, 0xf8b5, 0xf920,
|
||||
0xf967, 0xf960, 0xf9c9, 0xfa14, 0xfa85, 0xfa9b, 0xfab1, 0xfac7, 0xfafa, 0xfb10, 0xfb26, 0xfbb6, 0xfbfe
|
||||
0xc3ca, 0xc3f8, 0xc448, 0xc47c, 0xc4b5, 0xc4e3, 0xc4e0, 0xc524,
|
||||
0xc56f, 0xc5a2, 0xc5f8, 0xc60a, 0xc6a5, 0xc6de, 0xc719, 0xc738,
|
||||
0xc773, 0xc824, 0xc832, 0xc841, 0xc8c1, 0xc8fe, 0xc91f, 0xc93f,
|
||||
0xc941, 0xc91e, 0xc98b, 0xc996, 0xc9b3, 0xc9e0, 0xca0a, 0xca1c,
|
||||
0xca1f, 0xca3e, 0xca61, 0xca78, 0xca98, 0xcad2, 0xcb61, 0xcb9f,
|
||||
0xcc59, 0xcbed, 0xcc0a, 0xcc8c, 0xcc8f, 0xccba, 0xccc9, 0xccfd,
|
||||
0xce0c, 0xce77, 0xce8b, 0xcfac, 0xcf74, 0xd03c, 0xd059, 0xcff0,
|
||||
0xd087, 0xd0f2, 0xd0fc, 0xd361, 0xd3eb, 0xd47e, 0xd4a6, 0xd401,
|
||||
0xd593, 0xd5a3, 0xd4fa, 0xd595, 0xd730, 0xd767, 0xd816, 0xd82a,
|
||||
0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd80a, 0xd867, 0xd938, 0xd894,
|
||||
0xd89d, 0xd8ac, 0xd983, 0xd993, 0xd9b5, 0xd93d, 0xd965, 0xda3f,
|
||||
0xd9c6, 0xda16, 0xdaab, 0xdada, 0xda6b, 0xdb92, 0xdbb9, 0xdc79,
|
||||
0xdd4d, 0xdda3, 0xddbf, 0xd0d0, 0xde77, 0xdef4, 0xdf0b, 0xdf0f,
|
||||
0xdf04, 0xdf12, 0xdf31, 0xdf4c, 0xdf8c, 0xdfa5, 0xdfcf, 0xe076,
|
||||
0xe0c1, 0xe22a, 0xe27c, 0xe2a6, 0xe313, 0xe34b, 0xe387, 0xe38e,
|
||||
0xe3d7, 0xe407, 0xe43b, 0xe46f, 0xe4a8, 0xe4f2, 0xe554, 0xe57d,
|
||||
0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab, 0xe5b6, 0xe5ea, 0xe563,
|
||||
0xe5c6, 0xe630, 0xe696, 0xe6ba, 0xe6ca, 0xe725, 0xe7aa, 0xe903,
|
||||
0xe7db, 0xe80d, 0xe987, 0xe9d1, 0xe87d, 0xe905, 0xe965, 0xe974,
|
||||
0xe994, 0xe9a9, 0xe9bb, 0xec45, 0xeccc, 0xedc4, 0xecc7, 0xed01,
|
||||
0xed09, 0xed70, 0xed81, 0xed8f, 0xe0ad, 0xeee8, 0xeef8, 0xebdf,
|
||||
0xebe2, 0xebe5, 0xebeb, 0xebee, 0xebf4, 0xebf7, 0xebfa, 0xebe8,
|
||||
0xf43c, 0xf4ef, 0xf523, 0xf561, 0xf535, 0xf57b, 0xf5d3, 0xf71a,
|
||||
0xf73f, 0xf7e4, 0xf7e0, 0xf82f, 0xf88f, 0xf8af, 0xf8b5, 0xf920,
|
||||
0xf967, 0xf960, 0xf9c9, 0xfa14, 0xfa85, 0xfa9b, 0xfab1, 0xfac7,
|
||||
0xfafa, 0xfb10, 0xfb26, 0xfbb6, 0xfbfe
|
||||
};
|
||||
const std::set<uint16_t> variable_locations = {
|
||||
0x0228, 0x0229, 0x022a, 0x022b, 0x022c, 0x022d, 0x0230
|
||||
@ -59,19 +82,32 @@ int basic10_score(const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
int basic11_score(const Analyser::Static::MOS6502::Disassembly &disassembly) {
|
||||
const std::set<uint16_t> rom_functions = {
|
||||
0x0238, 0x023b, 0x023e, 0x0241, 0x0244, 0x0247,
|
||||
0xc3c6, 0xc3f4, 0xc444, 0xc47c, 0xc4a8, 0xc4d3, 0xc4e0, 0xc524, 0xc55f, 0xc592, 0xc5e8, 0xc5fa, 0xc692, 0xc6b3, 0xc6ee, 0xc70d,
|
||||
0xc748, 0xc7fd, 0xc809, 0xc816, 0xc82f, 0xc855, 0xc8c1, 0xc915, 0xc952, 0xc971, 0xc973, 0xc9a0, 0xc9bd, 0xc9c8, 0xc9e5, 0xca12,
|
||||
0xca3c, 0xca4e, 0xca51, 0xca70, 0xca99, 0xcac2, 0xcae2, 0xcb1c, 0xcbab, 0xcbf0, 0xcc59, 0xccb0, 0xccce, 0xcd16, 0xcd19, 0xcd46,
|
||||
0xcd55, 0xcd89, 0xce98, 0xcf03, 0xcf17, 0xcfac, 0xd000, 0xd03c, 0xd059, 0xd07c, 0xd113, 0xd17e, 0xd188, 0xd361, 0xd3eb, 0xd47e,
|
||||
0xd4a6, 0xd4ba, 0xd593, 0xd5a3, 0xd5b5, 0xd650, 0xd730, 0xd767, 0xd816, 0xd82a, 0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd8c5, 0xd922,
|
||||
0xd938, 0xd94f, 0xd958, 0xd967, 0xd983, 0xd993, 0xd9b5, 0xd9de, 0xda0c, 0xda3f, 0xda51, 0xdaa1, 0xdaab, 0xdada, 0xdaf6, 0xdb92,
|
||||
0xdbb9, 0xdcaf, 0xdd51, 0xdda7, 0xddc3, 0xddd4, 0xde77, 0xdef4, 0xdf0b, 0xdf0f, 0xdf13, 0xdf21, 0xdf49, 0xdf4c, 0xdf8c, 0xdfbd,
|
||||
0xdfe7, 0xe076, 0xe0c5, 0xe22e, 0xe27c, 0xe2aa, 0xe313, 0xe34f, 0xe38b, 0xe392, 0xe3db, 0xe407, 0xe43f, 0xe46f, 0xe4ac, 0xe4e0,
|
||||
0xe4f2, 0xe56c, 0xe57d, 0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab, 0xe5b6, 0xe5ea, 0xe5f5, 0xe607, 0xe65e, 0xe6c9, 0xe735, 0xe75a,
|
||||
0xe76a, 0xe7b2, 0xe85b, 0xe903, 0xe909, 0xe946, 0xe987, 0xe9d1, 0xeaf0, 0xeb78, 0xebce, 0xebe7, 0xec0c, 0xec21, 0xec33, 0xec45,
|
||||
0xeccc, 0xedc4, 0xede0, 0xee1a, 0xee22, 0xee8c, 0xee9d, 0xeeab, 0xeec9, 0xeee8, 0xeef8, 0xf0c8, 0xf0fd, 0xf110, 0xf11d, 0xf12d,
|
||||
0xf204, 0xf210, 0xf268, 0xf37f, 0xf495, 0xf4ef, 0xf523, 0xf561, 0xf590, 0xf5c1, 0xf602, 0xf71a, 0xf77c, 0xf7e4, 0xf816, 0xf865,
|
||||
0xf88f, 0xf8af, 0xf8b5, 0xf920, 0xf967, 0xf9aa, 0xf9c9, 0xfa14, 0xfa9f, 0xfab5, 0xfacb, 0xfae1, 0xfb14, 0xfb2a, 0xfb40, 0xfbd0,
|
||||
0xc3c6, 0xc3f4, 0xc444, 0xc47c, 0xc4a8, 0xc4d3, 0xc4e0, 0xc524,
|
||||
0xc55f, 0xc592, 0xc5e8, 0xc5fa, 0xc692, 0xc6b3, 0xc6ee, 0xc70d,
|
||||
0xc748, 0xc7fd, 0xc809, 0xc816, 0xc82f, 0xc855, 0xc8c1, 0xc915,
|
||||
0xc952, 0xc971, 0xc973, 0xc9a0, 0xc9bd, 0xc9c8, 0xc9e5, 0xca12,
|
||||
0xca3c, 0xca4e, 0xca51, 0xca70, 0xca99, 0xcac2, 0xcae2, 0xcb1c,
|
||||
0xcbab, 0xcbf0, 0xcc59, 0xccb0, 0xccce, 0xcd16, 0xcd19, 0xcd46,
|
||||
0xcd55, 0xcd89, 0xce98, 0xcf03, 0xcf17, 0xcfac, 0xd000, 0xd03c,
|
||||
0xd059, 0xd07c, 0xd113, 0xd17e, 0xd188, 0xd361, 0xd3eb, 0xd47e,
|
||||
0xd4a6, 0xd4ba, 0xd593, 0xd5a3, 0xd5b5, 0xd650, 0xd730, 0xd767,
|
||||
0xd816, 0xd82a, 0xd856, 0xd861, 0xd8a6, 0xd8b5, 0xd8c5, 0xd922,
|
||||
0xd938, 0xd94f, 0xd958, 0xd967, 0xd983, 0xd993, 0xd9b5, 0xd9de,
|
||||
0xda0c, 0xda3f, 0xda51, 0xdaa1, 0xdaab, 0xdada, 0xdaf6, 0xdb92,
|
||||
0xdbb9, 0xdcaf, 0xdd51, 0xdda7, 0xddc3, 0xddd4, 0xde77, 0xdef4,
|
||||
0xdf0b, 0xdf0f, 0xdf13, 0xdf21, 0xdf49, 0xdf4c, 0xdf8c, 0xdfbd,
|
||||
0xdfe7, 0xe076, 0xe0c5, 0xe22e, 0xe27c, 0xe2aa, 0xe313, 0xe34f,
|
||||
0xe38b, 0xe392, 0xe3db, 0xe407, 0xe43f, 0xe46f, 0xe4ac, 0xe4e0,
|
||||
0xe4f2, 0xe56c, 0xe57d, 0xe585, 0xe58c, 0xe594, 0xe5a4, 0xe5ab,
|
||||
0xe5b6, 0xe5ea, 0xe5f5, 0xe607, 0xe65e, 0xe6c9, 0xe735, 0xe75a,
|
||||
0xe76a, 0xe7b2, 0xe85b, 0xe903, 0xe909, 0xe946, 0xe987, 0xe9d1,
|
||||
0xeaf0, 0xeb78, 0xebce, 0xebe7, 0xec0c, 0xec21, 0xec33, 0xec45,
|
||||
0xeccc, 0xedc4, 0xede0, 0xee1a, 0xee22, 0xee8c, 0xee9d, 0xeeab,
|
||||
0xeec9, 0xeee8, 0xeef8, 0xf0c8, 0xf0fd, 0xf110, 0xf11d, 0xf12d,
|
||||
0xf204, 0xf210, 0xf268, 0xf37f, 0xf495, 0xf4ef, 0xf523, 0xf561,
|
||||
0xf590, 0xf5c1, 0xf602, 0xf71a, 0xf77c, 0xf7e4, 0xf816, 0xf865,
|
||||
0xf88f, 0xf8af, 0xf8b5, 0xf920, 0xf967, 0xf9aa, 0xf9c9, 0xfa14,
|
||||
0xfa9f, 0xfab5, 0xfacb, 0xfae1, 0xfb14, 0xfb2a, 0xfb40, 0xfbd0,
|
||||
0xfc18
|
||||
};
|
||||
const std::set<uint16_t> variable_locations = {
|
||||
@ -102,7 +138,7 @@ bool is_microdisc(Storage::Encodings::MFM::Parser &parser) {
|
||||
return !std::memcmp(signature, first_sample.data(), sizeof(signature));
|
||||
}
|
||||
|
||||
bool is_400_loader(Storage::Encodings::MFM::Parser &parser, uint16_t range_start, uint16_t range_end) {
|
||||
bool is_400_loader(Storage::Encodings::MFM::Parser &parser, const uint16_t range_start, const uint16_t range_end) {
|
||||
/*
|
||||
Both the Jasmin and BD-DOS boot sectors are sector 1 of track 0 and are loaded at $400;
|
||||
use disassembly to test for likely matches.
|
||||
@ -120,8 +156,8 @@ bool is_400_loader(Storage::Encodings::MFM::Parser &parser, uint16_t range_start
|
||||
}
|
||||
|
||||
// Grab a disassembly.
|
||||
const auto disassembly =
|
||||
Analyser::Static::MOS6502::Disassemble(first_sample, Analyser::Static::Disassembler::OffsetMapper(0x400), {0x400});
|
||||
const auto disassembly = Analyser::Static::MOS6502::Disassemble(
|
||||
first_sample, Analyser::Static::Disassembler::OffsetMapper(0x400), {0x400});
|
||||
|
||||
// Check for references to the Jasmin registers.
|
||||
int register_hits = 0;
|
||||
@ -145,7 +181,11 @@ bool is_bd500(Storage::Encodings::MFM::Parser &parser) {
|
||||
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
|
||||
@ -160,7 +200,11 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med
|
||||
if(file.data_type == File::MachineCode) {
|
||||
std::vector<uint16_t> entry_points = {file.starting_address};
|
||||
const Analyser::Static::MOS6502::Disassembly disassembly =
|
||||
Analyser::Static::MOS6502::Disassemble(file.data, Analyser::Static::Disassembler::OffsetMapper(file.starting_address), entry_points);
|
||||
Analyser::Static::MOS6502::Disassemble(
|
||||
file.data,
|
||||
Analyser::Static::Disassembler::OffsetMapper(file.starting_address),
|
||||
entry_points
|
||||
);
|
||||
|
||||
if(basic10_score(disassembly) > basic11_score(disassembly)) ++basic10_votes; else ++basic11_votes;
|
||||
}
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Oric {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,6 @@ struct File {
|
||||
std::vector<uint8_t> data;
|
||||
};
|
||||
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||
std::vector<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &);
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,11 @@
|
||||
#include "StaticAnalyser.hpp"
|
||||
#include "Target.hpp"
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::PCCompatible::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::PCCompatible::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
// This analyser can comprehend disks only.
|
||||
if(media.disks.empty()) return {};
|
||||
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::PCCompatible {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,11 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &file_name,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
if(media.cartridges.empty())
|
||||
return {};
|
||||
|
||||
@ -54,7 +58,8 @@ Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &med
|
||||
if(lowercase_name.find("(jp)") == std::string::npos) {
|
||||
target->region =
|
||||
(lowercase_name.find("(us)") == std::string::npos &&
|
||||
lowercase_name.find("(ntsc)") == std::string::npos) ? Target::Region::Europe : Target::Region::USA;
|
||||
lowercase_name.find("(ntsc)") == std::string::npos) ?
|
||||
Target::Region::Europe : Target::Region::USA;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
@ -63,9 +68,9 @@ Analyser::Static::TargetList Analyser::Static::Sega::GetTargets(const Media &med
|
||||
// If one is found, set the paging scheme appropriately.
|
||||
const uint16_t inverse_checksum = uint16_t(0x10000 - (data[0x7fe6] | (data[0x7fe7] << 8)));
|
||||
if(
|
||||
data[0x7fe3] >= 0x87 && data[0x7fe3] < 0x96 && // i.e. game is dated between 1987 and 1996
|
||||
data[0x7fe3] >= 0x87 && data[0x7fe3] < 0x96 && // i.e. game is dated between 1987 and 1996
|
||||
(inverse_checksum&0xff) == data[0x7fe8] &&
|
||||
(inverse_checksum >> 8) == data[0x7fe9] && // i.e. the standard checksum appears to be present
|
||||
(inverse_checksum >> 8) == data[0x7fe9] && // i.e. the standard checksum appears to be present.
|
||||
!data[0x7fea] && !data[0x7feb] && !data[0x7fec] && !data[0x7fed] && !data[0x7fee] && !data[0x7fef]
|
||||
) {
|
||||
target->paging_scheme = Target::PagingScheme::Codemasters;
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::Sega {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ struct Target: public Analyser::Static::Target, public Reflection::StructImpl<Ta
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool is_master_system(Analyser::Static::Sega::Target::Model model) {
|
||||
constexpr bool is_master_system(const Analyser::Static::Sega::Target::Model model) {
|
||||
return model >= Analyser::Static::Sega::Target::Model::MasterSystem;
|
||||
}
|
||||
|
||||
|
@ -104,14 +104,14 @@ std::string get_extension(const std::string &name) {
|
||||
}
|
||||
|
||||
class MediaAccumulator {
|
||||
public:
|
||||
public:
|
||||
MediaAccumulator(const std::string &file_name, TargetPlatform::IntType &potential_platforms) :
|
||||
file_name_(file_name), potential_platforms_(potential_platforms), extension_(get_extension(file_name)) {}
|
||||
|
||||
/// Adds @c instance to the media collection and adds @c platforms to the set of potentials.
|
||||
/// If @c instance is an @c TargetPlatform::TypeDistinguisher then it is given an opportunity to restrict the set of potentials.
|
||||
template <typename InstanceT>
|
||||
void insert(TargetPlatform::IntType platforms, std::shared_ptr<InstanceT> instance) {
|
||||
void insert(const TargetPlatform::IntType platforms, std::shared_ptr<InstanceT> instance) {
|
||||
if constexpr (std::is_base_of_v<Storage::Disk::Disk, InstanceT>) {
|
||||
media.disks.push_back(instance);
|
||||
} else if constexpr (std::is_base_of_v<Storage::Tape::Tape, InstanceT>) {
|
||||
@ -134,13 +134,13 @@ class MediaAccumulator {
|
||||
|
||||
/// Concstructs a new instance of @c InstanceT supplying @c args and adds it to the back of @c list using @c insert_instance.
|
||||
template <typename InstanceT, typename... Args>
|
||||
void insert(TargetPlatform::IntType platforms, Args &&... args) {
|
||||
void insert(const TargetPlatform::IntType platforms, Args &&... args) {
|
||||
insert(platforms, std::make_shared<InstanceT>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/// Calls @c insert with the specified parameters, ignoring any exceptions thrown.
|
||||
template <typename InstanceT, typename... Args>
|
||||
void try_insert(TargetPlatform::IntType platforms, Args &&... args) {
|
||||
void try_insert(const TargetPlatform::IntType platforms, Args &&... args) {
|
||||
try {
|
||||
insert<InstanceT>(platforms, std::forward<Args>(args)...);
|
||||
} catch(...) {}
|
||||
@ -149,22 +149,22 @@ class MediaAccumulator {
|
||||
/// Performs a @c try_insert for an object of @c InstanceT if @c extension matches that of the file name,
|
||||
/// providing the file name as the only construction argument.
|
||||
template <typename InstanceT>
|
||||
void try_standard(TargetPlatform::IntType platforms, const char *extension) {
|
||||
void try_standard(const TargetPlatform::IntType platforms, const char *extension) {
|
||||
if(name_matches(extension)) {
|
||||
try_insert<InstanceT>(platforms, file_name_);
|
||||
}
|
||||
}
|
||||
|
||||
bool name_matches(const char *extension) {
|
||||
bool name_matches(const char *const extension) {
|
||||
return extension_ == extension;
|
||||
}
|
||||
|
||||
Media media;
|
||||
|
||||
private:
|
||||
const std::string &file_name_;
|
||||
TargetPlatform::IntType &potential_platforms_;
|
||||
const std::string extension_;
|
||||
private:
|
||||
const std::string &file_name_;
|
||||
TargetPlatform::IntType &potential_platforms_;
|
||||
const std::string extension_;
|
||||
};
|
||||
|
||||
}
|
||||
@ -227,7 +227,8 @@ static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::
|
||||
|
||||
accumulator.try_standard<MassStorage::HDV>(TargetPlatform::AppleII, "hdv");
|
||||
accumulator.try_standard<Disk::DiskImageHolder<Disk::HFE>>(
|
||||
TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore | TargetPlatform::Oric | TargetPlatform::ZXSpectrum,
|
||||
TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore |
|
||||
TargetPlatform::Oric | TargetPlatform::ZXSpectrum,
|
||||
"hfe"); // TODO: switch to AllDisk once the MSX stops being so greedy.
|
||||
|
||||
accumulator.try_standard<Disk::DiskImageHolder<Disk::FAT12>>(TargetPlatform::PCCompatible, "ima");
|
||||
|
@ -28,7 +28,11 @@ static std::vector<Storage::Data::ZX8081::File> GetFiles(const std::shared_ptr<S
|
||||
return files;
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::ZX8081::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType potential_platforms) {
|
||||
Analyser::Static::TargetList Analyser::Static::ZX8081::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType potential_platforms
|
||||
) {
|
||||
TargetList destination;
|
||||
if(!media.tapes.empty()) {
|
||||
std::vector<Storage::Data::ZX8081::File> files = GetFiles(media.tapes.front());
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::ZX8081 {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
@ -103,7 +103,11 @@ bool IsSpectrumDisk(const std::shared_ptr<Storage::Disk::Disk> &disk) {
|
||||
|
||||
}
|
||||
|
||||
Analyser::Static::TargetList Analyser::Static::ZXSpectrum::GetTargets(const Media &media, const std::string &, TargetPlatform::IntType) {
|
||||
Analyser::Static::TargetList Analyser::Static::ZXSpectrum::GetTargets(
|
||||
const Media &media,
|
||||
const std::string &,
|
||||
TargetPlatform::IntType
|
||||
) {
|
||||
TargetList destination;
|
||||
auto target = std::make_unique<Target>();
|
||||
target->confidence = 0.5;
|
||||
|
@ -14,6 +14,6 @@
|
||||
|
||||
namespace Analyser::Static::ZXSpectrum {
|
||||
|
||||
TargetList GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
TargetList GetTargets(const Media &, const std::string &file_name, TargetPlatform::IntType potential_platforms);
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user