mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
Factors out commonalities in SSD/DSD and ADF implementations.
This commit is contained in:
parent
2f48ee59fa
commit
ef605eda51
@ -84,6 +84,7 @@
|
||||
4B50730A1DDFCFDF00C48FBD /* ArrayBuilderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */; };
|
||||
4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */; };
|
||||
4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */; };
|
||||
4B58601E1F806AB200AEE2E3 /* MFMSectorDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */; };
|
||||
4B59199C1DAC6C46005BB85C /* OricTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B59199A1DAC6C46005BB85C /* OricTAP.cpp */; };
|
||||
4B5A12571DD55862007A2231 /* Disassembler6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A12551DD55862007A2231 /* Disassembler6502.cpp */; };
|
||||
4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; };
|
||||
@ -631,6 +632,8 @@
|
||||
4B55CE5B1C3B7D6F0093A61B /* CSOpenGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSOpenGLView.h; sourceTree = "<group>"; };
|
||||
4B55CE5C1C3B7D6F0093A61B /* CSOpenGLView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSOpenGLView.m; sourceTree = "<group>"; };
|
||||
4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachineDocument.swift; sourceTree = "<group>"; };
|
||||
4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MFMSectorDump.cpp; sourceTree = "<group>"; };
|
||||
4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MFMSectorDump.hpp; sourceTree = "<group>"; };
|
||||
4B59199A1DAC6C46005BB85C /* OricTAP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OricTAP.cpp; sourceTree = "<group>"; };
|
||||
4B59199B1DAC6C46005BB85C /* OricTAP.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OricTAP.hpp; sourceTree = "<group>"; };
|
||||
4B5A12551DD55862007A2231 /* Disassembler6502.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disassembler6502.cpp; path = ../../StaticAnalyser/Disassembler/Disassembler6502.cpp; sourceTree = "<group>"; };
|
||||
@ -1472,7 +1475,6 @@
|
||||
4B45188C1F75FD1B00926311 /* Formats */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BFDD7891F7F2DB4008579B9 /* Utility */,
|
||||
4B45188D1F75FD1B00926311 /* AcornADF.cpp */,
|
||||
4B45188E1F75FD1B00926311 /* AcornADF.hpp */,
|
||||
4B45188F1F75FD1B00926311 /* CPCDSK.cpp */,
|
||||
@ -1483,10 +1485,13 @@
|
||||
4B4518941F75FD1B00926311 /* G64.hpp */,
|
||||
4B4518951F75FD1B00926311 /* HFE.cpp */,
|
||||
4B4518961F75FD1B00926311 /* HFE.hpp */,
|
||||
4B58601C1F806AB200AEE2E3 /* MFMSectorDump.cpp */,
|
||||
4B58601D1F806AB200AEE2E3 /* MFMSectorDump.hpp */,
|
||||
4B4518971F75FD1B00926311 /* OricMFMDSK.cpp */,
|
||||
4B4518981F75FD1B00926311 /* OricMFMDSK.hpp */,
|
||||
4B4518991F75FD1B00926311 /* SSD.cpp */,
|
||||
4B45189A1F75FD1B00926311 /* SSD.hpp */,
|
||||
4BFDD7891F7F2DB4008579B9 /* Utility */,
|
||||
);
|
||||
path = Formats;
|
||||
sourceTree = "<group>";
|
||||
@ -2463,8 +2468,8 @@
|
||||
4BFDD7891F7F2DB4008579B9 /* Utility */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BFDD78A1F7F2DB4008579B9 /* ImplicitSectors.hpp */,
|
||||
4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */,
|
||||
4BFDD78A1F7F2DB4008579B9 /* ImplicitSectors.hpp */,
|
||||
);
|
||||
path = Utility;
|
||||
sourceTree = "<group>";
|
||||
@ -2898,6 +2903,7 @@
|
||||
4B59199C1DAC6C46005BB85C /* OricTAP.cpp in Sources */,
|
||||
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,
|
||||
4B7136861F78724F008B8ED9 /* Encoder.cpp in Sources */,
|
||||
4B58601E1F806AB200AEE2E3 /* MFMSectorDump.cpp in Sources */,
|
||||
4B448E841F1C4C480009ABD6 /* PulseQueuedTape.cpp in Sources */,
|
||||
4BD14B111D74627C0088EAD6 /* StaticAnalyser.cpp in Sources */,
|
||||
4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */,
|
||||
|
@ -12,18 +12,16 @@
|
||||
|
||||
namespace {
|
||||
static const unsigned int sectors_per_track = 16;
|
||||
static const size_t bytes_per_sector = 256;
|
||||
static const unsigned int sector_size = 1;
|
||||
}
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
AcornADF::AcornADF(const char *file_name) :
|
||||
Storage::FileHolder(file_name) {
|
||||
AcornADF::AcornADF(const char *file_name) : MFMSectorDump(file_name) {
|
||||
// very loose validation: the file needs to be a multiple of 256 bytes
|
||||
// and not ungainly large
|
||||
if(file_stats_.st_size % (off_t)bytes_per_sector) throw ErrorNotAcornADF;
|
||||
if(file_stats_.st_size < 7 * (off_t)bytes_per_sector) throw ErrorNotAcornADF;
|
||||
if(file_stats_.st_size % (off_t)(128 << sector_size)) throw ErrorNotAcornADF;
|
||||
if(file_stats_.st_size < 7 * (off_t)(128 << sector_size)) throw ErrorNotAcornADF;
|
||||
|
||||
// check that the initial directory's 'Hugo's are present
|
||||
fseek(file_, 513, SEEK_SET);
|
||||
@ -34,6 +32,8 @@ AcornADF::AcornADF(const char *file_name) :
|
||||
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;
|
||||
|
||||
set_geometry(sectors_per_track, sector_size, true);
|
||||
}
|
||||
|
||||
unsigned int AcornADF::get_head_position_count() {
|
||||
@ -44,37 +44,6 @@ unsigned int AcornADF::get_head_count() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool AcornADF::get_is_read_only() {
|
||||
return is_read_only_;
|
||||
}
|
||||
|
||||
long AcornADF::get_file_offset_for_position(unsigned int head, unsigned int position) {
|
||||
return (position * 1 + head) * bytes_per_sector * sectors_per_track;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> AcornADF::get_track_at_position(unsigned int head, unsigned int position) {
|
||||
uint8_t sectors[bytes_per_sector*sectors_per_track];
|
||||
|
||||
if(head > 1) return nullptr;
|
||||
long file_offset = get_file_offset_for_position(head, position);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
|
||||
fseek(file_, file_offset, SEEK_SET);
|
||||
fread(sectors, 1, sizeof(sectors), file_);
|
||||
}
|
||||
|
||||
return track_for_sectors(sectors, (uint8_t)position, (uint8_t)head, 0, sector_size, true);
|
||||
}
|
||||
|
||||
void AcornADF::set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track) {
|
||||
uint8_t parsed_track[bytes_per_sector*sectors_per_track];
|
||||
decode_sectors(*track, parsed_track, 0, sectors_per_track-1, sector_size, true);
|
||||
|
||||
long file_offset = get_file_offset_for_position(head, position);
|
||||
|
||||
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
|
||||
ensure_file_is_at_least_length(file_offset);
|
||||
fseek(file_, file_offset, SEEK_SET);
|
||||
fwrite(parsed_track, 1, sizeof(parsed_track), file_);
|
||||
return (position * 1 + head) * (128 << sector_size) * sectors_per_track;
|
||||
}
|
||||
|
@ -9,8 +9,7 @@
|
||||
#ifndef AcornADF_hpp
|
||||
#define AcornADF_hpp
|
||||
|
||||
#include "../DiskImage.hpp"
|
||||
#include "../../../FileHolder.hpp"
|
||||
#include "MFMSectorDump.hpp"
|
||||
|
||||
namespace Storage {
|
||||
namespace Disk {
|
||||
@ -18,7 +17,7 @@ namespace Disk {
|
||||
/*!
|
||||
Provies a @c Disk containing an ADF disk image — a decoded sector dump of an Acorn ADFS disk.
|
||||
*/
|
||||
class AcornADF: public DiskImage, public Storage::FileHolder {
|
||||
class AcornADF: public MFMSectorDump {
|
||||
public:
|
||||
/*!
|
||||
Construct an @c AcornADF containing content from the file with name @c file_name.
|
||||
@ -34,12 +33,8 @@ class AcornADF: public DiskImage, public Storage::FileHolder {
|
||||
|
||||
unsigned int get_head_position_count();
|
||||
unsigned int get_head_count();
|
||||
bool get_is_read_only();
|
||||
void set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track);
|
||||
std::shared_ptr<Track> get_track_at_position(unsigned int head, unsigned int position);
|
||||
|
||||
private:
|
||||
std::mutex file_access_mutex_;
|
||||
long get_file_offset_for_position(unsigned int head, unsigned int position);
|
||||
};
|
||||
|
||||
|
54
Storage/Disk/DiskImage/Formats/MFMSectorDump.cpp
Normal file
54
Storage/Disk/DiskImage/Formats/MFMSectorDump.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// MFMSectorDump.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 30/09/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "MFMSectorDump.hpp"
|
||||
|
||||
#include "Utility/ImplicitSectors.hpp"
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
MFMSectorDump::MFMSectorDump(const char *file_name) : Storage::FileHolder(file_name) {}
|
||||
|
||||
void MFMSectorDump::set_geometry(int sectors_per_track, uint8_t sector_size, bool is_double_density) {
|
||||
sectors_per_track_ = sectors_per_track;
|
||||
sector_size_ = sector_size;
|
||||
is_double_density_ = is_double_density;
|
||||
}
|
||||
|
||||
bool MFMSectorDump::get_is_read_only() {
|
||||
return is_read_only_;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> MFMSectorDump::get_track_at_position(unsigned int head, unsigned int position) {
|
||||
uint8_t sectors[(128 << sector_size_)*sectors_per_track_];
|
||||
|
||||
if(head > 1) return nullptr;
|
||||
long file_offset = get_file_offset_for_position(head, position);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
|
||||
fseek(file_, file_offset, SEEK_SET);
|
||||
fread(sectors, 1, sizeof(sectors), file_);
|
||||
}
|
||||
|
||||
return track_for_sectors(sectors, (uint8_t)position, (uint8_t)head, 0, sector_size_, is_double_density_);
|
||||
}
|
||||
|
||||
void MFMSectorDump::set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track) {
|
||||
uint8_t parsed_track[(128 << sector_size_)*sectors_per_track_];
|
||||
// Assumption here: sector IDs will run from 0.
|
||||
decode_sectors(*track, parsed_track, 0, (uint8_t)(sectors_per_track_-1), sector_size_, is_double_density_);
|
||||
|
||||
long file_offset = get_file_offset_for_position(head, position);
|
||||
|
||||
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
|
||||
ensure_file_is_at_least_length(file_offset);
|
||||
fseek(file_, file_offset, SEEK_SET);
|
||||
fwrite(parsed_track, 1, sizeof(parsed_track), file_);
|
||||
fflush(file_);
|
||||
}
|
42
Storage/Disk/DiskImage/Formats/MFMSectorDump.hpp
Normal file
42
Storage/Disk/DiskImage/Formats/MFMSectorDump.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// MFMSectorDump.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 30/09/2017.
|
||||
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef SectorDump_hpp
|
||||
#define SectorDump_hpp
|
||||
|
||||
#include "../DiskImage.hpp"
|
||||
#include "../../../FileHolder.hpp"
|
||||
|
||||
namespace Storage {
|
||||
namespace Disk {
|
||||
|
||||
/*!
|
||||
Provies the base for writeable [M]FM disk images that just contain contiguous sector content dumps.
|
||||
*/
|
||||
class MFMSectorDump: public DiskImage, public Storage::FileHolder {
|
||||
public:
|
||||
MFMSectorDump(const char *file_name);
|
||||
void set_geometry(int sectors_per_track, uint8_t sector_size, bool is_double_density);
|
||||
|
||||
bool get_is_read_only();
|
||||
void set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track);
|
||||
std::shared_ptr<Track> get_track_at_position(unsigned int head, unsigned int position);
|
||||
|
||||
private:
|
||||
std::mutex file_access_mutex_;
|
||||
virtual long get_file_offset_for_position(unsigned int head, unsigned int position) = 0;
|
||||
|
||||
int sectors_per_track_ = 0;
|
||||
uint8_t sector_size_ = 0;
|
||||
bool is_double_density_ = true;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SectorDump_hpp */
|
@ -12,14 +12,12 @@
|
||||
|
||||
namespace {
|
||||
static const unsigned int sectors_per_track = 10;
|
||||
static const size_t bytes_per_sector = 256;
|
||||
static const unsigned int sector_size = 1;
|
||||
}
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
SSD::SSD(const char *file_name) :
|
||||
Storage::FileHolder(file_name) {
|
||||
SSD::SSD(const char *file_name) : MFMSectorDump(file_name) {
|
||||
// very loose validation: the file needs to be a multiple of 256 bytes
|
||||
// and not ungainly large
|
||||
|
||||
@ -32,6 +30,8 @@ SSD::SSD(const char *file_name) :
|
||||
track_count_ = (unsigned int)(file_stats_.st_size / (256 * 10));
|
||||
if(track_count_ < 40) track_count_ = 40;
|
||||
else if(track_count_ < 80) track_count_ = 80;
|
||||
|
||||
set_geometry(sectors_per_track, sector_size, false);
|
||||
}
|
||||
|
||||
unsigned int SSD::get_head_position_count() {
|
||||
@ -42,37 +42,6 @@ unsigned int SSD::get_head_count() {
|
||||
return head_count_;
|
||||
}
|
||||
|
||||
bool SSD::get_is_read_only() {
|
||||
return is_read_only_;
|
||||
}
|
||||
|
||||
long SSD::get_file_offset_for_position(unsigned int head, unsigned int position) {
|
||||
return (position * head_count_ + head) * 256 * 10;
|
||||
}
|
||||
|
||||
std::shared_ptr<Track> SSD::get_track_at_position(unsigned int head, unsigned int position) {
|
||||
uint8_t sectors[bytes_per_sector*sectors_per_track];
|
||||
|
||||
if(head >= head_count_) return nullptr;
|
||||
long file_offset = get_file_offset_for_position(head, position);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
|
||||
fseek(file_, file_offset, SEEK_SET);
|
||||
fread(sectors, 1, sizeof(sectors), file_);
|
||||
}
|
||||
|
||||
return track_for_sectors(sectors, (uint8_t)position, (uint8_t)head, 0, sector_size, false);
|
||||
}
|
||||
|
||||
void SSD::set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track) {
|
||||
uint8_t parsed_track[bytes_per_sector*sectors_per_track];
|
||||
decode_sectors(*track, parsed_track, 0, sectors_per_track-1, sector_size, false);
|
||||
|
||||
long file_offset = get_file_offset_for_position(head, position);
|
||||
|
||||
std::lock_guard<std::mutex> lock_guard(file_access_mutex_);
|
||||
ensure_file_is_at_least_length(file_offset);
|
||||
fseek(file_, file_offset, SEEK_SET);
|
||||
fwrite(parsed_track, 1, sizeof(parsed_track), file_);
|
||||
}
|
||||
|
@ -9,8 +9,7 @@
|
||||
#ifndef SSD_hpp
|
||||
#define SSD_hpp
|
||||
|
||||
#include "../DiskImage.hpp"
|
||||
#include "../../../FileHolder.hpp"
|
||||
#include "MFMSectorDump.hpp"
|
||||
|
||||
namespace Storage {
|
||||
namespace Disk {
|
||||
@ -18,7 +17,7 @@ namespace Disk {
|
||||
/*!
|
||||
Provies a @c Disk containing a DSD or SSD disk image — a decoded sector dump of an Acorn DFS disk.
|
||||
*/
|
||||
class SSD: public DiskImage, public Storage::FileHolder {
|
||||
class SSD: public MFMSectorDump {
|
||||
public:
|
||||
/*!
|
||||
Construct an @c SSD containing content from the file with name @c file_name.
|
||||
@ -32,15 +31,10 @@ class SSD: public DiskImage, public Storage::FileHolder {
|
||||
ErrorNotSSD,
|
||||
};
|
||||
|
||||
// implemented to satisfy @c Disk
|
||||
unsigned int get_head_position_count();
|
||||
unsigned int get_head_count();
|
||||
bool get_is_read_only();
|
||||
void set_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr<Track> &track);
|
||||
std::shared_ptr<Track> get_track_at_position(unsigned int head, unsigned int position);
|
||||
|
||||
private:
|
||||
std::mutex file_access_mutex_;
|
||||
long get_file_offset_for_position(unsigned int head, unsigned int position);
|
||||
|
||||
unsigned int head_count_;
|
||||
|
Loading…
Reference in New Issue
Block a user