mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Adds a genuine attempt to discern Pravetz disks from Apple.
This commit is contained in:
parent
ba7fbc4032
commit
3e0055737e
@ -7,16 +7,48 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "StaticAnalyser.hpp"
|
#include "StaticAnalyser.hpp"
|
||||||
|
|
||||||
#include "../AppleII/Target.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/Track/TrackSerialiser.hpp"
|
||||||
#include "../../../Storage/Disk/Encodings/AppleGCR/SegmentParser.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) {
|
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.
|
// This analyser can comprehend disks only.
|
||||||
if(media.disks.empty()) return {};
|
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 track_zero = media.disks.front()->get_track_at_position(Storage::Disk::Track::Address(0, 0));
|
||||||
auto sector_map = Storage::Encodings::AppleGCR::sectors_from_segment(
|
auto sector_map = Storage::Encodings::AppleGCR::sectors_from_segment(
|
||||||
Storage::Disk::track_serialisation(*track_zero, Storage::Time(1, 50000)));
|
Storage::Disk::track_serialisation(*track_zero, Storage::Time(1, 50000)));
|
||||||
@ -29,14 +61,63 @@ Analyser::Static::TargetList Analyser::Static::DiskII::GetTargets(const Media &m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using Target = Analyser::Static::AppleII::Target;
|
// If there's no boot sector then if there are also no sectors at all,
|
||||||
auto target = std::unique_ptr<Target>(new Target);
|
// decline to nominate a machine. Otherwise go with an Apple as the default.
|
||||||
target->machine = Machine::AppleII;
|
|
||||||
target->media = media;
|
|
||||||
|
|
||||||
target->disk_controller = Target::DiskController::SixteenSector;
|
|
||||||
|
|
||||||
TargetList targets;
|
TargetList targets;
|
||||||
targets.push_back(std::move(target));
|
if(!sector_zero) {
|
||||||
|
if(sector_map.empty()) {
|
||||||
|
return targets;
|
||||||
|
} else {
|
||||||
|
targets.push_back(std::unique_ptr<Analyser::Static::Target>(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<Analyser::Static::Target>(OricTarget(sector_zero)));
|
||||||
|
} else {
|
||||||
|
targets.push_back(std::unique_ptr<Analyser::Static::Target>(AppleTarget(sector_zero)));
|
||||||
|
}
|
||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user