1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-25 18:30:21 +00:00

Made a first attempt at Acorn ADFS support plus the start of a suitable analyser.

This commit is contained in:
Thomas Harte 2016-09-25 17:46:11 -04:00
parent 6084020ab3
commit de863719d0
10 changed files with 193 additions and 21 deletions

View File

@ -350,6 +350,7 @@
4BD14B111D74627C0088EAD6 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD14B0F1D74627C0088EAD6 /* StaticAnalyser.cpp */; };
4BD468F71D8DF41D0084958B /* 1770.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD468F51D8DF41D0084958B /* 1770.cpp */; };
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; };
4BD69F941D98760000243FE1 /* AcornADF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD69F921D98760000243FE1 /* AcornADF.cpp */; };
4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE77A2C1D84ADFB00BC3827 /* File.cpp */; };
4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */; };
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; };
@ -802,6 +803,8 @@
4BD468F61D8DF41D0084958B /* 1770.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = 1770.hpp; path = 1770/1770.hpp; sourceTree = "<group>"; };
4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = "<group>"; };
4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = "<group>"; };
4BD69F921D98760000243FE1 /* AcornADF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AcornADF.cpp; sourceTree = "<group>"; };
4BD69F931D98760000243FE1 /* AcornADF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AcornADF.hpp; sourceTree = "<group>"; };
4BE77A2C1D84ADFB00BC3827 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = File.cpp; path = ../../StaticAnalyser/Commodore/File.cpp; sourceTree = "<group>"; };
4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = "<group>"; };
4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = "<group>"; };
@ -1133,6 +1136,8 @@
4B4C836F1D4F623200CD541F /* D64.hpp */,
4BF829611D8F536B001BAE39 /* SSD.cpp */,
4BF829621D8F536B001BAE39 /* SSD.hpp */,
4BD69F921D98760000243FE1 /* AcornADF.cpp */,
4BD69F931D98760000243FE1 /* AcornADF.hpp */,
);
path = Formats;
sourceTree = "<group>";
@ -2113,6 +2118,7 @@
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */,
4B96F7221D75119A0058BB2D /* Tape.cpp in Sources */,
4B0BE4281D3481E700D5256B /* DigitalPhaseLockedLoop.cpp in Sources */,
4BD69F941D98760000243FE1 /* AcornADF.cpp in Sources */,
4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */,
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */,
4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */,

View File

