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:
parent
3aa40212f3
commit
38aec44d85
@ -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++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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 */,
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
Storage/Tape/Formats/TapePRG.cpp
Normal file
49
Storage/Tape/Formats/TapePRG.cpp
Normal 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
|
||||||
|
}
|
58
Storage/Tape/Formats/TapePRG.hpp
Normal file
58
Storage/Tape/Formats/TapePRG.hpp
Normal 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 */
|
Loading…
Reference in New Issue
Block a user