mirror of
https://github.com/TomHarte/CLK.git
synced 2025-05-16 14:38:15 +00:00
Merge pull request #225 from TomHarte/TargetHints
Factors the concept of a target platform out from the static analyser, allowing file formats to opine
This commit is contained in:
commit
b4c532c0d5
@ -1060,6 +1060,7 @@
|
|||||||
4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLLTests.swift; sourceTree = "<group>"; };
|
4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DPLLTests.swift; sourceTree = "<group>"; };
|
||||||
4BF1354A1D6D2C300054B2EA /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StaticAnalyser.cpp; path = ../../StaticAnalyser/StaticAnalyser.cpp; sourceTree = "<group>"; };
|
4BF1354A1D6D2C300054B2EA /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StaticAnalyser.cpp; path = ../../StaticAnalyser/StaticAnalyser.cpp; sourceTree = "<group>"; };
|
||||||
4BF1354B1D6D2C300054B2EA /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StaticAnalyser.hpp; path = ../../StaticAnalyser/StaticAnalyser.hpp; sourceTree = "<group>"; };
|
4BF1354B1D6D2C300054B2EA /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StaticAnalyser.hpp; path = ../../StaticAnalyser/StaticAnalyser.hpp; sourceTree = "<group>"; };
|
||||||
|
4BF4A2D91F534DB300B171F4 /* TargetPlatforms.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TargetPlatforms.hpp; sourceTree = "<group>"; };
|
||||||
4BF6606A1F281573002CB053 /* ClockReceiver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClockReceiver.hpp; sourceTree = "<group>"; };
|
4BF6606A1F281573002CB053 /* ClockReceiver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClockReceiver.hpp; sourceTree = "<group>"; };
|
||||||
4BF8295B1D8F048B001BAE39 /* MFM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MFM.cpp; path = Encodings/MFM.cpp; sourceTree = "<group>"; };
|
4BF8295B1D8F048B001BAE39 /* MFM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MFM.cpp; path = Encodings/MFM.cpp; sourceTree = "<group>"; };
|
||||||
4BF8295C1D8F048B001BAE39 /* MFM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MFM.hpp; path = Encodings/MFM.hpp; sourceTree = "<group>"; };
|
4BF8295C1D8F048B001BAE39 /* MFM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MFM.hpp; path = Encodings/MFM.hpp; sourceTree = "<group>"; };
|
||||||
@ -1457,6 +1458,7 @@
|
|||||||
4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */,
|
4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */,
|
||||||
4B5FADB91DE3151600AEC565 /* FileHolder.hpp */,
|
4B5FADB91DE3151600AEC565 /* FileHolder.hpp */,
|
||||||
4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */,
|
4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */,
|
||||||
|
4BF4A2D91F534DB300B171F4 /* TargetPlatforms.hpp */,
|
||||||
4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */,
|
4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */,
|
||||||
4BEE0A691D72496600532C7B /* Cartridge */,
|
4BEE0A691D72496600532C7B /* Cartridge */,
|
||||||
4B8805F81DCFF6CD003085B1 /* Data */,
|
4B8805F81DCFF6CD003085B1 /* Data */,
|
||||||
|
@ -40,22 +40,12 @@
|
|||||||
#include "../Storage/Tape/Formats/TZX.hpp"
|
#include "../Storage/Tape/Formats/TZX.hpp"
|
||||||
#include "../Storage/Tape/Formats/ZX80O81P.hpp"
|
#include "../Storage/Tape/Formats/ZX80O81P.hpp"
|
||||||
|
|
||||||
typedef int TargetPlatformType;
|
// Target Platform Types
|
||||||
enum class TargetPlatform: TargetPlatformType {
|
#include "../Storage/TargetPlatforms.hpp"
|
||||||
Acorn = 1 << 0,
|
|
||||||
AmstradCPC = 1 << 1,
|
|
||||||
Atari2600 = 1 << 2,
|
|
||||||
Commodore = 1 << 3,
|
|
||||||
Oric = 1 << 4,
|
|
||||||
ZX8081 = 1 << 5,
|
|
||||||
|
|
||||||
AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX8081,
|
|
||||||
AllDisk = Acorn | AmstradCPC | Commodore | Oric,
|
|
||||||
};
|
|
||||||
|
|
||||||
using namespace StaticAnalyser;
|
using namespace StaticAnalyser;
|
||||||
|
|
||||||
static Media GetMediaAndPlatforms(const char *file_name, TargetPlatformType &potential_platforms) {
|
static Media GetMediaAndPlatforms(const char *file_name, TargetPlatform::IntType &potential_platforms) {
|
||||||
// Get the extension, if any; it will be assumed that extensions are reliable, so an extension is a broad-phase
|
// Get the extension, if any; it will be assumed that extensions are reliable, so an extension is a broad-phase
|
||||||
// test as to file format.
|
// test as to file format.
|
||||||
const char *mixed_case_extension = strrchr(file_name, '.');
|
const char *mixed_case_extension = strrchr(file_name, '.');
|
||||||
@ -72,7 +62,9 @@ static Media GetMediaAndPlatforms(const char *file_name, TargetPlatformType &pot
|
|||||||
Media result;
|
Media result;
|
||||||
#define Insert(list, class, platforms) \
|
#define Insert(list, class, platforms) \
|
||||||
list.emplace_back(new Storage::class(file_name));\
|
list.emplace_back(new Storage::class(file_name));\
|
||||||
potential_platforms |= (TargetPlatformType)(platforms);\
|
potential_platforms |= platforms;\
|
||||||
|
TargetPlatform::TypeDistinguisher *distinguisher = dynamic_cast<TargetPlatform::TypeDistinguisher *>(list.back().get());\
|
||||||
|
if(distinguisher) potential_platforms &= distinguisher->target_platform_type();
|
||||||
|
|
||||||
#define TryInsert(list, class, platforms) \
|
#define TryInsert(list, class, platforms) \
|
||||||
try {\
|
try {\
|
||||||
@ -125,6 +117,8 @@ static Media GetMediaAndPlatforms(const char *file_name, TargetPlatformType &pot
|
|||||||
#undef Insert
|
#undef Insert
|
||||||
#undef TryInsert
|
#undef TryInsert
|
||||||
|
|
||||||
|
// Filter potential platforms as per file preferences, if any.
|
||||||
|
|
||||||
free(lowercase_extension);
|
free(lowercase_extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +126,7 @@ static Media GetMediaAndPlatforms(const char *file_name, TargetPlatformType &pot
|
|||||||
}
|
}
|
||||||
|
|
||||||
Media StaticAnalyser::GetMedia(const char *file_name) {
|
Media StaticAnalyser::GetMedia(const char *file_name) {
|
||||||
TargetPlatformType throwaway;
|
TargetPlatform::IntType throwaway;
|
||||||
return GetMediaAndPlatforms(file_name, throwaway);
|
return GetMediaAndPlatforms(file_name, throwaway);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,17 +135,17 @@ std::list<Target> StaticAnalyser::GetTargets(const char *file_name) {
|
|||||||
|
|
||||||
// Collect all disks, tapes and ROMs as can be extrapolated from this file, forming the
|
// Collect all disks, tapes and ROMs as can be extrapolated from this file, forming the
|
||||||
// union of all platforms this file might be a target for.
|
// union of all platforms this file might be a target for.
|
||||||
TargetPlatformType potential_platforms = 0;
|
TargetPlatform::IntType potential_platforms = 0;
|
||||||
Media media = GetMediaAndPlatforms(file_name, potential_platforms);
|
Media media = GetMediaAndPlatforms(file_name, potential_platforms);
|
||||||
|
|
||||||
// Hand off to platform-specific determination of whether these things are actually compatible and,
|
// Hand off to platform-specific determination of whether these things are actually compatible and,
|
||||||
// if so, how to load them.
|
// if so, how to load them.
|
||||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Acorn) Acorn::AddTargets(media, targets);
|
if(potential_platforms & TargetPlatform::Acorn) Acorn::AddTargets(media, targets);
|
||||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::AmstradCPC) AmstradCPC::AddTargets(media, targets);
|
if(potential_platforms & TargetPlatform::AmstradCPC) AmstradCPC::AddTargets(media, targets);
|
||||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Atari2600) Atari::AddTargets(media, targets);
|
if(potential_platforms & TargetPlatform::Atari2600) Atari::AddTargets(media, targets);
|
||||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Commodore) Commodore::AddTargets(media, targets);
|
if(potential_platforms & TargetPlatform::Commodore) Commodore::AddTargets(media, targets);
|
||||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::Oric) Oric::AddTargets(media, targets);
|
if(potential_platforms & TargetPlatform::Oric) Oric::AddTargets(media, targets);
|
||||||
if(potential_platforms & (TargetPlatformType)TargetPlatform::ZX8081) ZX8081::AddTargets(media, targets);
|
if(potential_platforms & TargetPlatform::ZX8081) ZX8081::AddTargets(media, targets, potential_platforms);
|
||||||
|
|
||||||
// Reset any tapes to their initial position
|
// Reset any tapes to their initial position
|
||||||
for(auto target : targets) {
|
for(auto target : targets) {
|
||||||
|
@ -27,14 +27,24 @@ static std::vector<Storage::Data::ZX8081::File> GetFiles(const std::shared_ptr<S
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StaticAnalyser::ZX8081::AddTargets(const Media &media, std::list<Target> &destination) {
|
void StaticAnalyser::ZX8081::AddTargets(const Media &media, std::list<Target> &destination, TargetPlatform::IntType potential_platforms) {
|
||||||
if(!media.tapes.empty()) {
|
if(!media.tapes.empty()) {
|
||||||
std::vector<Storage::Data::ZX8081::File> files = GetFiles(media.tapes.front());
|
std::vector<Storage::Data::ZX8081::File> files = GetFiles(media.tapes.front());
|
||||||
media.tapes.front()->reset();
|
media.tapes.front()->reset();
|
||||||
if(!files.empty()) {
|
if(!files.empty()) {
|
||||||
StaticAnalyser::Target target;
|
StaticAnalyser::Target target;
|
||||||
target.machine = Target::ZX8081;
|
target.machine = Target::ZX8081;
|
||||||
target.zx8081.isZX81 = files.front().isZX81;
|
|
||||||
|
// Guess the machine type from the file only if it isn't already known.
|
||||||
|
switch(potential_platforms & (TargetPlatform::ZX80 | TargetPlatform::ZX81)) {
|
||||||
|
default:
|
||||||
|
target.zx8081.isZX81 = files.front().isZX81;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TargetPlatform::ZX80: target.zx8081.isZX81 = false; break;
|
||||||
|
case TargetPlatform::ZX81: target.zx8081.isZX81 = true; break;
|
||||||
|
}
|
||||||
|
|
||||||
/*if(files.front().data.size() > 16384) {
|
/*if(files.front().data.size() > 16384) {
|
||||||
target.zx8081.memory_model = ZX8081MemoryModel::SixtyFourKB;
|
target.zx8081.memory_model = ZX8081MemoryModel::SixtyFourKB;
|
||||||
} else*/ if(files.front().data.size() > 1024) {
|
} else*/ if(files.front().data.size() > 1024) {
|
||||||
|
@ -10,11 +10,12 @@
|
|||||||
#define StaticAnalyser_ZX8081_StaticAnalyser_hpp
|
#define StaticAnalyser_ZX8081_StaticAnalyser_hpp
|
||||||
|
|
||||||
#include "../StaticAnalyser.hpp"
|
#include "../StaticAnalyser.hpp"
|
||||||
|
#include "../../Storage/TargetPlatforms.hpp"
|
||||||
|
|
||||||
namespace StaticAnalyser {
|
namespace StaticAnalyser {
|
||||||
namespace ZX8081 {
|
namespace ZX8081 {
|
||||||
|
|
||||||
void AddTargets(const Media &media, std::list<Target> &destination);
|
void AddTargets(const Media &media, std::list<Target> &destination, TargetPlatform::IntType potential_platforms);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ class Cartridge {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::list<Segment> &get_segments() { return segments_; }
|
const std::list<Segment> &get_segments() { return segments_; }
|
||||||
|
virtual ~Cartridge() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::list<Segment> segments_;
|
std::list<Segment> segments_;
|
||||||
|
@ -70,7 +70,8 @@ using namespace Storage::Tape;
|
|||||||
|
|
||||||
UEF::UEF(const char *file_name) :
|
UEF::UEF(const char *file_name) :
|
||||||
time_base_(1200),
|
time_base_(1200),
|
||||||
is_300_baud_(false) {
|
is_300_baud_(false),
|
||||||
|
platform_type_(TargetPlatform::Acorn) {
|
||||||
file_ = gzopen(file_name, "rb");
|
file_ = gzopen(file_name, "rb");
|
||||||
|
|
||||||
char identifier[10];
|
char identifier[10];
|
||||||
@ -85,10 +86,11 @@ UEF::UEF(const char *file_name) :
|
|||||||
if(version[1] > 0 || version[0] > 10) {
|
if(version[1] > 0 || version[0] > 10) {
|
||||||
throw ErrorNotUEF;
|
throw ErrorNotUEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_platform_type();
|
||||||
}
|
}
|
||||||
|
|
||||||
UEF::~UEF()
|
UEF::~UEF() {
|
||||||
{
|
|
||||||
gzclose(file_);
|
gzclose(file_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,31 +104,42 @@ void UEF::virtual_reset() {
|
|||||||
|
|
||||||
#pragma mark - Chunk navigator
|
#pragma mark - Chunk navigator
|
||||||
|
|
||||||
|
bool UEF::get_next_chunk(UEF::Chunk &result) {
|
||||||
|
uint16_t chunk_id = (uint16_t)gzget16(file_);
|
||||||
|
uint32_t chunk_length = (uint32_t)gzget32(file_);
|
||||||
|
z_off_t start_of_next_chunk = gztell(file_) + chunk_length;
|
||||||
|
|
||||||
|
if(gzeof(file_)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.id = chunk_id;
|
||||||
|
result.length = chunk_length;
|
||||||
|
result.start_of_next_chunk = start_of_next_chunk;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void UEF::get_next_pulses() {
|
void UEF::get_next_pulses() {
|
||||||
while(empty()) {
|
while(empty()) {
|
||||||
// read chunk details
|
// read chunk details
|
||||||
uint16_t chunk_id = (uint16_t)gzget16(file_);
|
Chunk next_chunk;
|
||||||
uint32_t chunk_length = (uint32_t)gzget32(file_);
|
if(!get_next_chunk(next_chunk)) {
|
||||||
|
|
||||||
// figure out where the next chunk will start
|
|
||||||
z_off_t start_of_next_chunk = gztell(file_) + chunk_length;
|
|
||||||
|
|
||||||
if(gzeof(file_)) {
|
|
||||||
set_is_at_end(true);
|
set_is_at_end(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(chunk_id) {
|
switch(next_chunk.id) {
|
||||||
case 0x0100: queue_implicit_bit_pattern(chunk_length); break;
|
case 0x0100: queue_implicit_bit_pattern(next_chunk.length); break;
|
||||||
case 0x0102: queue_explicit_bit_pattern(chunk_length); break;
|
case 0x0102: queue_explicit_bit_pattern(next_chunk.length); break;
|
||||||
case 0x0112: queue_integer_gap(); break;
|
case 0x0112: queue_integer_gap(); break;
|
||||||
case 0x0116: queue_floating_point_gap(); break;
|
case 0x0116: queue_floating_point_gap(); break;
|
||||||
|
|
||||||
case 0x0110: queue_carrier_tone(); break;
|
case 0x0110: queue_carrier_tone(); break;
|
||||||
case 0x0111: queue_carrier_tone_with_dummy(); break;
|
case 0x0111: queue_carrier_tone_with_dummy(); break;
|
||||||
|
|
||||||
case 0x0114: queue_security_cycles(); break;
|
case 0x0114: queue_security_cycles(); break;
|
||||||
case 0x0104: queue_defined_data(chunk_length); break;
|
case 0x0104: queue_defined_data(next_chunk.length); break;
|
||||||
|
|
||||||
// change of base rate
|
// change of base rate
|
||||||
case 0x0113: {
|
case 0x0113: {
|
||||||
@ -143,19 +156,18 @@ void UEF::get_next_pulses() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("!!! Skipping %04x\n", chunk_id);
|
printf("!!! Skipping %04x\n", next_chunk.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gzseek(file_, start_of_next_chunk, SEEK_SET);
|
gzseek(file_, next_chunk.start_of_next_chunk, SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Chunk parsers
|
#pragma mark - Chunk parsers
|
||||||
|
|
||||||
void UEF::queue_implicit_bit_pattern(uint32_t length) {
|
void UEF::queue_implicit_bit_pattern(uint32_t length) {
|
||||||
while(length--)
|
while(length--) {
|
||||||
{
|
|
||||||
queue_implicit_byte(gzget8(file_));
|
queue_implicit_byte(gzget8(file_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,8 +175,7 @@ void UEF::queue_implicit_bit_pattern(uint32_t length) {
|
|||||||
void UEF::queue_explicit_bit_pattern(uint32_t length) {
|
void UEF::queue_explicit_bit_pattern(uint32_t length) {
|
||||||
size_t length_in_bits = (length << 3) - (size_t)gzget8(file_);
|
size_t length_in_bits = (length << 3) - (size_t)gzget8(file_);
|
||||||
uint8_t current_byte = 0;
|
uint8_t current_byte = 0;
|
||||||
for(size_t bit = 0; bit < length_in_bits; bit++)
|
for(size_t bit = 0; bit < length_in_bits; bit++) {
|
||||||
{
|
|
||||||
if(!(bit&7)) current_byte = gzget8(file_);
|
if(!(bit&7)) current_byte = gzget8(file_);
|
||||||
queue_bit(current_byte&1);
|
queue_bit(current_byte&1);
|
||||||
current_byte >>= 1;
|
current_byte >>= 1;
|
||||||
@ -303,3 +314,30 @@ void UEF::queue_bit(int bit) {
|
|||||||
emplace_back(Pulse::High, duration);
|
emplace_back(Pulse::High, duration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - TypeDistinguisher
|
||||||
|
|
||||||
|
TargetPlatform::Type UEF::target_platform_type() {
|
||||||
|
return platform_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UEF::set_platform_type() {
|
||||||
|
// If a chunk of type 0005 exists anywhere in the UEF then the UEF specifies its target machine.
|
||||||
|
// So check and, if so, update the list of machines for which this file thinks it is suitable.
|
||||||
|
Chunk next_chunk;
|
||||||
|
while(get_next_chunk(next_chunk)) {
|
||||||
|
if(next_chunk.id == 0x0005) {
|
||||||
|
uint8_t target = gzget8(file_);
|
||||||
|
switch(target >> 4) {
|
||||||
|
case 0: platform_type_ = TargetPlatform::BBCModelA; break;
|
||||||
|
case 1: platform_type_ = TargetPlatform::AcornElectron; break;
|
||||||
|
case 2: platform_type_ = TargetPlatform::BBCModelB; break;
|
||||||
|
case 3: platform_type_ = TargetPlatform::BBCMaster; break;
|
||||||
|
case 4: platform_type_ = TargetPlatform::AcornAtom; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gzseek(file_, next_chunk.start_of_next_chunk, SEEK_SET);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
#define TapeUEF_hpp
|
#define TapeUEF_hpp
|
||||||
|
|
||||||
#include "../PulseQueuedTape.hpp"
|
#include "../PulseQueuedTape.hpp"
|
||||||
|
|
||||||
|
#include "../../TargetPlatforms.hpp"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Storage {
|
namespace Storage {
|
||||||
namespace Tape {
|
namespace Tape {
|
||||||
@ -20,7 +22,7 @@ namespace Tape {
|
|||||||
/*!
|
/*!
|
||||||
Provides a @c Tape containing a UEF tape image, a slightly-convoluted description of pulses.
|
Provides a @c Tape containing a UEF tape image, a slightly-convoluted description of pulses.
|
||||||
*/
|
*/
|
||||||
class UEF : public PulseQueuedTape {
|
class UEF : public PulseQueuedTape, public TargetPlatform::TypeDistinguisher {
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
Constructs a @c UEF containing content from the file with name @c file_name.
|
Constructs a @c UEF containing content from the file with name @c file_name.
|
||||||
@ -37,10 +39,21 @@ class UEF : public PulseQueuedTape {
|
|||||||
private:
|
private:
|
||||||
void virtual_reset();
|
void virtual_reset();
|
||||||
|
|
||||||
|
void set_platform_type();
|
||||||
|
TargetPlatform::Type target_platform_type();
|
||||||
|
TargetPlatform::Type platform_type_;
|
||||||
|
|
||||||
gzFile file_;
|
gzFile file_;
|
||||||
unsigned int time_base_;
|
unsigned int time_base_;
|
||||||
bool is_300_baud_;
|
bool is_300_baud_;
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
uint16_t id;
|
||||||
|
uint32_t length;
|
||||||
|
z_off_t start_of_next_chunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool get_next_chunk(Chunk &);
|
||||||
void get_next_pulses();
|
void get_next_pulses();
|
||||||
|
|
||||||
void queue_implicit_bit_pattern(uint32_t length);
|
void queue_implicit_bit_pattern(uint32_t length);
|
||||||
|
@ -20,9 +20,11 @@ ZX80O81P::ZX80O81P(const char *file_name) :
|
|||||||
|
|
||||||
// If it's a ZX81 file, prepend a file name.
|
// If it's a ZX81 file, prepend a file name.
|
||||||
std::string type = extension();
|
std::string type = extension();
|
||||||
|
platform_type_ = TargetPlatform::ZX80;
|
||||||
if(type == "p" || type == "81") {
|
if(type == "p" || type == "81") {
|
||||||
// TODO, maybe: prefix a proper file name; this is leaving the file nameless.
|
// TODO, maybe: prefix a proper file name; this is leaving the file nameless.
|
||||||
data_.insert(data_.begin(), 0x80);
|
data_.insert(data_.begin(), 0x80);
|
||||||
|
platform_type_ = TargetPlatform::ZX81;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<::Storage::Data::ZX8081::File> file = Storage::Data::ZX8081::FileFromData(data_);
|
std::shared_ptr<::Storage::Data::ZX8081::File> file = Storage::Data::ZX8081::FileFromData(data_);
|
||||||
@ -100,3 +102,7 @@ Tape::Pulse ZX80O81P::virtual_get_next_pulse() {
|
|||||||
|
|
||||||
return pulse;
|
return pulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TargetPlatform::Type ZX80O81P::target_platform_type() {
|
||||||
|
return platform_type_;
|
||||||
|
}
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
#define ZX80O81P_hpp
|
#define ZX80O81P_hpp
|
||||||
|
|
||||||
#include "../Tape.hpp"
|
#include "../Tape.hpp"
|
||||||
|
|
||||||
#include "../../FileHolder.hpp"
|
#include "../../FileHolder.hpp"
|
||||||
|
#include "../../TargetPlatforms.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -21,7 +23,7 @@ namespace Tape {
|
|||||||
/*!
|
/*!
|
||||||
Provides a @c Tape containing a ZX80-format .O tape image, which is a byte stream capture.
|
Provides a @c Tape containing a ZX80-format .O tape image, which is a byte stream capture.
|
||||||
*/
|
*/
|
||||||
class ZX80O81P: public Tape, public Storage::FileHolder {
|
class ZX80O81P: public Tape, public Storage::FileHolder, public TargetPlatform::TypeDistinguisher {
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
Constructs a @c ZX80O containing content from the file with name @c file_name.
|
Constructs a @c ZX80O containing content from the file with name @c file_name.
|
||||||
@ -34,10 +36,14 @@ class ZX80O81P: public Tape, public Storage::FileHolder {
|
|||||||
ErrorNotZX80O81P
|
ErrorNotZX80O81P
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
// implemented to satisfy @c Tape
|
// implemented to satisfy @c Tape
|
||||||
bool is_at_end();
|
bool is_at_end();
|
||||||
|
|
||||||
private:
|
// implemented to satisfy TargetPlatform::TypeDistinguisher
|
||||||
|
TargetPlatform::Type target_platform_type();
|
||||||
|
TargetPlatform::Type platform_type_;
|
||||||
|
|
||||||
void virtual_reset();
|
void virtual_reset();
|
||||||
Pulse virtual_get_next_pulse();
|
Pulse virtual_get_next_pulse();
|
||||||
bool has_finished_data();
|
bool has_finished_data();
|
||||||
|
41
Storage/TargetPlatforms.hpp
Normal file
41
Storage/TargetPlatforms.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// TargetPlatforms.h
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 27/08/2017.
|
||||||
|
// Copyright © 2017 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TargetPlatforms_hpp
|
||||||
|
#define TargetPlatforms_hpp
|
||||||
|
|
||||||
|
namespace TargetPlatform {
|
||||||
|
|
||||||
|
typedef int IntType;
|
||||||
|
enum Type: IntType {
|
||||||
|
AmstradCPC = 1 << 1,
|
||||||
|
Atari2600 = 1 << 2,
|
||||||
|
AcornAtom = 1 << 3,
|
||||||
|
AcornElectron = 1 << 4,
|
||||||
|
BBCMaster = 1 << 5,
|
||||||
|
BBCModelA = 1 << 6,
|
||||||
|
BBCModelB = 1 << 7,
|
||||||
|
Commodore = 1 << 8,
|
||||||
|
Oric = 1 << 9,
|
||||||
|
ZX80 = 1 << 10,
|
||||||
|
ZX81 = 1 << 11,
|
||||||
|
|
||||||
|
Acorn = AcornAtom | AcornElectron | BBCMaster | BBCModelA | BBCModelB,
|
||||||
|
ZX8081 = ZX80 | ZX81,
|
||||||
|
AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX80 | ZX81,
|
||||||
|
AllDisk = Acorn | AmstradCPC | Commodore | Oric,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TypeDistinguisher {
|
||||||
|
public:
|
||||||
|
virtual Type target_platform_type() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TargetPlatforms_h */
|
Loading…
x
Reference in New Issue
Block a user