@ -19,7 +19,7 @@ class FMParser: public Storage::Disk::Drive {
FMParser(bool is_mfm) :
Storage::Disk::Drive(4000000, 1, 300),
crc_generator_(0x1021, 0xffff),
shift_register_(0), track_(0)
shift_register_(0), track_(0), is_mfm_(is_mfm)
{
// Make sure this drive really is at track '1'.
while(!get_is_track_zero()) step(-1);
@ -58,6 +58,7 @@ class FMParser: public Storage::Disk::Drive {
int bit_count_;
std::shared_ptr<Storage::Encodings::MFM::Sector> sector_cache_[65536];
NumberTheory::CRC16 crc_generator_;
bool is_mfm_;
void process_input_bit(int value, unsigned int cycles_since_index_hole)
{
@ -98,7 +99,18 @@ class FMParser: public Storage::Disk::Drive {
while(1)
{
run_for_cycles(1);
if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) break;
if(is_mfm_)
{
if(shift_register_ == Storage::Encodings::MFM::MFMAddressMark)
{
uint8_t mark = get_next_byte();
if(mark == Storage::Encodings::MFM::MFMIDAddressByte) break;
}
}
else
{
if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) break;
}
if(index_count_ >= 2) return nullptr;
}
@ -115,8 +127,20 @@ class FMParser: public Storage::Disk::Drive {
while(1)
{
run_for_cycles(1);
if(shift_register_ == Storage::Encodings::MFM::FMDataAddressMark) break;
if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) return nullptr;
if(is_mfm_)
{
if(shift_register_ == Storage::Encodings::MFM::MFMAddressMark)
{
uint8_t mark = get_next_byte();
if(mark == Storage::Encodings::MFM::MFMDataAddressByte) break;
if(mark == Storage::Encodings::MFM::MFMIDAddressByte) return nullptr;
}
}
else
{
if(shift_register_ == Storage::Encodings::MFM::FMDataAddressMark) break;
if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) return nullptr;
}
if(index_count_ >= 2) return nullptr;
}
@ -165,7 +189,7 @@ std::unique_ptr<Catalogue> StaticAnalyser::Acorn::GetDFSCatalogue(const std::sha
std::shared_ptr<Storage::Encodings::MFM::Sector> names = parser.get_sector(0, 0);
std::shared_ptr<Storage::Encodings::MFM::Sector> details = parser.get_sector(0, 1);
if(!names || !details) return catalogue;
if(!names || !details) return nullptr;
if(names->data.size() != 256 || details->data.size() != 256) return nullptr;
uint8_t final_file_offset = details->data[5];

View File

@ -69,6 +69,7 @@ void StaticAnalyser::Acorn::AddTargets(
target.probability = 1.0; // TODO: a proper estimation
target.acorn.has_dfs = false;
target.acorn.has_adfs = false;
target.acorn.should_hold_shift = false;
// strip out inappropriate cartridges
target.cartridges = AcornCartridgesFrom(cartridges);
@ -116,14 +117,15 @@ void StaticAnalyser::Acorn::AddTargets(
if(disks.size() > 0)
{
std::shared_ptr<Storage::Disk::Disk> disk = disks.front();
std::unique_ptr<Catalogue> catalogue = GetDFSCatalogue(disk);
if(catalogue == nullptr) catalogue = GetADFSCatalogue(disk);
if(catalogue)
std::unique_ptr<Catalogue> dfs_catalogue, adfs_catalogue;
dfs_catalogue = GetDFSCatalogue(disk);
if(dfs_catalogue == nullptr) adfs_catalogue = GetADFSCatalogue(disk);
if(dfs_catalogue || adfs_catalogue)
{
target.disks = disks;
target.acorn.has_dfs = true;
target.acorn.has_dfs = !!dfs_catalogue;
switch(catalogue->bootOption)
switch((dfs_catalogue ?: adfs_catalogue)->bootOption)
{
case Catalogue::BootOption::None: target.loadingCommand = "*CAT\n"; break;
default: target.acorn.should_hold_shift = true; break;

View File

@ -20,6 +20,7 @@
#include "../Storage/Cartridge/Formats/PRG.hpp"
// Disks
#include "../Storage/Disk/Formats/AcornADF.hpp"
#include "../Storage/Disk/Formats/D64.hpp"
#include "../Storage/Disk/Formats/G64.hpp"
#include "../Storage/Disk/Formats/SSD.hpp"
@ -80,6 +81,7 @@ std::list<Target> StaticAnalyser::GetTargets(const char *file_name)
}
Format("a26", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // A26
Format("adf", disks, Disk::AcornADF, TargetPlatform::Acorn) // ADF
Format("bin", cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600) // BIN
Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64
Format("dsd", disks, Disk::SSD, TargetPlatform::Acorn) // DSD

View File

@ -49,23 +49,23 @@ template <class T> class MFMShifter: public Shifter<T> {
}
void add_index_address_mark() {
static_cast<T *>(this)->output_short(output_ = 0x5224);
add_byte(0xfc);
static_cast<T *>(this)->output_short(output_ = MFMIndexAddressMark);
add_byte(MFMIndexAddressByte);
}
void add_ID_address_mark() {
static_cast<T *>(this)->output_short(output_ = 0x4489);
add_byte(0xfe);
static_cast<T *>(this)->output_short(output_ = MFMAddressMark);
add_byte(MFMIDAddressByte);
}
void add_data_address_mark() {
static_cast<T *>(this)->output_short(output_ = 0x4489);
add_byte(0xfb);
static_cast<T *>(this)->output_short(output_ = MFMAddressMark);
add_byte(MFMDataAddressByte);
}
void add_deleted_data_address_mark() {
static_cast<T *>(this)->output_short(output_ = 0x4489);
add_byte(0xf8);
static_cast<T *>(this)->output_short(output_ = MFMAddressMark);
add_byte(MFMDeletedDataAddressByte);
}
private:

View File

@ -22,6 +22,13 @@ const uint16_t FMIDAddressMark = 0xf57e; // data 0xfe, with clock 0xc7 => 1111
const uint16_t FMDataAddressMark = 0xf56f; // data 0xfb, with clock 0xc7 => 1111 1011 with clock 1100 0111 => 1111 0101 0110 1111
const uint16_t FMDeletedDataAddressMark = 0xf56a; // data 0xf8, with clock 0xc7 => 1111 1000 with clock 1100 0111 => 1111 0101 0110 1010
const uint16_t MFMIndexAddressMark = 0x5224;
const uint16_t MFMAddressMark = 0x4489;
const uint8_t MFMIndexAddressByte = 0xfc;
const uint8_t MFMIDAddressByte = 0xfe;
const uint8_t MFMDataAddressByte = 0xfb;
const uint8_t MFMDeletedDataAddressByte = 0xf8;
struct Sector {
uint8_t track, side, sector;

View File

@ -0,0 +1,82 @@
//
// AcornADF.cpp
// Clock Signal
//
// Created by Thomas Harte on 25/09/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "AcornADF.hpp"
#include <sys/stat.h>
#include "../Encodings/MFM.hpp"
using namespace Storage::Disk;
AcornADF::AcornADF(const char *file_name) : _file(nullptr)
{
struct stat file_stats;
stat(file_name, &file_stats);
// very loose validation: the file needs to be a multiple of 256 bytes
// and not ungainly large
if(file_stats.st_size & 255) throw ErrorNotAcornADF;
if(file_stats.st_size < 2048) throw ErrorNotAcornADF;
_file = fopen(file_name, "rb");
if(!_file) throw ErrorCantOpen;
// check that the initial directory's 'Hugo's are present
fseek(_file, 513, SEEK_SET);
uint8_t bytes[4];
fread(bytes, 1, 4, _file);
if(bytes[0] != 'H' || bytes[1] != 'u' || bytes[2] != 'g' || bytes[3] != 'o') throw ErrorNotAcornADF;
fseek(_file, 0x6fb, SEEK_SET);
fread(bytes, 1, 4, _file);
if(bytes[0] != 'H' || bytes[1] != 'u' || bytes[2] != 'g' || bytes[3] != 'o') throw ErrorNotAcornADF;
}
AcornADF::~AcornADF()
{
if(_file) fclose(_file);
}
unsigned int AcornADF::get_head_position_count()
{
return 80;
}
unsigned int AcornADF::get_head_count()
{
return 2;
}
std::shared_ptr<Track> AcornADF::get_track_at_position(unsigned int head, unsigned int position)
{
std::shared_ptr<Track> track;
if(head >= 2) return track;
long file_offset = (position * 2 + head) * 256 * 16;
fseek(_file, file_offset, SEEK_SET);
std::vector<Storage::Encodings::MFM::Sector> sectors;
for(int sector = 0; sector < 16; sector++)
{
Storage::Encodings::MFM::Sector new_sector;
new_sector.track = (uint8_t)position;
new_sector.side = 0;
new_sector.sector = (uint8_t)sector;
new_sector.data.resize(256);
fread(&new_sector.data[0], 1, 256, _file);
if(feof(_file))
break;
sectors.push_back(std::move(new_sector));
}
if(sectors.size()) return Storage::Encodings::MFM::GetMFMTrackWithSectors(sectors);
return track;
}

View File

@ -0,0 +1,48 @@
//
// AcornADF.hpp
// Clock Signal
//
// Created by Thomas Harte on 25/09/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef AcornADF_hpp
#define AcornADF_hpp
#include "../Disk.hpp"
namespace Storage {
namespace Disk {
/*!
Provies a @c Disk containing an ADF disk image a decoded sector dump of an Acorn ADFS disk.
*/
class AcornADF: public Disk {
public:
/*!
Construct an @c AcornADF containing content from the file with name @c file_name.
@throws ErrorCantOpen if this file can't be opened.
@throws ErrorNotAcornADF if the file doesn't appear to contain an Acorn .ADF format image.
*/
AcornADF(const char *file_name);
~AcornADF();
enum {
ErrorCantOpen,
ErrorNotAcornADF,
};
// implemented to satisfy @c Disk
unsigned int get_head_position_count();
unsigned int get_head_count();
std::shared_ptr<Track> get_track_at_position(unsigned int head, unsigned int position);
private:
FILE *_file;
};
}
}
#endif /* AcornADF_hpp */

View File

@ -69,7 +69,8 @@ std::shared_ptr<Track> SSD::get_track_at_position(unsigned int head, unsigned in
new_sector.data.resize(256);
fread(&new_sector.data[0], 1, 256, _file);
if(feof(_file)) break;
if(feof(_file))
break;
sectors.push_back(std::move(new_sector));
}

View File

@ -20,10 +20,10 @@ namespace Disk {
class SSD: public Disk {
public:
/*!
Construct a @c D64 containing content from the file with name @c file_name.
Construct an @c SSD containing content from the file with name @c file_name.
@throws ErrorCantOpen if this file can't be opened.
@throws ErrorNotD64 if the file doesn't appear to contain a .D64 format image.
@throws ErrorNotSSD if the file doesn't appear to contain a .SSD format image.
*/
SSD(const char *file_name);
~SSD();