mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-07 12:54:34 +00:00
Merge pull request #211 from TomHarte/HFE
Introduces support for the HFE file format.
This commit is contained in:
commit
5bdd24d93f
@ -442,6 +442,7 @@
|
|||||||
4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295B1D8F048B001BAE39 /* MFM.cpp */; };
|
4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295B1D8F048B001BAE39 /* MFM.cpp */; };
|
||||||
4BF829631D8F536B001BAE39 /* SSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829611D8F536B001BAE39 /* SSD.cpp */; };
|
4BF829631D8F536B001BAE39 /* SSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829611D8F536B001BAE39 /* SSD.cpp */; };
|
||||||
4BF829661D8F732B001BAE39 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829641D8F732B001BAE39 /* Disk.cpp */; };
|
4BF829661D8F732B001BAE39 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829641D8F732B001BAE39 /* Disk.cpp */; };
|
||||||
|
4BFB9FAE1F467D3A00960122 /* HFE.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFB9FAC1F467D3A00960122 /* HFE.cpp */; };
|
||||||
4BFCA1201ECBDC1500AC40C1 /* Z80AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.cpp */; };
|
4BFCA1201ECBDC1500AC40C1 /* Z80AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.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 */; };
|
||||||
@ -1067,6 +1068,8 @@
|
|||||||
4BF829641D8F732B001BAE39 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disk.cpp; path = ../../StaticAnalyser/Acorn/Disk.cpp; sourceTree = "<group>"; };
|
4BF829641D8F732B001BAE39 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disk.cpp; path = ../../StaticAnalyser/Acorn/Disk.cpp; sourceTree = "<group>"; };
|
||||||
4BF829651D8F732B001BAE39 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Disk.hpp; path = ../../StaticAnalyser/Acorn/Disk.hpp; sourceTree = "<group>"; };
|
4BF829651D8F732B001BAE39 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Disk.hpp; path = ../../StaticAnalyser/Acorn/Disk.hpp; sourceTree = "<group>"; };
|
||||||
4BF829681D8F7361001BAE39 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Acorn/File.hpp; sourceTree = "<group>"; };
|
4BF829681D8F7361001BAE39 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Acorn/File.hpp; sourceTree = "<group>"; };
|
||||||
|
4BFB9FAC1F467D3A00960122 /* HFE.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HFE.cpp; sourceTree = "<group>"; };
|
||||||
|
4BFB9FAD1F467D3A00960122 /* HFE.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = HFE.hpp; sourceTree = "<group>"; };
|
||||||
4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80AllRAM.cpp; path = Z80/Z80AllRAM.cpp; sourceTree = "<group>"; };
|
4BFCA11D1ECBD9BD00AC40C1 /* Z80AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Z80AllRAM.cpp; path = Z80/Z80AllRAM.cpp; sourceTree = "<group>"; };
|
||||||
4BFCA11E1ECBD9BD00AC40C1 /* Z80AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80AllRAM.hpp; path = Z80/Z80AllRAM.hpp; sourceTree = "<group>"; };
|
4BFCA11E1ECBD9BD00AC40C1 /* Z80AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80AllRAM.hpp; path = Z80/Z80AllRAM.hpp; sourceTree = "<group>"; };
|
||||||
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AllRAMProcessor.cpp; sourceTree = "<group>"; };
|
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AllRAMProcessor.cpp; sourceTree = "<group>"; };
|
||||||
@ -1587,6 +1590,8 @@
|
|||||||
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
||||||
4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */,
|
4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */,
|
||||||
4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */,
|
4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */,
|
||||||
|
4BFB9FAC1F467D3A00960122 /* HFE.cpp */,
|
||||||
|
4BFB9FAD1F467D3A00960122 /* HFE.hpp */,
|
||||||
);
|
);
|
||||||
path = Formats;
|
path = Formats;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2819,6 +2824,7 @@
|
|||||||
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */,
|
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */,
|
||||||
4B37EE821D7345A6006A09A4 /* BinaryDump.cpp in Sources */,
|
4B37EE821D7345A6006A09A4 /* BinaryDump.cpp in Sources */,
|
||||||
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */,
|
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */,
|
||||||
|
4BFB9FAE1F467D3A00960122 /* HFE.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -245,6 +245,22 @@
|
|||||||
<key>NSDocumentClass</key>
|
<key>NSDocumentClass</key>
|
||||||
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
|
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>hfe</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeIconFile</key>
|
||||||
|
<string>floppy35</string>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>HxC Disk Image</string>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>LSTypeIsPackage</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
<key>NSDocumentClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "../Storage/Disk/Formats/CPCDSK.hpp"
|
#include "../Storage/Disk/Formats/CPCDSK.hpp"
|
||||||
#include "../Storage/Disk/Formats/D64.hpp"
|
#include "../Storage/Disk/Formats/D64.hpp"
|
||||||
#include "../Storage/Disk/Formats/G64.hpp"
|
#include "../Storage/Disk/Formats/G64.hpp"
|
||||||
|
#include "../Storage/Disk/Formats/HFE.hpp"
|
||||||
#include "../Storage/Disk/Formats/OricMFMDSK.hpp"
|
#include "../Storage/Disk/Formats/OricMFMDSK.hpp"
|
||||||
#include "../Storage/Disk/Formats/SSD.hpp"
|
#include "../Storage/Disk/Formats/SSD.hpp"
|
||||||
|
|
||||||
@ -48,7 +49,8 @@ enum class TargetPlatform: TargetPlatformType {
|
|||||||
Oric = 1 << 4,
|
Oric = 1 << 4,
|
||||||
ZX8081 = 1 << 5,
|
ZX8081 = 1 << 5,
|
||||||
|
|
||||||
AllTape = Acorn | Commodore | Oric | ZX8081 | AmstradCPC,
|
AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX8081,
|
||||||
|
AllDisk = Acorn | AmstradCPC | Commodore | Oric,
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace StaticAnalyser;
|
using namespace StaticAnalyser;
|
||||||
@ -95,6 +97,7 @@ static Media GetMediaAndPlatforms(const char *file_name, TargetPlatformType &pot
|
|||||||
Format("dsk", result.disks, Disk::CPCDSK, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC)
|
Format("dsk", result.disks, Disk::CPCDSK, TargetPlatform::AmstradCPC) // DSK (Amstrad CPC)
|
||||||
Format("dsk", result.disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric)
|
Format("dsk", result.disks, Disk::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric)
|
||||||
Format("g64", result.disks, Disk::G64, TargetPlatform::Commodore) // G64
|
Format("g64", result.disks, Disk::G64, TargetPlatform::Commodore) // G64
|
||||||
|
Format("hfe", result.disks, Disk::HFE, TargetPlatform::AmstradCPC) // HFE (TODO: plus other target platforms)
|
||||||
Format("o", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O
|
Format("o", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // O
|
||||||
Format("p", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
Format("p", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
||||||
Format("p81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P81
|
Format("p81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P81
|
||||||
|
86
Storage/Disk/Formats/HFE.cpp
Normal file
86
Storage/Disk/Formats/HFE.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// HFE.cpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 17/08/2017.
|
||||||
|
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "HFE.hpp"
|
||||||
|
|
||||||
|
#include "../PCMTrack.hpp"
|
||||||
|
|
||||||
|
using namespace Storage::Disk;
|
||||||
|
|
||||||
|
HFE::HFE(const char *file_name) :
|
||||||
|
Storage::FileHolder(file_name) {
|
||||||
|
if(!check_signature("HXCPICFE", 8)) throw ErrorNotHFE;
|
||||||
|
|
||||||
|
if(fgetc(file_)) throw ErrorNotHFE;
|
||||||
|
track_count_ = (unsigned int)fgetc(file_);
|
||||||
|
head_count_ = (unsigned int)fgetc(file_);
|
||||||
|
|
||||||
|
fseek(file_, 7, SEEK_CUR);
|
||||||
|
track_list_offset_ = (long)fgetc16le() << 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
HFE::~HFE() {
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int HFE::get_head_position_count() {
|
||||||
|
return track_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int HFE::get_head_count() {
|
||||||
|
return head_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HFE::get_is_read_only() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Track> HFE::get_uncached_track_at_position(unsigned int head, unsigned int position) {
|
||||||
|
// Get track position and length from the lookup table; data is then always interleaved
|
||||||
|
// based on an assumption of two heads.
|
||||||
|
fseek(file_, track_list_offset_ + position * 4, SEEK_SET);
|
||||||
|
|
||||||
|
long track_offset = (long)fgetc16le() << 9;
|
||||||
|
uint16_t track_length = fgetc16le();
|
||||||
|
|
||||||
|
fseek(file_, track_offset, SEEK_SET);
|
||||||
|
if(head) fseek(file_, 256, SEEK_CUR);
|
||||||
|
|
||||||
|
PCMSegment segment;
|
||||||
|
uint16_t side_length = track_length / 2;
|
||||||
|
segment.data.resize(side_length);
|
||||||
|
segment.number_of_bits = side_length * 8;
|
||||||
|
|
||||||
|
uint16_t c = 0;
|
||||||
|
while(c < side_length) {
|
||||||
|
uint16_t length = (uint16_t)std::min(256, side_length - c);
|
||||||
|
fread(&segment.data[c], 1, length, file_);
|
||||||
|
c += length;
|
||||||
|
fseek(file_, 256, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flip bytes; HFE's preference is that the least-significant bit
|
||||||
|
// is serialised first, but PCMTrack posts the most-significant first.
|
||||||
|
for(size_t i = 0; i < segment.data.size(); i++) {
|
||||||
|
uint8_t original = segment.data[i];
|
||||||
|
uint8_t flipped_byte =
|
||||||
|
(uint8_t)(
|
||||||
|
((original & 0x01) << 7) |
|
||||||
|
((original & 0x02) << 5) |
|
||||||
|
((original & 0x04) << 3) |
|
||||||
|
((original & 0x08) << 1) |
|
||||||
|
((original & 0x10) >> 1) |
|
||||||
|
((original & 0x20) >> 3) |
|
||||||
|
((original & 0x40) >> 5) |
|
||||||
|
((original & 0x80) >> 7)
|
||||||
|
);
|
||||||
|
segment.data[i] = flipped_byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Track> track(new PCMTrack(segment));
|
||||||
|
return track;
|
||||||
|
}
|
53
Storage/Disk/Formats/HFE.hpp
Normal file
53
Storage/Disk/Formats/HFE.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// HFE.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 17/08/2017.
|
||||||
|
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef HFE_hpp
|
||||||
|
#define HFE_hpp
|
||||||
|
|
||||||
|
#include "../Disk.hpp"
|
||||||
|
#include "../../FileHolder.hpp"
|
||||||
|
|
||||||
|
namespace Storage {
|
||||||
|
namespace Disk {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Provies a @c Disk containing an HFE disk image — a bit stream representation of a floppy.
|
||||||
|
*/
|
||||||
|
class HFE: public Disk, public Storage::FileHolder {
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
Construct an @c SSD containing content from the file with name @c file_name.
|
||||||
|
|
||||||
|
@throws ErrorCantOpen if this file can't be opened.
|
||||||
|
@throws ErrorNotSSD if the file doesn't appear to contain a .SSD format image.
|
||||||
|
*/
|
||||||
|
HFE(const char *file_name);
|
||||||
|
~HFE();
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ErrorNotHFE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// implemented to satisfy @c Disk
|
||||||
|
unsigned int get_head_position_count();
|
||||||
|
unsigned int get_head_count();
|
||||||
|
bool get_is_read_only();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Track> get_uncached_track_at_position(unsigned int head, unsigned int position);
|
||||||
|
|
||||||
|
unsigned int head_count_;
|
||||||
|
unsigned int track_count_;
|
||||||
|
long track_list_offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HFE_hpp */
|
Loading…
Reference in New Issue
Block a user