From 80702616ea9a873d5ed57f27b59a4fe866213823 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 6 Nov 2016 22:56:38 -0500 Subject: [PATCH] Had a quick go at using the Oric parser for static analysis. Found out that synchronisation is lost. Need to investigate. --- .../Clock Signal.xcodeproj/project.pbxproj | 6 ++ StaticAnalyser/Oric/StaticAnalyser.cpp | 22 +++-- StaticAnalyser/Oric/Tape.cpp | 95 +++++++++++++++++++ StaticAnalyser/Oric/Tape.hpp | 38 ++++++++ Storage/Tape/Parsers/Oric.cpp | 8 +- 5 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 StaticAnalyser/Oric/Tape.cpp create mode 100644 StaticAnalyser/Oric/Tape.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index b28985d17..a0340de54 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -60,6 +60,7 @@ 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 */; }; + 4B8805FE1DD02552003085B1 /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805FC1DD02552003085B1 /* Tape.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 */; }; @@ -508,6 +509,8 @@ 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 = ""; }; + 4B8805FC1DD02552003085B1 /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Tape.cpp; path = ../../StaticAnalyser/Oric/Tape.cpp; sourceTree = ""; }; + 4B8805FD1DD02552003085B1 /* Tape.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Tape.hpp; path = ../../StaticAnalyser/Oric/Tape.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; }; @@ -1770,6 +1773,8 @@ children = ( 4BCF1FA91DADD41B0039D2E7 /* StaticAnalyser.cpp */, 4BCF1FAA1DADD41B0039D2E7 /* StaticAnalyser.hpp */, + 4B8805FC1DD02552003085B1 /* Tape.cpp */, + 4B8805FD1DD02552003085B1 /* Tape.hpp */, ); name = Oric; sourceTree = ""; @@ -2325,6 +2330,7 @@ 4B8FE2201DA19D7C0090D3CE /* Atari2600OptionsPanel.swift in Sources */, 4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */, 4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */, + 4B8805FE1DD02552003085B1 /* Tape.cpp in Sources */, 4B9CCDA11DA279CA0098B625 /* Vic20OptionsPanel.swift in Sources */, 4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */, 4B3051301D98ACC600B4FED8 /* Plus3.cpp in Sources */, diff --git a/StaticAnalyser/Oric/StaticAnalyser.cpp b/StaticAnalyser/Oric/StaticAnalyser.cpp index 295e92149..a258ad65a 100644 --- a/StaticAnalyser/Oric/StaticAnalyser.cpp +++ b/StaticAnalyser/Oric/StaticAnalyser.cpp @@ -8,6 +8,8 @@ #include "StaticAnalyser.hpp" +#include "Tape.hpp" + using namespace StaticAnalyser::Oric; void StaticAnalyser::Oric::AddTargets( @@ -16,14 +18,20 @@ void StaticAnalyser::Oric::AddTargets( const std::list> &cartridges, std::list &destination) { - // TODO: any sort of sanity checking at all; at the minute just trust the file type - // approximation already performed. Target target; target.machine = Target::Oric; target.probability = 1.0; - target.disks = disks; - target.tapes = tapes; - target.cartridges = cartridges; - target.loadingCommand = "CLOAD\"\"\n"; - destination.push_back(target); + + for(auto tape : tapes) + { + std::list tape_files = GetFiles(tape); + if(tape_files.size()) + { + target.tapes.push_back(tape); + target.loadingCommand = "CLOAD\"\"\n"; + } + } + + if(target.tapes.size() || target.disks.size() || target.cartridges.size()) + destination.push_back(target); } diff --git a/StaticAnalyser/Oric/Tape.cpp b/StaticAnalyser/Oric/Tape.cpp new file mode 100644 index 000000000..17662734f --- /dev/null +++ b/StaticAnalyser/Oric/Tape.cpp @@ -0,0 +1,95 @@ +// +// Tape.cpp +// Clock Signal +// +// Created by Thomas Harte on 06/11/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Tape.hpp" +#include "../../Storage/Tape/Parsers/Oric.hpp" + +using namespace StaticAnalyser::Oric; + +std::list StaticAnalyser::Oric::GetFiles(const std::shared_ptr &tape) +{ + std::list files; + Storage::Tape::Oric::Parser parser; + + tape->reset(); + while(!tape->is_at_end()) + { + // sync to next lead-in, check that it's one of three 0x16s + bool is_fast = parser.sync_and_get_encoding_speed(tape); + int next_bytes[2]; + next_bytes[0] = parser.get_next_byte(tape, is_fast); + next_bytes[1] = parser.get_next_byte(tape, is_fast); + + if(next_bytes[0] != 0x16 || next_bytes[1] != 0x16) continue; + + // get the first byte that isn't a 0x16, check it was a 0x24 + int byte = 0x16; + while(!tape->is_at_end() && byte == 0x16) + { + byte = parser.get_next_byte(tape, is_fast); + } + if(byte != 0x24) continue; + + // skip two empty bytes + parser.get_next_byte(tape, is_fast); + parser.get_next_byte(tape, is_fast); + + // get data and launch types + File new_file; + switch(parser.get_next_byte(tape, is_fast)) + { + case 0x00: new_file.data_type = File::ProgramType::BASIC; break; + case 0x80: new_file.data_type = File::ProgramType::MachineCode; break; + default: new_file.data_type = File::ProgramType::None; break; + } + switch(parser.get_next_byte(tape, is_fast)) + { + case 0x80: new_file.launch_type = File::ProgramType::BASIC; break; + case 0xc7: new_file.launch_type = File::ProgramType::MachineCode; break; + default: new_file.launch_type = File::ProgramType::None; break; + } + + // read end and start addresses + new_file.ending_address = (uint16_t)(parser.get_next_byte(tape, is_fast) << 8); + new_file.ending_address |= (uint16_t)parser.get_next_byte(tape, is_fast); + new_file.starting_address = (uint16_t)(parser.get_next_byte(tape, is_fast) << 8); + new_file.starting_address |= (uint16_t)parser.get_next_byte(tape, is_fast); + + // skip an empty bytes + parser.get_next_byte(tape, is_fast); + + // read file name, up to 16 characters and null terminated + char file_name[17]; + int name_pos = 0; + while(name_pos < 16) + { + file_name[name_pos] = (char)parser.get_next_byte(tape, is_fast); + if(!file_name[name_pos]) break; + name_pos++; + } + file_name[16] = '\0'; + new_file.name = file_name; + + // read body + size_t body_length = new_file.ending_address - new_file.starting_address + 1; + new_file.data.reserve(body_length); + for(size_t c = 0; c < body_length; c++) + { + new_file.data.push_back((uint8_t)parser.get_next_byte(tape, is_fast)); + } + + // only one validation check: was there enough tape? + if(!tape->is_at_end()) + { + files.push_back(new_file); + } + } + tape->reset(); + + return files; +} diff --git a/StaticAnalyser/Oric/Tape.hpp b/StaticAnalyser/Oric/Tape.hpp new file mode 100644 index 000000000..b8d0f39db --- /dev/null +++ b/StaticAnalyser/Oric/Tape.hpp @@ -0,0 +1,38 @@ +// +// Tape.hpp +// Clock Signal +// +// Created by Thomas Harte on 06/11/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef StaticAnalyser_Oric_Tape_hpp +#define StaticAnalyser_Oric_Tape_hpp + +#include "../../Storage/Tape/Tape.hpp" +#include +#include +#include + +namespace StaticAnalyser { +namespace Oric { + +struct File { + std::string name; + uint16_t starting_address; + uint16_t ending_address; + enum ProgramType { + BASIC, + MachineCode, + None + }; + ProgramType data_type, launch_type; + std::vector data; +}; + +std::list GetFiles(const std::shared_ptr &tape); + +} +} + +#endif /* Tape_hpp */ diff --git a/Storage/Tape/Parsers/Oric.cpp b/Storage/Tape/Parsers/Oric.cpp index e14069dd9..aa055794c 100644 --- a/Storage/Tape/Parsers/Oric.cpp +++ b/Storage/Tape/Parsers/Oric.cpp @@ -25,7 +25,7 @@ int Parser::get_next_byte(const std::shared_ptr &tape, bool bit_count++; } // TODO: check parity? - return tape->is_at_end() ? -1 : (result >> 1); + return tape->is_at_end() ? -1 : (result&0xff); } bool Parser::sync_and_get_encoding_speed(const std::shared_ptr &tape) @@ -141,7 +141,10 @@ void Parser::inspect_waves(const std::vector &waves) return; } if(slow_sync_matching_depth < waves.size() && fast_sync_matching_depth < waves.size()) - remove_waves((int)std::min(slow_sync_matching_depth, fast_sync_matching_depth)); + { + int least_depth = (int)std::min(slow_sync_matching_depth, fast_sync_matching_depth); + remove_waves(least_depth ? least_depth : 1); + } return; } @@ -158,6 +161,7 @@ size_t Parser::pattern_matching_depth(const std::vector &waves, Patter while(depth < waves.size() && pattern->type != WaveType::Unrecognised) { if(waves[depth] != pattern->type) break; + depth++; pattern_depth++; if(pattern_depth == pattern->count) {