1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00
CLK/Storage/Tape/Parsers/Spectrum.hpp
2021-03-07 20:49:09 -05:00

125 lines
2.6 KiB
C++

//
// Spectrum.hpp
// Clock Signal
//
// Created by Thomas Harte on 07/03/2021.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#ifndef Storage_Tape_Parsers_Spectrum_hpp
#define Storage_Tape_Parsers_Spectrum_hpp
#include "TapeParser.hpp"
#include <optional>
namespace Storage {
namespace Tape {
namespace ZXSpectrum {
enum class WaveType {
// All references to 't-states' below are cycles relative to the
// ZX Spectrum's 3.5Mhz processor.
Pilot, // Nominally 2168 t-states.
Sync1, // 667 t-states.
Sync2, // 735 t-states.
Zero, // 855 t-states.
One, // 1710 t-states.
Gap,
};
enum class SymbolType {
Pilot,
Sync,
Zero,
One,
Gap,
};
struct Header {
uint8_t type = 0;
char name[11]{}; // 10 bytes on tape; always given a NULL terminator in this code.
uint16_t data_length = 0;
uint16_t parameters[2] = {0, 0};
enum class Type {
Program = 0,
NumberArray = 1,
CharacterArray = 2,
Code = 3,
Unknown
};
Type decoded_type() {
if(type > 3) return Type::Unknown;
return Type(type);
}
struct BasicParameters {
std::optional<uint16_t> autostart_line_number;
uint16_t start_of_variable_area;
};
BasicParameters basic_parameters() {
const BasicParameters params = {
.autostart_line_number = parameters[0] < 32768 ? std::make_optional(parameters[0]) : std::nullopt,
.start_of_variable_area = parameters[1]
};
return params;
}
struct CodeParameters {
uint16_t start_address;
};
CodeParameters code_parameters() {
const CodeParameters params = {
.start_address = parameters[0]
};
return params;
}
struct DataParameters {
char name;
enum class Type {
Numeric,
String
} type;
};
DataParameters data_parameters() {
#if TARGET_RT_BIG_ENDIAN
const uint8_t data_name = uint8_t(parameters[0]);
#else
const uint8_t data_name = uint8_t(parameters[0] >> 8);
#endif
using Type = DataParameters::Type;
const DataParameters params = {
.name = char((data_name & 0x1f) + 'a'),
.type = (data_name & 0x40) ? Type::String : Type::Numeric
};
return params;
}
};
class Parser: public Storage::Tape::PulseClassificationParser<WaveType, SymbolType> {
public:
/*!
Finds the next header from the tape, if any.
*/
std::optional<Header> find_header(const std::shared_ptr<Storage::Tape::Tape> &tape);
void reset_checksum();
std::optional<uint8_t> get_byte(const std::shared_ptr<Storage::Tape::Tape> &tape);
private:
void process_pulse(const Storage::Tape::Tape::Pulse &pulse) override;
void inspect_waves(const std::vector<WaveType> &waves) override;
uint8_t checksum_ = 0;
};
}
}
}
#endif /* Spectrum_hpp */