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

Extends UEF support to include chunk 0005, the target platform description, which is exposed via TargetPlatform::TypeDistinguisher.

This commit is contained in:
Thomas Harte 2017-08-27 15:43:09 -04:00
parent 63ee8c9d58
commit a3e2d142e3
4 changed files with 94 additions and 37 deletions

View File

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

View File

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

View File

@ -10,6 +10,7 @@
#define ZX80O81P_hpp #define ZX80O81P_hpp
#include "../Tape.hpp" #include "../Tape.hpp"
#include "../../FileHolder.hpp" #include "../../FileHolder.hpp"
#include "../../TargetPlatforms.hpp" #include "../../TargetPlatforms.hpp"

View File

@ -13,17 +13,22 @@ namespace TargetPlatform {
typedef int IntType; typedef int IntType;
enum Type: IntType { enum Type: IntType {
Acorn = 1 << 0, AmstradCPC = 1 << 1,
AmstradCPC = 1 << 1, Atari2600 = 1 << 2,
Atari2600 = 1 << 2, AcornAtom = 1 << 3,
Commodore = 1 << 3, AcornElectron = 1 << 4,
Oric = 1 << 4, BBCMaster = 1 << 5,
ZX80 = 1 << 5, BBCModelA = 1 << 6,
ZX81 = 1 << 6, BBCModelB = 1 << 7,
Commodore = 1 << 8,
Oric = 1 << 9,
ZX80 = 1 << 10,
ZX81 = 1 << 11,
ZX8081 = ZX80 | ZX81, Acorn = AcornAtom | AcornElectron | BBCMaster | BBCModelA | BBCModelB,
AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX80 | ZX81, ZX8081 = ZX80 | ZX81,
AllDisk = Acorn | AmstradCPC | Commodore | Oric, AllTape = Acorn | AmstradCPC | Commodore | Oric | ZX80 | ZX81,
AllDisk = Acorn | AmstradCPC | Commodore | Oric,
}; };
class TypeDistinguisher { class TypeDistinguisher {