mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-03 08:05:40 +00:00
109 lines
2.6 KiB
C++
109 lines
2.6 KiB
C++
//
|
|
// ZX80O.cpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 04/06/2017.
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#include "ZX80O81P.hpp"
|
|
#include "../../Data/ZX8081.hpp"
|
|
|
|
using namespace Storage::Tape;
|
|
|
|
ZX80O81P::ZX80O81P(const std::string &file_name) {
|
|
Storage::FileHolder file(file_name);
|
|
|
|
// Grab the actual file contents
|
|
data_.resize(static_cast<std::size_t>(file.stats().st_size));
|
|
file.read(data_.data(), static_cast<std::size_t>(file.stats().st_size));
|
|
|
|
// If it's a ZX81 file, prepend a file name.
|
|
std::string type = file.extension();
|
|
platform_type_ = TargetPlatform::ZX80;
|
|
if(type == "p" || type == "81") {
|
|
// TODO, maybe: prefix a proper file name; this is leaving the file nameless.
|
|
data_.insert(data_.begin(), 0x80);
|
|
platform_type_ = TargetPlatform::ZX81;
|
|
}
|
|
|
|
std::shared_ptr<::Storage::Data::ZX8081::File> zx_file = Storage::Data::ZX8081::FileFromData(data_);
|
|
if(!zx_file) throw ErrorNotZX80O81P;
|
|
|
|
// then rewind and start again
|
|
virtual_reset();
|
|
}
|
|
|
|
void ZX80O81P::virtual_reset() {
|
|
data_pointer_ = 0;
|
|
is_past_silence_ = false;
|
|
has_ended_final_byte_ = false;
|
|
is_high_ = true;
|
|
bit_pointer_ = wave_pointer_ = 0;
|
|
}
|
|
|
|
bool ZX80O81P::has_finished_data() {
|
|
return (data_pointer_ == data_.size()) && !wave_pointer_ && !bit_pointer_;
|
|
}
|
|
|
|
bool ZX80O81P::is_at_end() {
|
|
return has_finished_data() && has_ended_final_byte_;
|
|
}
|
|
|
|
Tape::Pulse ZX80O81P::virtual_get_next_pulse() {
|
|
Tape::Pulse pulse;
|
|
|
|
// Start with 1 second of silence.
|
|
if(!is_past_silence_ || has_finished_data()) {
|
|
pulse.type = Pulse::Type::Low;
|
|
pulse.length.length = 1;
|
|
pulse.length.clock_rate = 1;
|
|
is_past_silence_ = true;
|
|
has_ended_final_byte_ = has_finished_data();
|
|
return pulse;
|
|
}
|
|
|
|
// For each byte, output 8 bits and then silence.
|
|
if(!bit_pointer_ && !wave_pointer_) {
|
|
byte_ = data_[data_pointer_];
|
|
data_pointer_++;
|
|
bit_pointer_ = 0;
|
|
wave_pointer_ = 0;
|
|
}
|
|
|
|
if(!wave_pointer_) {
|
|
// post-waves silence (here actually a pre-waves silence) is 1300 microseconds
|
|
pulse.length.length = 13;
|
|
pulse.length.clock_rate = 10000;
|
|
pulse.type = Pulse::Type::Low;
|
|
|
|
wave_pointer_ ++;
|
|
} else {
|
|
// pulses are of length 150 microseconds
|
|
pulse.length.length = 3;
|
|
pulse.length.clock_rate = 20000;
|
|
|
|
if(is_high_) {
|
|
pulse.type = Pulse::Type::High;
|
|
is_high_ = false;
|
|
} else {
|
|
pulse.type = Pulse::Type::Low;
|
|
is_high_ = true;
|
|
|
|
// Bytes are stored MSB first.
|
|
int wave_count = (byte_ & (0x80 >> bit_pointer_)) ? 9 : 4;
|
|
wave_pointer_++;
|
|
if(wave_pointer_ == wave_count + 1) {
|
|
bit_pointer_ = (bit_pointer_ + 1)&7;
|
|
wave_pointer_ = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pulse;
|
|
}
|
|
|
|
TargetPlatform::Type ZX80O81P::target_platform_type() {
|
|
return platform_type_;
|
|
}
|