From 50175a9aed15db7a1648853d85142f05da7e7be6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 7 Sep 2016 22:17:19 -0400 Subject: [PATCH] Added logic to try to spot when the first program is BASIC and, if so, what the correct memory model is, then to get that information to the Vic. Though it currently then gets overwritten by the view controller. Grrrr. --- Machines/Commodore/Vic-20/Vic20.cpp | 33 ++++++++- Machines/Commodore/Vic-20/Vic20.hpp | 2 + .../Documents/Vic20Document.swift | 4 ++ .../Clock Signal/Machine/Wrappers/CSVic20.mm | 6 ++ .../Commodore/CommodoreAnalyser.cpp | 70 +++++++++++++++++-- StaticAnalyser/StaticAnalyser.hpp | 12 ++-- 6 files changed, 116 insertions(+), 11 deletions(-) diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index e1a7b993c..76eedc4cd 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -269,10 +269,39 @@ void Machine::set_prg(const char *file_name, size_t length, const uint8_t *data) #pragma mar - Tape +void Machine::configure_as_target(const StaticAnalyser::Target &target) +{ + if(target.tapes.size()) + { + _tape.set_tape(target.tapes.front()); + } + + if(_should_automatically_load_media) + { + if(target.loadingCommand.length()) // TODO: and automatic loading option enabled + { + set_typer_for_string(target.loadingCommand.c_str()); + } + + switch(target.vic20.memory_model) + { + case StaticAnalyser::Vic20MemoryModel::Unexpanded: + set_memory_size(Default); + break; + case StaticAnalyser::Vic20MemoryModel::EightKB: + set_memory_size(ThreeKB); + break; + case StaticAnalyser::Vic20MemoryModel::ThirtyTwoKB: + set_memory_size(ThirtyTwoKB); + break; + } + } +} + void Machine::set_tape(std::shared_ptr tape) { - _tape.set_tape(tape); - if(_should_automatically_load_media) set_typer_for_string("LOAD\nRUN\n"); +// _tape.set_tape(tape); +// if(_should_automatically_load_media) set_typer_for_string("LOAD\nRUN\n"); } void Machine::tape_did_change_input(Tape *tape) diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index 59fec787b..8e6fe001b 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -21,6 +21,7 @@ #include "../../../Storage/Tape/Tape.hpp" #include "../../../Storage/Disk/Disk.hpp" +#include "../../../StaticAnalyser/StaticAnalyser.hpp" namespace Commodore { namespace Vic20 { @@ -260,6 +261,7 @@ class Machine: ~Machine(); void set_rom(ROMSlot slot, size_t length, const uint8_t *data); + void configure_as_target(const StaticAnalyser::Target &target); void set_prg(const char *file_name, size_t length, const uint8_t *data); void set_tape(std::shared_ptr tape); void set_disk(std::shared_ptr disk); diff --git a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift index 6eb656b3b..a45cc8919 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift @@ -41,6 +41,10 @@ class Vic20Document: MachineDocument { return "Vic20Document" } + override func configureAs(analysis: CSStaticAnalyser) { + analysis.applyToMachine(vic20) + } + override func readFromURL(url: NSURL, ofType typeName: String) throws { if let pathExtension = url.pathExtension { switch pathExtension.lowercaseString { diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm index 7198aafe7..9dad2a4a7 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSVic20.mm @@ -46,6 +46,12 @@ using namespace Commodore::Vic20; [self setROM:rom slot:Drive]; } +- (void)applyTarget:(StaticAnalyser::Target)target { + @synchronized(self) { + _vic20.configure_as_target(target); + } +} + - (BOOL)openTAPAtURL:(NSURL *)URL { @synchronized(self) { try { diff --git a/StaticAnalyser/Commodore/CommodoreAnalyser.cpp b/StaticAnalyser/Commodore/CommodoreAnalyser.cpp index 7fce5cf3c..ce9890f20 100644 --- a/StaticAnalyser/Commodore/CommodoreAnalyser.cpp +++ b/StaticAnalyser/Commodore/CommodoreAnalyser.cpp @@ -36,12 +36,74 @@ void StaticAnalyser::Commodore::AddTargets( // continue if there are any files if(files.size()) { - // TODO: decide between ,1 (don't relocate; for machine code) and ,0 (relocate; for BASIC) - // TODO: decide memory model (based on extents and sizes) - // TODO: decide machine (disassemble?) + bool is_basic = true; + + // decide whether this is a BASIC file based on the proposition that: + // (1) they're always relocatable; and + // (2) they have a per-line structure of: + // [4 bytes: address of start of next line] + // [4 bytes: this line number] + // ... null-terminated code ... + // (with a next line address of 0000 indicating end of program)ß + if(files.front().type != File::RelocatableProgram) is_basic = false; + else + { + uint16_t line_address = 0; + int line_number = -1; + + uint16_t starting_address = files.front().starting_address; + line_address = starting_address; + is_basic = false; + while(1) + { + if(line_address - starting_address >= files.front().data.size() + 2) break; + + uint16_t next_line_address = files.front().data[line_address - starting_address]; + next_line_address |= files.front().data[line_address - starting_address + 1] << 8; + + if(!next_line_address) + { + is_basic = true; + break; + } + if(next_line_address < line_address + 5) break; + + if(line_address - starting_address >= files.front().data.size() + 5) break; + uint16_t next_line_number = files.front().data[line_address - starting_address + 2]; + next_line_number |= files.front().data[line_address - starting_address + 3] << 8; + + if(next_line_number <= line_number) break; + + line_number = (uint16_t)next_line_number; + line_address = next_line_address; + } + } + + target.vic20.memory_model = Vic20MemoryModel::Unexpanded; + if(is_basic) + { + target.loadingCommand = "LOAD\"\",1,0\nRUN\n"; + switch(files.front().starting_address) + { + case 0x1001: + default: break; + case 0x1201: + target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB; + break; + case 0x0401: + target.vic20.memory_model = Vic20MemoryModel::EightKB; + break; + } + } + else + { + // TODO: this is machine code. So, ummm? + } + + target.tapes = tapes; } } if(target.tapes.size() || target.cartridges.size() || target.disks.size()) destination.push_back(target); -} \ No newline at end of file +} diff --git a/StaticAnalyser/StaticAnalyser.hpp b/StaticAnalyser/StaticAnalyser.hpp index 1e3b59a22..691d5e364 100644 --- a/StaticAnalyser/StaticAnalyser.hpp +++ b/StaticAnalyser/StaticAnalyser.hpp @@ -19,6 +19,12 @@ namespace StaticAnalyser { +enum class Vic20MemoryModel { + Unexpanded, + EightKB, + ThirtyTwoKB +}; + /*! A list of disks, tapes and cartridges plus information about the machine to which to attach them and its configuration, and instructions on how to launch the software attached, plus a measure of confidence in this target's correctness. @@ -33,11 +39,7 @@ struct Target { union { struct { - enum class Vic20 { - Unexpanded, - EightKB, - ThirtyTwoKB - } memoryModel; + Vic20MemoryModel memory_model; bool has_c1540; } vic20;