1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Made sufficient changes for the Vic itself to believe it can recast a PRG as a tape and insert it that way. So now the ball is in the court of: how the heck are Commodore tapes encoded?

This commit is contained in:
Thomas Harte 2016-08-15 19:44:41 -04:00
parent 3aa40212f3
commit 38aec44d85
8 changed files with 128 additions and 19 deletions

View File

@ -9,6 +9,7 @@
#include "Vic20.hpp" #include "Vic20.hpp"
#include <algorithm> #include <algorithm>
#include "../../../Storage/Tape/Formats/TapePRG.hpp"
using namespace Commodore::Vic20; using namespace Commodore::Vic20;
@ -218,7 +219,7 @@ void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data)
} }
} }
void Machine::add_prg(size_t length, const uint8_t *data) void Machine::set_prg(const char *file_name, size_t length, const uint8_t *data)
{ {
if(length > 2) if(length > 2)
{ {
@ -237,16 +238,8 @@ void Machine::add_prg(size_t length, const uint8_t *data)
} }
else else
{ {
// TODO: write to virtual media (tape, probably?), load normally. // if it's not a ROM then insert it as a tape
data += 2; set_tape(std::shared_ptr<Storage::Tape>(new Storage::TapePRG(file_name)));
while(_rom_length)
{
uint8_t *ram = _processorWriteMemoryMap[_rom_address >> 10];
if(ram) ram[_rom_address & 0x3ff] = *data;
data++;
_rom_length--;
_rom_address++;
}
} }
} }
} }

View File

@ -260,7 +260,7 @@ class Machine:
~Machine(); ~Machine();
void set_rom(ROMSlot slot, size_t length, const uint8_t *data); void set_rom(ROMSlot slot, size_t length, const uint8_t *data);
void add_prg(size_t length, const uint8_t *data); void set_prg(const char *file_name, size_t length, const uint8_t *data);
void set_tape(std::shared_ptr<Storage::Tape> tape); void set_tape(std::shared_ptr<Storage::Tape> tape);
void set_disk(std::shared_ptr<Storage::Disk> disk); void set_disk(std::shared_ptr<Storage::Disk> disk);

View File

@ -22,6 +22,7 @@
4B2A53A11D117D36003C6002 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; }; 4B2A53A11D117D36003C6002 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; };
4B2A53A21D117D36003C6002 /* CSElectron.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539C1D117D36003C6002 /* CSElectron.mm */; }; 4B2A53A21D117D36003C6002 /* CSElectron.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539C1D117D36003C6002 /* CSElectron.mm */; };
4B2A53A31D117D36003C6002 /* CSVic20.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539E1D117D36003C6002 /* CSVic20.mm */; }; 4B2A53A31D117D36003C6002 /* CSVic20.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539E1D117D36003C6002 /* CSVic20.mm */; };
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */; };
4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2E2D931C399D1200138695 /* ElectronDocument.xib */; }; 4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2E2D931C399D1200138695 /* ElectronDocument.xib */; };
4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; }; 4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; };
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; }; 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; };
@ -393,6 +394,8 @@
4B2A539C1D117D36003C6002 /* CSElectron.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSElectron.mm; sourceTree = "<group>"; }; 4B2A539C1D117D36003C6002 /* CSElectron.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSElectron.mm; sourceTree = "<group>"; };
4B2A539D1D117D36003C6002 /* CSVic20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVic20.h; sourceTree = "<group>"; }; 4B2A539D1D117D36003C6002 /* CSVic20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVic20.h; sourceTree = "<group>"; };
4B2A539E1D117D36003C6002 /* CSVic20.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSVic20.mm; sourceTree = "<group>"; }; 4B2A539E1D117D36003C6002 /* CSVic20.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSVic20.mm; sourceTree = "<group>"; };
4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapePRG.cpp; sourceTree = "<group>"; };
4B2BFC5E1D613E0200BA3AA9 /* TapePRG.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TapePRG.hpp; sourceTree = "<group>"; };
4B2E2D941C399D1200138695 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ElectronDocument.xib; sourceTree = "<group>"; }; 4B2E2D941C399D1200138695 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ElectronDocument.xib; sourceTree = "<group>"; };
4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = "<group>"; }; 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = "<group>"; };
4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = "<group>"; }; 4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = "<group>"; };
@ -1004,6 +1007,8 @@
4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */, 4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */,
4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */, 4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */,
4BC91B821D1F160E00884B76 /* CommodoreTAP.hpp */, 4BC91B821D1F160E00884B76 /* CommodoreTAP.hpp */,
4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */,
4B2BFC5E1D613E0200BA3AA9 /* TapePRG.hpp */,
); );
path = Formats; path = Formats;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1908,6 +1913,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */,
4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */, 4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */,
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */, 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */,
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */, 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,

View File

