From d9f00651543bb2b1891c5911e0f759956e55befa Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 28 Aug 2016 12:20:40 -0400 Subject: [PATCH] Sketched out just enough classes to get through the get-contents-into-memory step of static analysis. --- .../Clock Signal.xcodeproj/project.pbxproj | 12 +++++ StaticAnalyser/StaticAnalyser.cpp | 40 +++++++---------- StaticAnalyser/StaticAnalyser.hpp | 21 ++++++--- Storage/Cartridge/Cartridge.hpp | 45 ++++++++++++++++++- Storage/Cartridge/Formats/A26.cpp | 15 +++++++ Storage/Cartridge/Formats/A26.hpp | 30 +++++++++++++ Storage/Cartridge/Formats/AcornROM.cpp | 15 +++++++ Storage/Cartridge/Formats/AcornROM.hpp | 29 ++++++++++++ Storage/Cartridge/Formats/PRG.cpp | 22 +++++---- Storage/Cartridge/Formats/PRG.hpp | 6 --- 10 files changed, 184 insertions(+), 51 deletions(-) create mode 100644 Storage/Cartridge/Formats/A26.cpp create mode 100644 Storage/Cartridge/Formats/A26.hpp create mode 100644 Storage/Cartridge/Formats/AcornROM.cpp create mode 100644 Storage/Cartridge/Formats/AcornROM.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 9d63cc952..e33b3cec4 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -26,6 +26,8 @@ 4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2E2D931C399D1200138695 /* ElectronDocument.xib */; }; 4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; }; 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; }; + 4B37EE7F1D734596006A09A4 /* A26.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE7D1D734596006A09A4 /* A26.cpp */; }; + 4B37EE821D7345A6006A09A4 /* AcornROM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B37EE801D7345A6006A09A4 /* AcornROM.cpp */; }; 4B3BA0C31D318AEC005DD7A7 /* C1540Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */; }; 4B3BA0CE1D318B44005DD7A7 /* C1540Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */; }; 4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0C91D318B44005DD7A7 /* MOS6522Bridge.mm */; }; @@ -406,6 +408,10 @@ 4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = ""; }; 4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = ""; }; 4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = ""; }; + 4B37EE7D1D734596006A09A4 /* A26.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = A26.cpp; sourceTree = ""; }; + 4B37EE7E1D734596006A09A4 /* A26.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = A26.hpp; sourceTree = ""; }; + 4B37EE801D7345A6006A09A4 /* AcornROM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AcornROM.cpp; sourceTree = ""; }; + 4B37EE811D7345A6006A09A4 /* AcornROM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AcornROM.hpp; sourceTree = ""; }; 4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = C1540Tests.swift; sourceTree = ""; }; 4B3BA0C51D318B44005DD7A7 /* C1540Bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = C1540Bridge.h; sourceTree = ""; }; 4B3BA0C61D318B44005DD7A7 /* C1540Bridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = C1540Bridge.mm; sourceTree = ""; }; @@ -1545,6 +1551,10 @@ children = ( 4BEE0A6D1D72496600532C7B /* PRG.cpp */, 4BEE0A6E1D72496600532C7B /* PRG.hpp */, + 4B37EE7D1D734596006A09A4 /* A26.cpp */, + 4B37EE7E1D734596006A09A4 /* A26.hpp */, + 4B37EE801D7345A6006A09A4 /* AcornROM.cpp */, + 4B37EE811D7345A6006A09A4 /* AcornROM.hpp */, ); path = Formats; sourceTree = ""; @@ -1972,6 +1982,7 @@ 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */, + 4B37EE7F1D734596006A09A4 /* A26.cpp in Sources */, 4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */, 4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */, 4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */, @@ -2010,6 +2021,7 @@ 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */, 4BC91B831D1F160E00884B76 /* CommodoreTAP.cpp in Sources */, 4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */, + 4B37EE821D7345A6006A09A4 /* AcornROM.cpp in Sources */, 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/StaticAnalyser/StaticAnalyser.cpp b/StaticAnalyser/StaticAnalyser.cpp index a808a1bc0..9c0f39ea6 100644 --- a/StaticAnalyser/StaticAnalyser.cpp +++ b/StaticAnalyser/StaticAnalyser.cpp @@ -10,6 +10,8 @@ #include +#include "../Storage/Cartridge/Formats/A26.hpp" +#include "../Storage/Cartridge/Formats/AcornROM.hpp" #include "../Storage/Cartridge/Formats/PRG.hpp" #include "../Storage/Disk/Formats/D64.hpp" @@ -26,7 +28,6 @@ enum class TargetPlatform: TargetPlatformType { Commodore = 1 << 2 }; - using namespace StaticAnalyser; std::list StaticAnalyser::GetTargets(const char *file_name) @@ -59,27 +60,21 @@ std::list StaticAnalyser::GetTargets(const char *file_name) list.emplace_back(new Storage::class(file_name));\ potential_platforms |= (TargetPlatformType)(platforms);\ +#define TryInsert(list, class, platforms) \ + try {\ + Insert(list, class, platforms) \ + } catch(...) {} + #define Format(extension, list, class, platforms) \ if(!strcmp(lowercase_extension, extension)) \ { \ - try { \ - list.emplace_back(new Storage::class(file_name));\ - potential_platforms |= (TargetPlatformType)(platforms);\ - } catch(...) {}\ + TryInsert(list, class, platforms) \ } - // A26 - if(!strcmp(lowercase_extension, "a26")) - { - } - - // BIN - if(!strcmp(lowercase_extension, "bin")) - { - } - - Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64 - Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64 + Format("a26", cartridges, Cartridge::A26, TargetPlatform::Atari2600) // A26 + Format("bin", cartridges, Cartridge::A26, TargetPlatform::Atari2600) // BIN + Format("d64", disks, Disk::D64, TargetPlatform::Commodore) // D64 + Format("g64", disks, Disk::G64, TargetPlatform::Commodore) // G64 // PRG if(!strcmp(lowercase_extension, "prg")) @@ -97,12 +92,9 @@ std::list StaticAnalyser::GetTargets(const char *file_name) } // ROM - if(!strcmp(lowercase_extension, "rom")) - { - } - - Format("tap", tapes, Tape::CommodoreTAP, TargetPlatform::Commodore) // TAP - Format("uef", tapes, Tape::UEF, TargetPlatform::Acorn) // UEF (tape) + Format("rom", cartridges, Cartridge::AcornROM, TargetPlatform::Acorn) // ROM + Format("tap", tapes, Tape::CommodoreTAP, TargetPlatform::Commodore) // TAP + Format("uef", tapes, Tape::UEF, TargetPlatform::Acorn) // UEF (tape) #undef Format #undef Insert @@ -110,8 +102,6 @@ std::list StaticAnalyser::GetTargets(const char *file_name) // Hand off to platform-specific determination of whether these things are actually compatible and, // if so, how to load them. (TODO) - printf("Lowercase extension: %s", lowercase_extension); - free(lowercase_extension); return targets; } diff --git a/StaticAnalyser/StaticAnalyser.hpp b/StaticAnalyser/StaticAnalyser.hpp index d7810ada9..23d60867c 100644 --- a/StaticAnalyser/StaticAnalyser.hpp +++ b/StaticAnalyser/StaticAnalyser.hpp @@ -19,14 +19,16 @@ namespace StaticAnalyser { -enum Machine { - Atari2600, - Electron, - Vic20 -}; - +/*! + 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. +*/ struct Target { - Machine machine; + enum { + Atari2600, + Electron, + Vic20 + } machine; float probability; union { @@ -59,6 +61,11 @@ struct Target { std::list> cartridges; }; +/*! + Attempts, through any available means, to return a list of potential targets for the file with the given name. + + @returns The list of potential targets, sorted from most to least probable. +*/ std::list GetTargets(const char *file_name); } diff --git a/Storage/Cartridge/Cartridge.hpp b/Storage/Cartridge/Cartridge.hpp index 902684072..19e4a48d2 100644 --- a/Storage/Cartridge/Cartridge.hpp +++ b/Storage/Cartridge/Cartridge.hpp @@ -9,10 +9,53 @@ #ifndef Storage_Cartridge_hpp #define Storage_Cartridge_hpp +#include +#include +#include + namespace Storage { namespace Cartridge { -class Cartridge {}; +/*! + Provides a base class for cartridges; the bus provided to cartridges and therefore + the interface they support is extremely machine-dependent so unlike disks and tapes, + no model is imposed; this class seeks merely to be a base class for fully-descriptive + summaries of the contents of emulator files that themselves describe cartridges. + + Consumers will almost certainly seek to dynamic_cast to something more appropriate, + however some cartridge container formats have no exposition beyond the ROM dump, + making the base class 100% descriptive. +*/ +class Cartridge { + public: + struct Segment { + Segment(int start_address, int end_address, std::vector data) : + start_address(start_address), end_address(end_address), data(std::move(data)) {} + + /// Indicates that an address is unknown. + static const int UnknownAddress; + + /// The initial CPU-exposed starting address for this segment; may be @c UnknownAddress. + int start_address; + /*! + The initial CPU-exposed ending address for this segment; may be @c UnknownAddress. Not necessarily equal + to start_address + data_length due to potential paging. + */ + int end_address; + + /*! + The data contents for this segment. If @c start_address and @c end_address are suppled then + the first end_address - start_address bytes will be those initially visible. The size will + not necessarily be the same as @c end_address - @c start_address due to potential paging. + */ + std::vector data; + }; + + const std::list &get_segments() { return _segments; } + + protected: + std::list _segments; +}; } } diff --git a/Storage/Cartridge/Formats/A26.cpp b/Storage/Cartridge/Formats/A26.cpp new file mode 100644 index 000000000..9bed6998e --- /dev/null +++ b/Storage/Cartridge/Formats/A26.cpp @@ -0,0 +1,15 @@ +// +// A26.cpp +// Clock Signal +// +// Created by Thomas Harte on 28/08/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "A26.hpp" + +using namespace Storage::Cartridge; + +A26::A26(const char *file_name) +{ +} diff --git a/Storage/Cartridge/Formats/A26.hpp b/Storage/Cartridge/Formats/A26.hpp new file mode 100644 index 000000000..6aa024568 --- /dev/null +++ b/Storage/Cartridge/Formats/A26.hpp @@ -0,0 +1,30 @@ +// +// A26.hpp +// Clock Signal +// +// Created by Thomas Harte on 28/08/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Storage_Cartridge_A26_hpp +#define Storage_Cartridge_A26_hpp + +#include "../Cartridge.hpp" + +namespace Storage { +namespace Cartridge { + +class A26 : public Cartridge { + public: + A26(const char *file_name); + + enum { + ErrorNotAcornROM + }; +}; + +} +} + + +#endif /* A26_hpp */ diff --git a/Storage/Cartridge/Formats/AcornROM.cpp b/Storage/Cartridge/Formats/AcornROM.cpp new file mode 100644 index 000000000..f6d29742a --- /dev/null +++ b/Storage/Cartridge/Formats/AcornROM.cpp @@ -0,0 +1,15 @@ +// +// AcornROM.cpp +// Clock Signal +// +// Created by Thomas Harte on 28/08/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "AcornROM.hpp" + +using namespace Storage::Cartridge; + +AcornROM::AcornROM(const char *file_name) +{ +} diff --git a/Storage/Cartridge/Formats/AcornROM.hpp b/Storage/Cartridge/Formats/AcornROM.hpp new file mode 100644 index 000000000..f5f923ce7 --- /dev/null +++ b/Storage/Cartridge/Formats/AcornROM.hpp @@ -0,0 +1,29 @@ +// +// AcornROM.hpp +// Clock Signal +// +// Created by Thomas Harte on 28/08/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Storage_Cartridge_AcornROM_hpp +#define Storage_Cartridge_AcornROM_hpp + +#include "../Cartridge.hpp" + +namespace Storage { +namespace Cartridge { + +class AcornROM : public Cartridge { + public: + AcornROM(const char *file_name); + + enum { + ErrorNotAcornROM + }; +}; + +} +} + +#endif /* AcornROM_hpp */ diff --git a/Storage/Cartridge/Formats/PRG.cpp b/Storage/Cartridge/Formats/PRG.cpp index 422edd621..fcbfd36a7 100644 --- a/Storage/Cartridge/Formats/PRG.cpp +++ b/Storage/Cartridge/Formats/PRG.cpp @@ -13,7 +13,7 @@ using namespace Storage::Cartridge; -PRG::PRG(const char *file_name) : _contents(nullptr) +PRG::PRG(const char *file_name) { struct stat file_stats; stat(file_name, &file_stats); @@ -32,8 +32,9 @@ PRG::PRG(const char *file_name) : _contents(nullptr) int loading_address = fgetc(file); loading_address |= fgetc(file) << 8; - _contents = new uint8_t[file_stats.st_size - 2]; - fread(_contents, 1, (size_t)(file_stats.st_size - 2), file); + size_t data_length = (size_t)file_stats.st_size - 2; + std::vector contents(data_length); + fread(&contents[0], 1, (size_t)(data_length), file); fclose(file); // accept only files intended to load at 0xa000 @@ -42,15 +43,12 @@ PRG::PRG(const char *file_name) : _contents(nullptr) // also accept only cartridges with the proper signature if( - _contents[4] != 0x41 || - _contents[5] != 0x30 || - _contents[6] != 0xc3 || - _contents[7] != 0xc2 || - _contents[8] != 0xcd) + contents[4] != 0x41 || + contents[5] != 0x30 || + contents[6] != 0xc3 || + contents[7] != 0xc2 || + contents[8] != 0xcd) throw ErrorNotROM; -} -PRG::~PRG() -{ - delete[] _contents; + _segments.emplace_back(0xa000, 0xa000 + data_length, std::move(contents)); } diff --git a/Storage/Cartridge/Formats/PRG.hpp b/Storage/Cartridge/Formats/PRG.hpp index 2ad1adefc..00722d8e2 100644 --- a/Storage/Cartridge/Formats/PRG.hpp +++ b/Storage/Cartridge/Formats/PRG.hpp @@ -9,7 +9,6 @@ #ifndef Storage_Cartridge_PRG_hpp #define Storage_Cartridge_PRG_hpp -#include #include "../Cartridge.hpp" namespace Storage { @@ -18,15 +17,10 @@ namespace Cartridge { class PRG : public Cartridge { public: PRG(const char *file_name); - ~PRG(); enum { ErrorNotROM }; - - private: - uint8_t *_contents; - uint16_t _size; }; }