From d1ef2f7c6302f2fbecc9bdaf1369cc37f3c08a5e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 6 Nov 2016 19:22:09 -0500 Subject: [PATCH] Made an attempt to consolidate what I learnt of Oric encoding while building this hastily and untidily directly into the Oric implementation. (while adding support for the slow tape encoding mode) --- .../Clock Signal.xcodeproj/project.pbxproj | 6 ++ Storage/Tape/Parsers/Oric.cpp | 80 +++++++++++++++++++ Storage/Tape/Parsers/Oric.hpp | 44 ++++++++++ 3 files changed, 130 insertions(+) create mode 100644 Storage/Tape/Parsers/Oric.cpp create mode 100644 Storage/Tape/Parsers/Oric.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index ad79b4962..b28985d17 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -59,6 +59,7 @@ 4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */; }; 4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F21DCFD22A003085B1 /* Commodore.cpp */; }; 4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F51DCFF6C9003085B1 /* Commodore.cpp */; }; + 4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F91DCFF807003085B1 /* Oric.cpp */; }; 4B8FE21B1DA19D5F0090D3CE /* Atari2600Options.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B8FE2131DA19D5F0090D3CE /* Atari2600Options.xib */; }; 4B8FE21C1DA19D5F0090D3CE /* MachineDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B8FE2151DA19D5F0090D3CE /* MachineDocument.xib */; }; 4B8FE21D1DA19D5F0090D3CE /* ElectronOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B8FE2171DA19D5F0090D3CE /* ElectronOptions.xib */; }; @@ -505,6 +506,8 @@ 4B8805F31DCFD22A003085B1 /* Commodore.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Commodore.hpp; path = Parsers/Commodore.hpp; sourceTree = ""; }; 4B8805F51DCFF6C9003085B1 /* Commodore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Commodore.cpp; path = Data/Commodore.cpp; sourceTree = ""; }; 4B8805F61DCFF6C9003085B1 /* Commodore.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Commodore.hpp; path = Data/Commodore.hpp; sourceTree = ""; }; + 4B8805F91DCFF807003085B1 /* Oric.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Oric.cpp; path = Parsers/Oric.cpp; sourceTree = ""; }; + 4B8805FA1DCFF807003085B1 /* Oric.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Oric.hpp; path = Parsers/Oric.hpp; sourceTree = ""; }; 4B8E4ECD1DCE483D003716C3 /* KeyboardMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = KeyboardMachine.hpp; sourceTree = ""; }; 4B8FE2141DA19D5F0090D3CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Atari2600Options.xib"; sourceTree = SOURCE_ROOT; }; 4B8FE2161DA19D5F0090D3CE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/MachineDocument.xib"; sourceTree = SOURCE_ROOT; }; @@ -1205,6 +1208,8 @@ 4B8805EF1DCFC99C003085B1 /* Acorn.hpp */, 4B8805F21DCFD22A003085B1 /* Commodore.cpp */, 4B8805F31DCFD22A003085B1 /* Commodore.hpp */, + 4B8805F91DCFF807003085B1 /* Oric.cpp */, + 4B8805FA1DCFF807003085B1 /* Oric.hpp */, ); name = Parsers; sourceTree = ""; @@ -2330,6 +2335,7 @@ 4B4C83701D4F623200CD541F /* D64.cpp in Sources */, 4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */, 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, + 4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */, 4BEE0A701D72496600532C7B /* PRG.cpp in Sources */, 4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */, 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */, diff --git a/Storage/Tape/Parsers/Oric.cpp b/Storage/Tape/Parsers/Oric.cpp new file mode 100644 index 000000000..722d7b175 --- /dev/null +++ b/Storage/Tape/Parsers/Oric.cpp @@ -0,0 +1,80 @@ +// +// Oric.cpp +// Clock Signal +// +// Created by Thomas Harte on 06/11/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Oric.hpp" + +using namespace Storage::Tape::Oric; + +int Parser::get_next_byte(const std::shared_ptr &tape, bool use_fast_encoding) +{ + _use_fast_encoding = use_fast_encoding; + _cycle_length = 0.0f; + + int result = 0; + int bit_count = 0; + while(bit_count < 10 && !tape->is_at_end()) + { + SymbolType symbol = get_next_symbol(tape); + if(!bit_count && symbol != SymbolType::Zero) continue; + result |= ((symbol == SymbolType::One) ? 1 : 0) << bit_count; + bit_count++; + } + // TODO: check parity + return tape->is_at_end() ? -1 : (result >> 1); +} + +void Parser::process_pulse(Storage::Tape::Tape::Pulse pulse) +{ + const float length_threshold = 0.0003125f; + + bool wave_is_high = pulse.type == Storage::Tape::Tape::Pulse::High; + bool did_change = (wave_is_high != _wave_was_high && _cycle_length > 0.0f); + _cycle_length += pulse.length.get_float(); + if(did_change) + { + if(_cycle_length > 2.0 * length_threshold) push_wave(WaveType::Unrecognised); + else push_wave(_cycle_length < length_threshold ? WaveType::Short : WaveType::Long); + + _cycle_length = 0.0f; + _wave_was_high = wave_is_high; + } +} + +void Parser::inspect_waves(const std::vector &waves) +{ + if(_use_fast_encoding) + { + if(waves.size() < 2) return; + if(waves[0] == WaveType::Long && waves[1] != WaveType::Unrecognised) + { + push_symbol((waves[1] == WaveType::Long) ? SymbolType::Zero : SymbolType::One, 2); + return; + } + } + else + { + if(waves.size() < 16) return; +#define CHECK_RUN(length, type, symbol) \ + if(waves.size() >= length)\ + {\ + size_t c;\ + for(c = 0; c < length; c++) if(waves[c] != type) break;\ + if(c == length)\ + {\ + push_symbol(symbol, 8);\ + return;\ + }\ + } + + CHECK_RUN(8, WaveType::Long, SymbolType::Zero); + CHECK_RUN(16, WaveType::Short, SymbolType::One); +#undef CHECK_RUN + } + + remove_waves(1); +} diff --git a/Storage/Tape/Parsers/Oric.hpp b/Storage/Tape/Parsers/Oric.hpp new file mode 100644 index 000000000..7dae3ca67 --- /dev/null +++ b/Storage/Tape/Parsers/Oric.hpp @@ -0,0 +1,44 @@ +// +// Oric.hpp +// Clock Signal +// +// Created by Thomas Harte on 06/11/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Storage_Tape_Parsers_Oric_hpp +#define Storage_Tape_Parsers_Oric_hpp + +#include "TapeParser.hpp" + +namespace Storage { +namespace Tape { +namespace Oric { + +enum class WaveType { + Short, Long, Unrecognised +}; + +enum class SymbolType { + One, Zero +}; + +class Parser: public Storage::Tape::Parser { + public: + int get_next_byte(const std::shared_ptr &tape, bool use_fast_encoding); + + private: + void process_pulse(Storage::Tape::Tape::Pulse pulse); + void inspect_waves(const std::vector &waves); + + bool _use_fast_encoding; + bool _wave_was_high; + float _cycle_length; +}; + + +} +} +} + +#endif /* Oric_hpp */