@ -47,6 +47,7 @@ class Vic20Document: MachineDocument {
case "tap": vic20.openTAPAtURL(url) case "tap": vic20.openTAPAtURL(url)
case "g64": vic20.openG64AtURL(url) case "g64": vic20.openG64AtURL(url)
case "d64": vic20.openD64AtURL(url) case "d64": vic20.openD64AtURL(url)
case "prg": vic20.openPRGAtURL(url)
default: default:
let fileWrapper = try NSFileWrapper(URL: url, options: NSFileWrapperReadingOptions(rawValue: 0)) let fileWrapper = try NSFileWrapper(URL: url, options: NSFileWrapperReadingOptions(rawValue: 0))
try self.readFromFileWrapper(fileWrapper, ofType: typeName) try self.readFromFileWrapper(fileWrapper, ofType: typeName)
@ -59,10 +60,6 @@ class Vic20Document: MachineDocument {
return dataForResource(name, ofType: "bin", inDirectory: "ROMImages/Vic20") return dataForResource(name, ofType: "bin", inDirectory: "ROMImages/Vic20")
} }
override func readFromData(data: NSData, ofType typeName: String) throws {
vic20.setPRG(data)
}
// MARK: automatic loading tick box // MARK: automatic loading tick box
@IBOutlet var loadAutomaticallyButton: NSButton? @IBOutlet var loadAutomaticallyButton: NSButton?
var autoloadingUserDefaultsKey: String { var autoloadingUserDefaultsKey: String {

View File

@ -30,7 +30,7 @@ typedef NS_ENUM(NSInteger, CSVic20MemorySize)
- (void)setCharactersROM:(nonnull NSData *)rom; - (void)setCharactersROM:(nonnull NSData *)rom;
- (void)setDriveROM:(nonnull NSData *)rom; - (void)setDriveROM:(nonnull NSData *)rom;
- (void)setPRG:(nonnull NSData *)prg; - (BOOL)openPRGAtURL:(nonnull NSURL *)URL;
- (BOOL)openTAPAtURL:(nonnull NSURL *)URL; - (BOOL)openTAPAtURL:(nonnull NSURL *)URL;
- (BOOL)openG64AtURL:(nonnull NSURL *)URL; - (BOOL)openG64AtURL:(nonnull NSURL *)URL;
- (BOOL)openD64AtURL:(nonnull NSURL *)URL; - (BOOL)openD64AtURL:(nonnull NSURL *)URL;

View File

@ -82,9 +82,15 @@ using namespace Commodore::Vic20;
} }
} }
- (void)setPRG:(nonnull NSData *)prg { - (BOOL)openPRGAtURL:(NSURL *)URL {
NSData *prg = [NSData dataWithContentsOfURL:URL];
@synchronized(self) { @synchronized(self) {
_vic20.add_prg(prg.length, (const uint8_t *)prg.bytes); try {
_vic20.set_prg(URL.fileSystemRepresentation, prg.length, (const uint8_t *)prg.bytes);
return YES;
} catch(...) {
return NO;
}
} }
} }

View File

@ -0,0 +1,49 @@
//
// TapePRG.cpp
// Clock Signal
//
// Created by Thomas Harte on 14/08/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "TapePRG.hpp"
#include <sys/stat.h>
using namespace Storage;
TapePRG::TapePRG(const char *file_name) : _file(nullptr)
{
struct stat file_stats;
stat(file_name, &file_stats);
// There's really no way to validate other than that if this file is larger than 64kb,
// of if load address + length > 65536 then it's broken.
if(file_stats.st_size >= 65538 || file_stats.st_size < 3)
throw ErrorBadFormat;
_file = fopen(file_name, "rb");
if(!_file) throw ErrorBadFormat;
_load_address = (uint16_t)fgetc(_file);
_load_address |= (uint16_t)fgetc(_file) << 8;
if (_load_address + file_stats.st_size >= 65536)
throw ErrorBadFormat;
}
TapePRG::~TapePRG()
{
if(_file) fclose(_file);
}
Tape::Pulse TapePRG::get_next_pulse()
{
Tape::Pulse pulse;
return pulse;
}
void TapePRG::reset()
{
// TODO
}

View File

@ -0,0 +1,58 @@
//
// TapePRG.hpp
// Clock Signal
//
// Created by Thomas Harte on 14/08/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef TapePRG_hpp
#define TapePRG_hpp
#include "../Tape.hpp"
#include <stdint.h>
namespace Storage {
/*!
Provides a @c Tape containing a .PRG, which is a direct local file.
*/
class TapePRG: public Tape {
public:
/*!
Constructs a @c T64 containing content from the file with name @c file_name, of type @c type.
@param file_name The name of the file to load.
@param type The type of data the file should contain.
@throws ErrorBadFormat if this file could not be opened and recognised as the specified type.
*/
TapePRG(const char *file_name);
~TapePRG();
enum {
ErrorBadFormat
};
// implemented to satisfy @c Tape
Pulse get_next_pulse();
void reset();
private:
FILE *_file;
uint16_t _load_address;
enum FilePhase {
FilePhaseLeadIn,
FilePhaseHeader
} _filePhase;
enum BitPhase {
BitPhase0,
BitPhase1,
BitPhase2,
BitPhase3
} _bitPhase;
};
}
#endif /* T64_hpp */