From ec3cccbb0df2942fd3fa8b7e697f3474c354255f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 20 Feb 2016 22:03:14 -0500 Subject: [PATCH] Working towards HQ UEF support: fixed bug whereby writing to tape output would reset input pulse stepper; added support for chunk 0116 and approximate support for 0113. --- Machines/Electron/Electron.cpp | 10 +++---- Machines/Electron/Electron.hpp | 3 +- Storage/Tape/Formats/TapeUEF.cpp | 47 ++++++++++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index c74948a41..607cc262d 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -690,9 +690,9 @@ inline void Tape::get_next_tape_pulse() { _time_into_pulse = 0; _current_pulse = _tape->get_next_pulse(); - if(_pulse_stepper == nullptr || _current_pulse.length.clock_rate != _pulse_stepper->get_output_rate()) + if(_input_pulse_stepper == nullptr || _current_pulse.length.clock_rate != _input_pulse_stepper->get_output_rate()) { - _pulse_stepper = std::unique_ptr(new SignalProcessing::Stepper(_current_pulse.length.clock_rate, 2000000)); + _input_pulse_stepper = std::unique_ptr(new SignalProcessing::Stepper(_current_pulse.length.clock_rate, 2000000)); } } @@ -762,7 +762,7 @@ inline void Tape::set_is_in_input_mode(bool is_in_input_mode) inline void Tape::set_counter(uint8_t value) { - _pulse_stepper = std::unique_ptr(new SignalProcessing::Stepper(1200, 2000000)); + _output_pulse_stepper = std::unique_ptr(new SignalProcessing::Stepper(1200, 2000000)); } inline void Tape::set_data_register(uint8_t value) @@ -786,7 +786,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles) { while(number_of_cycles--) { - _time_into_pulse += (unsigned int)_pulse_stepper->step(); + _time_into_pulse += (unsigned int)_input_pulse_stepper->step(); if(_time_into_pulse == _current_pulse.length.length) { get_next_tape_pulse(); @@ -826,7 +826,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles) { while(number_of_cycles--) { - if(_pulse_stepper->step()) + if(_output_pulse_stepper->step()) { _output_bits_remaining--; if(!_output_bits_remaining) diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index d9bca2785..e9fb3c1d0 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -91,7 +91,8 @@ class Tape { std::shared_ptr _tape; Storage::Tape::Pulse _current_pulse; - std::unique_ptr _pulse_stepper; + std::unique_ptr _input_pulse_stepper; + std::unique_ptr _output_pulse_stepper; uint32_t _time_into_pulse; bool _is_running; diff --git a/Storage/Tape/Formats/TapeUEF.cpp b/Storage/Tape/Formats/TapeUEF.cpp index ba6d4b6de..6796fa5ce 100644 --- a/Storage/Tape/Formats/TapeUEF.cpp +++ b/Storage/Tape/Formats/TapeUEF.cpp @@ -8,6 +8,38 @@ #include "TapeUEF.hpp" #include +#include + +static float gzgetfloat(gzFile file) +{ + uint8_t bytes[4]; + bytes[0] = (uint8_t)gzgetc(file); + bytes[1] = (uint8_t)gzgetc(file); + bytes[2] = (uint8_t)gzgetc(file); + bytes[3] = (uint8_t)gzgetc(file); + + /* assume a four byte array named Float exists, where Float[0] + was the first byte read from the UEF, Float[1] the second, etc */ + + /* decode mantissa */ + int mantissa; + mantissa = bytes[0] | (bytes[1] << 8) | ((bytes[2]&0x7f)|0x80) << 16; + + float result = (float)mantissa; + result = (float)ldexp(result, -23); + + /* decode exponent */ + int exponent; + exponent = ((bytes[2]&0x80) >> 7) | (bytes[3]&0x7f) << 1; + exponent -= 127; + result = (float)ldexp(result, exponent); + + /* flip sign if necessary */ + if(bytes[3]&0x80) + result = -result; + + return result; +} Storage::UEF::UEF(const char *file_name) : _chunk_id(0), _chunk_length(0), _chunk_position(0), @@ -117,18 +149,24 @@ void Storage::UEF::find_next_tape_chunk() continue; } + printf("Deal with %04x?\n", _chunk_id); switch(_chunk_id) { case 0x0100: case 0x0102: // implicit and explicit bit patterns return; - case 0x0112: + case 0x0112: // integer gap _chunk_duration.length = (uint16_t)gzgetc(_file); _chunk_duration.length |= (uint16_t)(gzgetc(_file) << 8); _chunk_duration.clock_rate = _time_base; return; - case 0x0116: // gaps + case 0x0116: // floating point gap + { + float length = gzgetfloat(_file); + _chunk_duration.length = (unsigned int)(length * 4000000); + _chunk_duration.clock_rate = 4000000; + } return; case 0x0110: // carrier tone @@ -144,6 +182,11 @@ void Storage::UEF::find_next_tape_chunk() break; case 0x113: // change of base rate + { + // TODO: something smarter than just converting this to an int + float new_time_base = gzgetfloat(_file); + _time_base = (unsigned int)roundf(new_time_base); + } break; default: