mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-15 14:27:29 +00:00
Makes first attempt at 6 and 2 decoder.
This commit is contained in:
@@ -9,14 +9,24 @@
|
|||||||
#include "StaticAnalyser.hpp"
|
#include "StaticAnalyser.hpp"
|
||||||
#include "../AppleII/Target.hpp"
|
#include "../AppleII/Target.hpp"
|
||||||
|
|
||||||
|
#include "../../../Storage/Disk/Track/TrackSerialiser.hpp"
|
||||||
|
#include "../../../Storage/Disk/Encodings/AppleGCR/SegmentParser.hpp"
|
||||||
|
|
||||||
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.
|
||||||
|
if(media.disks.empty()) return {};
|
||||||
|
|
||||||
|
// Grab track 0, sector 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(
|
||||||
|
Storage::Disk::track_serialisation(*track_zero, Storage::Time(1, 50000)));
|
||||||
|
|
||||||
using Target = Analyser::Static::AppleII::Target;
|
using Target = Analyser::Static::AppleII::Target;
|
||||||
auto target = std::unique_ptr<Target>(new Target);
|
auto target = std::unique_ptr<Target>(new Target);
|
||||||
target->machine = Machine::AppleII;
|
target->machine = Machine::AppleII;
|
||||||
target->media = media;
|
target->media = media;
|
||||||
|
|
||||||
if(!target->media.disks.empty())
|
target->disk_controller = Target::DiskController::SixteenSector;
|
||||||
target->disk_controller = Target::DiskController::SixteenSector;
|
|
||||||
|
|
||||||
TargetList targets;
|
TargetList targets;
|
||||||
targets.push_back(std::move(target));
|
targets.push_back(std::move(target));
|
||||||
|
@@ -644,8 +644,8 @@
|
|||||||
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; };
|
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; };
|
||||||
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; };
|
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; };
|
||||||
4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */; };
|
4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */; };
|
||||||
4BF437EE209D0F7E008CBD6B /* TrackParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* TrackParser.cpp */; };
|
4BF437EE209D0F7E008CBD6B /* SegmentParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */; };
|
||||||
4BF437EF209D0F7E008CBD6B /* TrackParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* TrackParser.cpp */; };
|
4BF437EF209D0F7E008CBD6B /* SegmentParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */; };
|
||||||
4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */; };
|
4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */; };
|
||||||
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */; };
|
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */; };
|
||||||
4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BFCA1281ECBE7A700AC40C1 /* zexall.com */; };
|
4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BFCA1281ECBE7A700AC40C1 /* zexall.com */; };
|
||||||
@@ -1422,8 +1422,9 @@
|
|||||||
4BEF6AA81D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DigitalPhaseLockedLoopBridge.h; sourceTree = "<group>"; };
|
4BEF6AA81D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DigitalPhaseLockedLoopBridge.h; sourceTree = "<group>"; };
|
||||||
4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DigitalPhaseLockedLoopBridge.mm; sourceTree = "<group>"; };
|
4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DigitalPhaseLockedLoopBridge.mm; sourceTree = "<group>"; };
|
||||||
4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLLTests.swift; sourceTree = "<group>"; };
|
4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLLTests.swift; sourceTree = "<group>"; };
|
||||||
4BF437EC209D0F7E008CBD6B /* TrackParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TrackParser.cpp; sourceTree = "<group>"; };
|
4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentParser.cpp; sourceTree = "<group>"; };
|
||||||
4BF437ED209D0F7E008CBD6B /* TrackParser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TrackParser.hpp; sourceTree = "<group>"; };
|
4BF437ED209D0F7E008CBD6B /* SegmentParser.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SegmentParser.hpp; sourceTree = "<group>"; };
|
||||||
|
4BF437F0209D112F008CBD6B /* Sector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sector.hpp; sourceTree = "<group>"; };
|
||||||
4BF4A2D91F534DB300B171F4 /* TargetPlatforms.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TargetPlatforms.hpp; sourceTree = "<group>"; };
|
4BF4A2D91F534DB300B171F4 /* TargetPlatforms.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TargetPlatforms.hpp; sourceTree = "<group>"; };
|
||||||
4BF6606A1F281573002CB053 /* ClockReceiver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClockReceiver.hpp; sourceTree = "<group>"; };
|
4BF6606A1F281573002CB053 /* ClockReceiver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClockReceiver.hpp; sourceTree = "<group>"; };
|
||||||
4BF8295F1D8F3C87001BAE39 /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRC.hpp; path = ../../NumberTheory/CRC.hpp; sourceTree = "<group>"; };
|
4BF8295F1D8F3C87001BAE39 /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRC.hpp; path = ../../NumberTheory/CRC.hpp; sourceTree = "<group>"; };
|
||||||
@@ -3014,9 +3015,10 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4BD67DCE209BF27B00AB2146 /* Encoder.cpp */,
|
4BD67DCE209BF27B00AB2146 /* Encoder.cpp */,
|
||||||
|
4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */,
|
||||||
4BD67DCF209BF27B00AB2146 /* Encoder.hpp */,
|
4BD67DCF209BF27B00AB2146 /* Encoder.hpp */,
|
||||||
4BF437EC209D0F7E008CBD6B /* TrackParser.cpp */,
|
4BF437F0209D112F008CBD6B /* Sector.hpp */,
|
||||||
4BF437ED209D0F7E008CBD6B /* TrackParser.hpp */,
|
4BF437ED209D0F7E008CBD6B /* SegmentParser.hpp */,
|
||||||
);
|
);
|
||||||
name = AppleGCR;
|
name = AppleGCR;
|
||||||
path = Encodings/AppleGCR;
|
path = Encodings/AppleGCR;
|
||||||
@@ -3629,7 +3631,7 @@
|
|||||||
4B055AEE1FAE9BBF0060FFFF /* Keyboard.cpp in Sources */,
|
4B055AEE1FAE9BBF0060FFFF /* Keyboard.cpp in Sources */,
|
||||||
4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */,
|
4B055AED1FAE9BA20060FFFF /* Z80Storage.cpp in Sources */,
|
||||||
4B1B88BC202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */,
|
4B1B88BC202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */,
|
||||||
4BF437EF209D0F7E008CBD6B /* TrackParser.cpp in Sources */,
|
4BF437EF209D0F7E008CBD6B /* SegmentParser.cpp in Sources */,
|
||||||
4B055AD11FAE9B030060FFFF /* Video.cpp in Sources */,
|
4B055AD11FAE9B030060FFFF /* Video.cpp in Sources */,
|
||||||
4B055AA21FAE85DA0060FFFF /* SSD.cpp in Sources */,
|
4B055AA21FAE85DA0060FFFF /* SSD.cpp in Sources */,
|
||||||
4BEBFB4E2002C4BF000708CC /* MSXDSK.cpp in Sources */,
|
4BEBFB4E2002C4BF000708CC /* MSXDSK.cpp in Sources */,
|
||||||
@@ -3872,7 +3874,7 @@
|
|||||||
4B54C0C81F8D91E50050900F /* Keyboard.cpp in Sources */,
|
4B54C0C81F8D91E50050900F /* Keyboard.cpp in Sources */,
|
||||||
4B79A5011FC913C900EEDAD5 /* MSX.cpp in Sources */,
|
4B79A5011FC913C900EEDAD5 /* MSX.cpp in Sources */,
|
||||||
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */,
|
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */,
|
||||||
4BF437EE209D0F7E008CBD6B /* TrackParser.cpp in Sources */,
|
4BF437EE209D0F7E008CBD6B /* SegmentParser.cpp in Sources */,
|
||||||
4B8334861F5DA3780097E338 /* 6502Storage.cpp in Sources */,
|
4B8334861F5DA3780097E338 /* 6502Storage.cpp in Sources */,
|
||||||
4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */,
|
4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */,
|
||||||
4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */,
|
4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */,
|
||||||
|
@@ -139,24 +139,24 @@ Storage::Disk::PCMSegment AppleGCR::six_and_two_data(const uint8_t *source) {
|
|||||||
// and combined copies of the bottom two bits of the sector
|
// and combined copies of the bottom two bits of the sector
|
||||||
// contents; the 256 bytes afterwards are the remaining
|
// contents; the 256 bytes afterwards are the remaining
|
||||||
// six bits.
|
// six bits.
|
||||||
const uint8_t bit_shuffle[] = {0, 2, 1, 3};
|
const uint8_t bit_reverse[] = {0, 2, 1, 3};
|
||||||
for(std::size_t c = 0; c < 84; ++c) {
|
for(std::size_t c = 0; c < 84; ++c) {
|
||||||
segment.data[3 + c] =
|
segment.data[3 + c] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(
|
||||||
bit_shuffle[source[c]&3] |
|
bit_reverse[source[c]&3] |
|
||||||
(bit_shuffle[source[c + 86]&3] << 2) |
|
(bit_reverse[source[c + 86]&3] << 2) |
|
||||||
(bit_shuffle[source[c + 172]&3] << 4)
|
(bit_reverse[source[c + 172]&3] << 4)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
segment.data[87] =
|
segment.data[87] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(
|
||||||
(bit_shuffle[source[84]&3] << 0) |
|
(bit_reverse[source[84]&3] << 0) |
|
||||||
(bit_shuffle[source[170]&3] << 2)
|
(bit_reverse[source[170]&3] << 2)
|
||||||
);
|
);
|
||||||
segment.data[88] =
|
segment.data[88] =
|
||||||
static_cast<uint8_t>(
|
static_cast<uint8_t>(
|
||||||
(bit_shuffle[source[85]&3] << 0) |
|
(bit_reverse[source[85]&3] << 0) |
|
||||||
(bit_shuffle[source[171]&3] << 2)
|
(bit_reverse[source[171]&3] << 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
for(std::size_t c = 0; c < 256; ++c) {
|
for(std::size_t c = 0; c < 256; ++c) {
|
||||||
|
47
Storage/Disk/Encodings/AppleGCR/Sector.hpp
Normal file
47
Storage/Disk/Encodings/AppleGCR/Sector.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// Sector.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 04/05/2018.
|
||||||
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef Sector_h
|
||||||
|
#define Sector_h
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Encodings {
|
||||||
|
namespace AppleGCR {
|
||||||
|
|
||||||
|
struct Sector {
|
||||||
|
/*!
|
||||||
|
Describes the location of a sector, implementing < to allow for use as a set key.
|
||||||
|
*/
|
||||||
|
struct Address {
|
||||||
|
uint_fast8_t volume = 0, track = 0, sector = 0;
|
||||||
|
|
||||||
|
bool operator < (const Address &rhs) const {
|
||||||
|
return ((volume << 16) | (track << 8) | sector) < ((rhs.volume << 16) | (rhs.track << 8) | rhs.sector);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Address address;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
bool has_data_checksum_error = false;
|
||||||
|
bool has_header_checksum_error = false;
|
||||||
|
|
||||||
|
enum class Encoding {
|
||||||
|
FiveAndThree, SixAndTwo
|
||||||
|
};
|
||||||
|
Encoding encoding = Encoding::SixAndTwo;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* Sector_h */
|
166
Storage/Disk/Encodings/AppleGCR/SegmentParser.cpp
Normal file
166
Storage/Disk/Encodings/AppleGCR/SegmentParser.cpp
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
//
|
||||||
|
// SegmentParser.cpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 04/05/2018.
|
||||||
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SegmentParser.hpp"
|
||||||
|
|
||||||
|
#include "Encoder.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const uint8_t six_and_two_unmapping[] = {
|
||||||
|
0x00, 0x01, 0xff, 0xff,
|
||||||
|
0x02, 0x03, 0xff, 0x04, 0x05, 0x06, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x07, 0x08, 0xff, 0xff,
|
||||||
|
0xff, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0xff, 0xff,
|
||||||
|
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0xff, 0x14,
|
||||||
|
0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0x1b, 0xff, 0x1c, 0x1d, 0x1e, 0xff, 0xff,
|
||||||
|
0xff, 0x1f, 0xff, 0xff, 0x20, 0x21, 0xff, 0x22,
|
||||||
|
0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0x29, 0x2a, 0x2b, 0xff, 0x2c,
|
||||||
|
0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0xff, 0xff,
|
||||||
|
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0xff, 0x39,
|
||||||
|
0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Storage::Encodings::AppleGCR;
|
||||||
|
|
||||||
|
std::map<std::size_t, Sector> Storage::Encodings::AppleGCR::sectors_from_segment(const Disk::PCMSegment &&segment) {
|
||||||
|
std::map<std::size_t, Sector> result;
|
||||||
|
|
||||||
|
uint_fast8_t shift_register = 0;
|
||||||
|
|
||||||
|
const std::size_t scanning_sentinel = std::numeric_limits<std::size_t>::max();
|
||||||
|
std::unique_ptr<Sector> new_sector;
|
||||||
|
std::size_t pointer = scanning_sentinel;
|
||||||
|
std::array<uint_fast8_t, 8> header{{0, 0, 0, 0, 0, 0, 0, 0}};
|
||||||
|
std::array<uint_fast8_t, 3> scanner;
|
||||||
|
|
||||||
|
for(unsigned int bit = 0; bit < segment.number_of_bits; ++bit) {
|
||||||
|
// Apple GCR parsing: bytes always have the top bit set.
|
||||||
|
shift_register = static_cast<uint_fast8_t>((shift_register << 1) | segment.bit(bit));
|
||||||
|
if(!(shift_register&0x80)) continue;
|
||||||
|
|
||||||
|
// Grab the byte.
|
||||||
|
const uint_fast8_t value = shift_register;
|
||||||
|
shift_register = 0;
|
||||||
|
|
||||||
|
if(pointer == scanning_sentinel) {
|
||||||
|
scanner[0] = scanner[1];
|
||||||
|
scanner[1] = scanner[2];
|
||||||
|
scanner[2] = value;
|
||||||
|
|
||||||
|
if(
|
||||||
|
scanner[0] == header_prologue[0] &&
|
||||||
|
scanner[1] == header_prologue[1] &&
|
||||||
|
(
|
||||||
|
scanner[2] == header_prologue[2] ||
|
||||||
|
scanner[2] == data_prologue[2]
|
||||||
|
)) {
|
||||||
|
pointer = 0;
|
||||||
|
|
||||||
|
// If this is the start of a data section, and at least
|
||||||
|
// one header has been witnessed, start a sector.
|
||||||
|
if(scanner[2] == data_prologue[2]) {
|
||||||
|
new_sector.reset(new Sector);
|
||||||
|
new_sector->data.reserve(412);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(new_sector) {
|
||||||
|
// If this is an epilogue, make sense of this whole sector;
|
||||||
|
// otherwise just keep the byte for later.
|
||||||
|
if(value == epilogue[1]) {
|
||||||
|
std::unique_ptr<Sector> sector = std::move(new_sector);
|
||||||
|
new_sector.reset();
|
||||||
|
pointer = scanning_sentinel;
|
||||||
|
|
||||||
|
// Check for an expected size; the first byte of the epilogue has been stored, so
|
||||||
|
// these numbers are one bigger than usual.
|
||||||
|
if(sector->data.size() != 412 && sector->data.size() != 344) continue;
|
||||||
|
sector->data.resize(sector->data.size() - 1);
|
||||||
|
|
||||||
|
// Check for apparent four and four encoding.
|
||||||
|
uint_fast8_t header_mask = 0xff;
|
||||||
|
for(auto c : header) header_mask &= c;
|
||||||
|
header_mask &= 0xaa;
|
||||||
|
if(header_mask != 0xaa) continue;
|
||||||
|
|
||||||
|
sector->address.volume = ((header[0] << 1) | 1) & header[1];
|
||||||
|
sector->address.track = ((header[2] << 1) | 1) & header[3];
|
||||||
|
sector->address.sector = ((header[4] << 1) | 1) & header[5];
|
||||||
|
|
||||||
|
// Check the header checksum.
|
||||||
|
uint_fast8_t checksum = ((header[6] << 1) | 1) & header[7];
|
||||||
|
if(checksum != (sector->address.volume^sector->address.track^sector->address.sector)) continue;
|
||||||
|
|
||||||
|
if(sector->data.size() == 343) {
|
||||||
|
// Unmap the sector contents as 6 and 2 data.
|
||||||
|
bool out_of_bounds = false;
|
||||||
|
for(auto &c : sector->data) {
|
||||||
|
if(c < 0x96 || six_and_two_unmapping[c - 0x96] == 0xff) {
|
||||||
|
out_of_bounds = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c = six_and_two_unmapping[c - 0x96];
|
||||||
|
}
|
||||||
|
if(out_of_bounds) continue;
|
||||||
|
|
||||||
|
// Undo the XOR step on sector contents and check that checksum.
|
||||||
|
for(std::size_t c = 1; c < sector->data.size(); ++c) {
|
||||||
|
sector->data[c] ^= sector->data[c-1];
|
||||||
|
}
|
||||||
|
if(sector->data.back()) continue;
|
||||||
|
|
||||||
|
// Having checked the checksum, remove it.
|
||||||
|
sector->data.resize(sector->data.size() - 1);
|
||||||
|
|
||||||
|
// Undo the 6 and 2 mapping.
|
||||||
|
const uint8_t bit_reverse[] = {0, 2, 1, 3};
|
||||||
|
#define unmap(byte, nibble, shift) \
|
||||||
|
sector->data[86 + byte] = static_cast<uint8_t>(\
|
||||||
|
(sector->data[86 + byte] << 2) | bit_reverse[(sector->data[nibble] >> shift)&3]);
|
||||||
|
|
||||||
|
for(std::size_t c = 0; c < 84; ++c) {
|
||||||
|
unmap(c, c, 0);
|
||||||
|
unmap(c+86, c, 2);
|
||||||
|
unmap(c+172, c, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
unmap(84, 84, 0);
|
||||||
|
unmap(170, 84, 2);
|
||||||
|
unmap(85, 85, 0);
|
||||||
|
unmap(171, 85, 2);
|
||||||
|
|
||||||
|
#undef unmap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw away the collection of two-bit chunks.
|
||||||
|
sector->data.erase(sector->data.begin(), sector->data.end() - 256);
|
||||||
|
} else {
|
||||||
|
new_sector->data.push_back(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Just capture the header in place; it'll be decoded
|
||||||
|
// once a whole sector has been read.
|
||||||
|
header[pointer] = value;
|
||||||
|
++pointer;
|
||||||
|
if(pointer == 8) {
|
||||||
|
pointer = scanning_sentinel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
30
Storage/Disk/Encodings/AppleGCR/SegmentParser.hpp
Normal file
30
Storage/Disk/Encodings/AppleGCR/SegmentParser.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// SegmentParser.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 04/05/2018.
|
||||||
|
// Copyright © 2018 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TrackParser_hpp
|
||||||
|
#define TrackParser_hpp
|
||||||
|
|
||||||
|
#include "Sector.hpp"
|
||||||
|
#include "../../Track/PCMSegment.hpp"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Encodings {
|
||||||
|
namespace AppleGCR {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Scans @c segment for all included sectors, returning a set that maps from location within
|
||||||
|
the segment (counted in bits from the beginning) to sector.
|
||||||
|
*/
|
||||||
|
std::map<std::size_t, Sector> sectors_from_segment(const Disk::PCMSegment &&segment);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TrackParser_hpp */
|
@@ -1,9 +0,0 @@
|
|||||||
//
|
|
||||||
// TrackParser.cpp
|
|
||||||
// Clock Signal
|
|
||||||
//
|
|
||||||
// Created by Thomas Harte on 04/05/2018.
|
|
||||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "TrackParser.hpp"
|
|
@@ -1,14 +0,0 @@
|
|||||||
//
|
|
||||||
// TrackParser.hpp
|
|
||||||
// Clock Signal
|
|
||||||
//
|
|
||||||
// Created by Thomas Harte on 04/05/2018.
|
|
||||||
// Copyright © 2018 Thomas Harte. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef TrackParser_hpp
|
|
||||||
#define TrackParser_hpp
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#endif /* TrackParser_hpp */
|
|
@@ -19,7 +19,8 @@ namespace MFM {
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
Scans @c segment for all included sectors, returning a set that maps from location within
|
Scans @c segment for all included sectors, returning a set that maps from location within
|
||||||
the segment (counted in bits from the beginning) to sector.
|
the segment (counted in bits from the beginning and pointing to the location the disk
|
||||||
|
had reached upon detection of the ID mark) to sector.
|
||||||
*/
|
*/
|
||||||
std::map<std::size_t, Sector> sectors_from_segment(const Disk::PCMSegment &&segment, bool is_double_density);
|
std::map<std::size_t, Sector> sectors_from_segment(const Disk::PCMSegment &&segment, bool is_double_density);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user