1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-03 15:29:45 +00:00

Start parsing CSL.

This commit is contained in:
Thomas Harte 2024-06-16 14:27:48 -04:00
parent b3012bd89e
commit e46b12e359
3 changed files with 224 additions and 0 deletions

View File

@ -180,6 +180,9 @@
4B0F1C242605996900B85C66 /* ZXSpectrumTAP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F1C212605996900B85C66 /* ZXSpectrumTAP.cpp */; };
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
4B1082C32C1A87CA00B07C5D /* CSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1082C02C1A87CA00B07C5D /* CSL.cpp */; };
4B1082C42C1F5E7D00B07C5D /* CSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1082C02C1A87CA00B07C5D /* CSL.cpp */; };
4B1082C52C1F60A900B07C5D /* CSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1082C02C1A87CA00B07C5D /* CSL.cpp */; };
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */; };
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
@ -1305,6 +1308,8 @@
4B0F94FC208C1A1600FE41D9 /* NIB.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NIB.cpp; sourceTree = "<group>"; };
4B0F94FD208C1A1600FE41D9 /* NIB.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = NIB.hpp; sourceTree = "<group>"; };
4B0F9500208C42A300FE41D9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Target.hpp; path = AppleII/Target.hpp; sourceTree = "<group>"; };
4B1082C02C1A87CA00B07C5D /* CSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CSL.cpp; sourceTree = "<group>"; };
4B1082C12C1A87CA00B07C5D /* CSL.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CSL.hpp; sourceTree = "<group>"; };
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMSegmentEventSourceTests.mm; sourceTree = "<group>"; };
4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = "<group>"; };
4B12C0EC1FCFA98D005BFD93 /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = "<group>"; };
@ -2688,6 +2693,15 @@
path = Keyboard;
sourceTree = "<group>";
};
4B1082C22C1A87CA00B07C5D /* Automation */ = {
isa = PBXGroup;
children = (
4B1082C02C1A87CA00B07C5D /* CSL.cpp */,
4B1082C12C1A87CA00B07C5D /* CSL.hpp */,
);
path = Automation;
sourceTree = "<group>";
};
4B1414561B58879D00E04248 /* 6502 */ = {
isa = PBXGroup;
children = (
@ -3326,6 +3340,7 @@
4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */,
4BF4A2D91F534DB300B171F4 /* TargetPlatforms.hpp */,
4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */,
4B1082C22C1A87CA00B07C5D /* Automation */,
4BEE0A691D72496600532C7B /* Cartridge */,
4B8805F81DCFF6CD003085B1 /* Data */,
4BAB62AA1D3272D200DF5BA0 /* Disk */,
@ -5918,6 +5933,7 @@
4B055AAC1FAE85FD0060FFFF /* PCMSegment.cpp in Sources */,
4BB307BC235001C300457D33 /* 6850.cpp in Sources */,
4B055AB31FAE860F0060FFFF /* CSW.cpp in Sources */,
4B1082C52C1F60A900B07C5D /* CSL.cpp in Sources */,
4B89451D201967B4007DE474 /* Disk.cpp in Sources */,
4BFEA2F02682A7B900EBF94C /* Dave.cpp in Sources */,
4B4C81C628B3C5CD00F84AE9 /* SCSICard.cpp in Sources */,
@ -6084,6 +6100,7 @@
4BAF2B4E2004580C00480230 /* DMK.cpp in Sources */,
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,
4B5B37312777C7FC0047F238 /* IPF.cpp in Sources */,
4B1082C42C1F5E7D00B07C5D /* CSL.cpp in Sources */,
4B0ACC3023775819008902D0 /* TIASound.cpp in Sources */,
4B7136861F78724F008B8ED9 /* Encoder.cpp in Sources */,
4B0E04EA1FC9E5DA00F43484 /* CAS.cpp in Sources */,
@ -6372,6 +6389,7 @@
4B778F4A23A5F1FB0000D260 /* StaticAnalyser.cpp in Sources */,
4B7752AB28217E560073E2C5 /* SZX.cpp in Sources */,
4BD91D772401C2B8007BDC91 /* PatrikRakTests.swift in Sources */,
4B1082C32C1A87CA00B07C5D /* CSL.cpp in Sources */,
4B680CE223A5553100451D43 /* 68000ComparativeTests.mm in Sources */,
4B778F3723A5F11C0000D260 /* Parser.cpp in Sources */,
4B778F4523A5F1CD0000D260 /* SegmentParser.cpp in Sources */,

134
Storage/Automation/CSL.cpp Normal file
View File

@ -0,0 +1,134 @@
//
// CSL.cpp
// Clock Signal
//
// Created by Thomas Harte on 12/06/2024.
// Copyright © 2024 Thomas Harte. All rights reserved.
//
#include "CSL.hpp"
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <set>
using namespace Storage::Automation;
struct CSLTest {
CSLTest() {
CSL c("/Users/thomasharte/Downloads/Shaker_CSL/MODULE A/SHAKE26A-4.CSL");
}
};
CSLTest test;
CSL::CSL(const std::string &file_name) {
// Parse the entire file ahead of time; this isn't necessary but introduces
// little significant overhead and greatly simplifies my debugging.
std::ifstream file;
file.open(file_name);
using Type = Instruction::Type;
static const std::unordered_map<std::string, Type> keywords = {
{"csl_version", Type::Version},
{"reset", Type::Reset},
{"crtc_select", Type::CRTCSelect},
{"disk_insert", Type::DiskInsert},
{"disk_dir", Type::SetDiskDir},
{"tape_insert", Type::TapeInsert},
{"tape_dir", Type::SetTapeDir},
{"tape_play", Type::TapeInsert},
{"tape_stop", Type::TapeStop},
{"tape_rewind", Type::TapeRewind},
{"snapshot_load", Type::SnapshotLoad},
{"snapshot_dir", Type::SetSnapshotDir},
{"key_delay", Type::KeyDelay},
{"key_output", Type::KeyOutput},
{"key_from_file", Type::KeyFromFile},
{"wait", Type::Wait},
{"wait_driveonoff", Type::WaitDriveOnOff},
{"wait_ssm0000", Type::WaitSSM0000},
{"screenshot_name", Type::SetScreenshotName},
{"screenshot_dir", Type::SetScreenshotDir},
{"screenshot", Type::Screenshot},
{"snapshot_name", Type::SetSnapshotDir},
{"csl_load", Type::LoadCSL},
};
for(std::string line; std::getline(file, line); ) {
// Ignore comments.
if(line[0] == ';') {
continue;
}
std::istringstream stream(line);
std::string keyword;
stream >> keyword;
const auto key_pair = keywords.find(keyword);
if(key_pair == keywords.end()) {
throw InvalidKeyword;
}
Instruction instruction;
instruction.type = key_pair->second;
const auto require = [&](auto &&target) {
stream >> target;
if(!stream.good()) {
throw InvalidArgument;
}
};
switch(instruction.type) {
// Keywords with a single string mandatory argument.
case Type::Version: {
std::string argument;
require(argument);
instruction.argument = argument;
} break;
// Keywords with a single number mandatory argument.
case Type::Wait: {
uint64_t argument;
require(argument);
instruction.argument = argument;
} break;
// Miscellaneous:
case Type::Reset: {
std::string type;
stream >> type;
if(stream.good()) {
if(type != "soft" && type != "hard") {
throw InvalidArgument;
}
instruction.argument = (type == "soft") ? ResetType::Soft : ResetType::Hard;
}
} break;
case Type::CRTCSelect: {
std::string type;
require(type);
static const std::set<std::string> allowed_types = {
"0", "1", "1A", "1B", "2", "3", "4",
};
if(allowed_types.find(type) == allowed_types.end()) {
throw InvalidArgument;
}
instruction.argument = static_cast<uint64_t>(std::stoi(type));
} break;
default:
printf("");
break;
}
instructions.push_back(std::move(instruction));
}
}

View File

@ -0,0 +1,72 @@
//
// CSL.hpp
// Clock Signal
//
// Created by Thomas Harte on 12/06/2024.
// Copyright © 2024 Thomas Harte. All rights reserved.
//
#pragma once
#include <optional>
#include <string>
#include <vector>
namespace Storage::Automation {
struct CSL {
CSL(const std::string &file_name);
enum Errors {
InvalidKeyword,
InvalidArgument,
};
private:
enum ResetType {
Hard, Soft
};
struct Instruction {
enum class Type {
Version,
Reset,
CRTCSelect,
LoadCSL,
DiskInsert,
SetDiskDir,
TapeInsert,
SetTapeDir,
TapePlay,
TapeStop,
TapeRewind,
SetSnapshotDir,
SnapshotLoad,
SetSnapshotName,
Snapshot,
KeyDelay,
KeyOutput,
KeyFromFile,
Wait,
WaitDriveOnOff,
WaitVsyncOnOff,
WaitSSM0000,
SetScreenshotName,
SetScreenshotDir,
Screenshot,
} type;
std::variant<std::monostate, ResetType, std::string, uint64_t> argument;
};
std::vector<Instruction> instructions;
std::optional<Instruction> next();
};
}