From 9d7962d6c0c1c968346c23df050f4f7bcd0e6afa Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 31 Aug 2016 20:24:13 -0400 Subject: [PATCH] Closed the loop on Electron analysis for now. Including loading command detection. --- StaticAnalyser/Acorn/AcornAnalyser.cpp | 44 ++++++++++++++++++++++++-- StaticAnalyser/Acorn/Tape.cpp | 6 ++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/StaticAnalyser/Acorn/AcornAnalyser.cpp b/StaticAnalyser/Acorn/AcornAnalyser.cpp index ac91be23d..b96d0f603 100644 --- a/StaticAnalyser/Acorn/AcornAnalyser.cpp +++ b/StaticAnalyser/Acorn/AcornAnalyser.cpp @@ -63,14 +63,54 @@ void StaticAnalyser::Acorn::AddTargets( const std::list> &cartridges, std::list &destination) { + Target target; + target.machine = Target::Electron; + target.probability = 1.0; // TODO: a proper estimation + // strip out inappropriate cartridges - std::list> acornCartridges = AcornCartridgesFrom(cartridges); + target.cartridges = AcornCartridgesFrom(cartridges); // if there are any tapes, attempt to get data from the first if(tapes.size() > 0) { std::shared_ptr tape = tapes.front(); tape->reset(); - GetFiles(tape); + + // continue if there are any files + std::list files = GetFiles(tape); + if(files.size()) + { + bool is_basic = true; + + // protected files are always for *RUNning only + if(files.front().is_protected) is_basic = false; + + // check also for a continuous threading of BASIC lines; if none then this probably isn't BASIC code, + // so that's also justification to *RUN + size_t pointer = 0; + uint8_t *data = &files.front().data[0]; + size_t data_size = files.front().data.size(); + while(1) + { + if(pointer >= data_size-1 || data[pointer] != 13) + { + is_basic = false; + break; + } + if((data[pointer+1]&0x7f) == 0x7f) break; + pointer += data[pointer+3]; + } + + // Inspect first file. If it's protected or doesn't look like BASIC + // then the loading command is *RUN. Otherwise it's CHAIN"". + target.loadingCommand = is_basic ? "CHAIN\"\"\n" : "*RUN\n"; + + target.tapes = tapes; + } } + + // TODO: disks + + if(target.tapes.size() || target.cartridges.size()) + destination.push_back(target); } diff --git a/StaticAnalyser/Acorn/Tape.cpp b/StaticAnalyser/Acorn/Tape.cpp index 1a266c5ba..e31821e8f 100644 --- a/StaticAnalyser/Acorn/Tape.cpp +++ b/StaticAnalyser/Acorn/Tape.cpp @@ -20,7 +20,7 @@ struct TapeParser { { // skip any gaps Storage::Tape::Tape::Pulse next_pulse = _tape->get_next_pulse(); - while(next_pulse.type == Storage::Tape::Tape::Pulse::Zero) + while(!_tape->is_at_end() && next_pulse.type == Storage::Tape::Tape::Pulse::Zero) { next_pulse = _tape->get_next_pulse(); } @@ -231,9 +231,11 @@ std::unique_ptr GetNextFile(TapeParser &parser) { chunk = GetNextChunk(parser); if(!chunk) continue; - if(chunk->block_number) continue; + if(!chunk->block_number) break; } + if(!chunk) return nullptr; + // accumulate chunks for as long as block number is sequential and the end-of-file bit isn't set std::unique_ptr file(new File); file->chunks.push_back(*chunk);