mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 16:31:31 +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 */; };
|
||||
4BF829631D8F536B001BAE39 /* SSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829611D8F536B001BAE39 /* SSD.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 */; };
|
||||
4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1587,6 +1590,8 @@
|
||||
4BF829621D8F536B001BAE39 /* SSD.hpp */,
|
||||
4B838F1D1F35FDCD0016B5E6 /* CPCDSK.cpp */,
|
||||
4B838F1E1F35FDCD0016B5E6 /* CPCDSK.hpp */,
|
||||
4BFB9FAC1F467D3A00960122 /* HFE.cpp */,
|
||||
4BFB9FAD1F467D3A00960122 /* HFE.hpp */,
|
||||
);
|
||||
path = Formats;
|
||||
sourceTree = "<group>";
|
||||
@ -2819,6 +2824,7 @@
|
||||
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */,
|
||||
4B37EE821D7345A6006A09A4 /* BinaryDump.cpp in Sources */,
|
||||
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */,
|
||||
4BFB9FAE1F467D3A00960122 /* HFE.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -245,6 +245,22 @@
|
||||
<key>NSDocumentClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).MachineDocument</string>
|
||||
</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>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "../Storage/Disk/Formats/CPCDSK.hpp"
|
||||
#include "../Storage/Disk/Formats/D64.hpp"
|
||||
#include "../Storage/Disk/Formats/G64.hpp"
|
||||
#include "../Storage/Disk/Formats/HFE.hpp"
|
||||
#include "../Storage/Disk/Formats/OricMFMDSK.hpp"
|
||||
#include "../Storage/Disk/Formats/SSD.hpp"
|
||||
|
||||
@ -48,7 +49,8 @@ enum class TargetPlatform: TargetPlatformType {
|
||||
Oric = 1 << 4,
|
||||
ZX8081 = 1 << 5,
|
||||
|
||||
AllTape = Acorn | Commodore | Oric | ZX8081 | AmstradCPC,
|
||||
AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX8081,
|
||||
AllDisk = Acorn | AmstradCPC | Commodore | Oric,
|
||||
};
|
||||
|
||||
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::OricMFMDSK, TargetPlatform::Oric) // DSK (Oric)
|
||||
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("p", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081) // P
|
||||
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