1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-27 16:31:31 +00:00

Factors out commonalities in SSD/DSD and ADF implementations.

This commit is contained in:
Thomas Harte 2017-09-30 20:30:15 -04:00
parent 2f48ee59fa
commit ef605eda51
7 changed files with 117 additions and 88 deletions

View File

@ -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 */,

View File

@ -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;
}

View File

@ -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);
};

View 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_);
}

View 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 */

View File

@ -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_);
}

View 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_;