From 602b6a115e32efbdc84a97ea462879f3fd86095b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 22 Apr 2026 21:17:27 -0400 Subject: [PATCH] Grab full first file for analysis. --- Analyser/Static/Thomson/StaticAnalyser.cpp | 29 ++++++++--------- ClockReceiver/JustInTime.hpp | 2 +- Storage/Tape/Parsers/ThomsonMO.cpp | 38 ++++++++++++++++++++++ Storage/Tape/Parsers/ThomsonMO.hpp | 15 +++++++++ 4 files changed, 67 insertions(+), 17 deletions(-) diff --git a/Analyser/Static/Thomson/StaticAnalyser.cpp b/Analyser/Static/Thomson/StaticAnalyser.cpp index d903599e6..625ebc305 100644 --- a/Analyser/Static/Thomson/StaticAnalyser.cpp +++ b/Analyser/Static/Thomson/StaticAnalyser.cpp @@ -81,30 +81,27 @@ Analyser::Static::TargetList Analyser::Static::Thomson::GetTargets( Storage::Tape::Thomson::MO::Parser parser; auto &tape = media.tapes.front(); const auto serialiser = tape->serialiser(); - const auto first = parser.block(*serialiser); + const auto first = parser.file(*serialiser); - if(first && first->checksum_valid()) { + if(first && first->checksums_valid) { target->media.tapes = media.tapes; // Cf. https://pulkomandy.tk/wiki/doku.php?id=documentations:monitor:tape.format for leader block format; // my parser provides block type separately and length implicitly so the type at offset 0xd is at 0xb // in ->data. - static constexpr size_t TypeOffset = 0xb; - if(!first->type && first->data.size() > TypeOffset) { - const auto command = [&]() -> std::wstring { - if(!first->data[TypeOffset]) { // File type; 0 = BASIC, 1 = DATA; 2 = binary. - return L"RUN\""; - } else { - return L"LOADM\"\",,R"; - } - }; - - // TODO: determine whether BASIC 1 or BASIC 128 is appropriate. - if(DefaultMO6) { - target->loading_command = std::wstring(L"2 ") + command() + L"\n"; + const auto command = [&]() -> std::wstring { + if(!first->type) { // File type; 0 = BASIC, 1 = DATA; 2 = binary. + return L"RUN\""; } else { - target->loading_command = command() + L"\n"; + return L"LOADM\"\",,R"; } + }; + + // TODO: determine whether BASIC 1 or BASIC 128 is appropriate. + if(DefaultMO6) { + target->loading_command = std::wstring(L"2 ") + command() + L"\n"; + } else { + target->loading_command = command() + L"\n"; } } } diff --git a/ClockReceiver/JustInTime.hpp b/ClockReceiver/JustInTime.hpp index 03e1ab088..21fd56dcf 100644 --- a/ClockReceiver/JustInTime.hpp +++ b/ClockReceiver/JustInTime.hpp @@ -286,7 +286,7 @@ private: } #ifndef NDEBUG - std::atomic_flag flush_concurrency_check_{}; + std::atomic_flag flush_concurrency_check_ = ATOMIC_FLAG_INIT; #endif }; diff --git a/Storage/Tape/Parsers/ThomsonMO.cpp b/Storage/Tape/Parsers/ThomsonMO.cpp index ca0a4b420..35897585c 100644 --- a/Storage/Tape/Parsers/ThomsonMO.cpp +++ b/Storage/Tape/Parsers/ThomsonMO.cpp @@ -92,6 +92,44 @@ std::optional Parser::block(Storage::Tape::TapeSerialiser &serialiser) { return result; } +std::optional Parser::file(Storage::Tape::TapeSerialiser &serialiser) { + std::optional result; + + do { + // Find next leader. + const auto leader = block(serialiser); + if(!leader.has_value()) break; + if(leader->type != 0) continue; + if(leader->data.size() != 14) continue; + + // Create file. + result = File(); + const auto copy_string = [&](auto &target, const size_t offset) { + std::copy_n(leader->data.data() + offset, sizeof(target) - 1, target); + + auto end = std::find_if(std::rbegin(target) + 1, std::rend(target), [](const char c) { + return c != ' '; + }); + *(end - 1) = '\0'; + }; + + copy_string(result->name, 0); + copy_string(result->extension, 8); + + result->type = leader->data[11]; + result->mode = uint16_t((leader->data[12] << 8) | leader->data[13]); + + // Accumulate data for as long as it comes. + while(true) { + const auto next = block(serialiser); + if(next->type != 1) break; + std::copy(next->data.begin(), next->data.end(), std::back_inserter(result->data)); + } + } while(false); + + return result; +} + uint8_t Block::check_digit() const { return uint8_t(checksum - std::accumulate(data.begin(), data.end(), 0)); } diff --git a/Storage/Tape/Parsers/ThomsonMO.hpp b/Storage/Tape/Parsers/ThomsonMO.hpp index 3f377a156..ae4ea1cef 100644 --- a/Storage/Tape/Parsers/ThomsonMO.hpp +++ b/Storage/Tape/Parsers/ThomsonMO.hpp @@ -27,11 +27,26 @@ struct Block { uint8_t check_digit() const; }; +struct File { + char name[9]{}; + char extension[4]{}; + std::string filename() const { + return std::string(name) + '.' + extension; + } + + uint8_t type = 0; + uint16_t mode = 0; + + std::vector data; + bool checksums_valid = true; +}; + class Parser { public: std::optional bit(Storage::Tape::TapeSerialiser &); std::optional byte(Storage::Tape::TapeSerialiser &); std::optional block(Storage::Tape::TapeSerialiser &); + std::optional file(Storage::Tape::TapeSerialiser &); void seed_level(Pulse::Type);