From 3e0055737e6f8701425ca8e946387f6beac5eb76 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 5 May 2018 19:32:08 -0400 Subject: [PATCH] Adds a genuine attempt to discern Pravetz disks from Apple. --- Analyser/Static/DiskII/StaticAnalyser.cpp | 99 ++++++++++++++++++++--- 1 file changed, 90 insertions(+), 9 deletions(-) diff --git a/Analyser/Static/DiskII/StaticAnalyser.cpp b/Analyser/Static/DiskII/StaticAnalyser.cpp index 2c0cc8aef..c60dfde4f 100644 --- a/Analyser/Static/DiskII/StaticAnalyser.cpp +++ b/Analyser/Static/DiskII/StaticAnalyser.cpp @@ -7,16 +7,48 @@ // #include "StaticAnalyser.hpp" + #include "../AppleII/Target.hpp" +#include "../Oric/Target.hpp" +#include "../Disassembler/6502.hpp" +#include "../Disassembler/AddressMapper.hpp" #include "../../../Storage/Disk/Track/TrackSerialiser.hpp" #include "../../../Storage/Disk/Encodings/AppleGCR/SegmentParser.hpp" +namespace { + +Analyser::Static::Target *AppleTarget(const Storage::Encodings::AppleGCR::Sector *sector_zero) { + using Target = Analyser::Static::AppleII::Target; + auto *target = new Target; + target->machine = Analyser::Machine::AppleII; + + if(sector_zero && sector_zero->encoding == Storage::Encodings::AppleGCR::Sector::Encoding::FiveAndThree) { + target->disk_controller = Target::DiskController::ThirteenSector; + } else { + target->disk_controller = Target::DiskController::SixteenSector; + } + + return target; +} + +Analyser::Static::Target *OricTarget(const Storage::Encodings::AppleGCR::Sector *sector_zero) { + using Target = Analyser::Static::Oric::Target; + auto *target = new Target; + target->machine = Analyser::Machine::Oric; + + // TODO: configure the Oric as a Pravetz 8D with 8DOS. + + return target; +} + +} + Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) { // This analyser can comprehend disks only. if(media.disks.empty()) return {}; - // Grab track 0, sector 0. + // Grab track 0, sector 0: the boot sector. auto track_zero = media.disks.front()->get_track_at_position(Storage::Disk::Track::Address(0, 0)); auto sector_map = Storage::Encodings::AppleGCR::sectors_from_segment( Storage::Disk::track_serialisation(*track_zero, Storage::Time(1, 50000))); @@ -28,15 +60,64 @@ Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &m break; } } - - using Target = Analyser::Static::AppleII::Target; - auto target = std::unique_ptr(new Target); - target->machine = Machine::AppleII; - target->media = media; - - target->disk_controller = Target::DiskController::SixteenSector; + // If there's no boot sector then if there are also no sectors at all, + // decline to nominate a machine. Otherwise go with an Apple as the default. TargetList targets; - targets.push_back(std::move(target)); + if(!sector_zero) { + if(sector_map.empty()) { + return targets; + } else { + targets.push_back(std::unique_ptr(AppleTarget(nullptr))); + return targets; + } + } + + // If the boot sector looks like it's intended for the Oric, create an Oric. + // Otherwise go with the Apple II. + + 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; + + // Look for a tight BPL loop reading the Oric's shift register address of 0x31c. The Apple II just has RAM there, + // so the probability of such a loop is infinitesimal. + for(const auto &instruction: disassembly.instructions_by_address) { + // Is this a read of the shift register? + if( + ( + (instruction.second.operation == Analyser::Static::MOS6502::Instruction::LDA) || + (instruction.second.operation == Analyser::Static::MOS6502::Instruction::LDX) || + (instruction.second.operation == Analyser::Static::MOS6502::Instruction::LDY) + ) && + instruction.second.addressing_mode == Analyser::Static::MOS6502::Instruction::Absolute && + instruction.second.address == 0x031c) { + did_read_shift_register = true; + continue; + } + + if(did_read_shift_register) { + if( + instruction.second.operation == Analyser::Static::MOS6502::Instruction::BPL && + instruction.second.address == 0xfb) { + is_oric = true; + break; + } + + did_read_shift_register = false; + } + } + + // Check also for calls into the 0x3xx page above 0x320, as that's where the Oric's boot ROM is. + for(const auto address: disassembly.outward_calls) { + is_oric |= address >= 0x320 && address < 0x400; + } + + if(is_oric) { + targets.push_back(std::unique_ptr(OricTarget(sector_zero))); + } else { + targets.push_back(std::unique_ptr(AppleTarget(sector_zero))); + } return targets; }