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 <algorithm>
|
||||
#include "../../../Storage/Tape/Formats/TapePRG.hpp"
|
||||
|
||||
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)
|
||||
{
|
||||
@ -237,16 +238,8 @@ void Machine::add_prg(size_t length, const uint8_t *data)
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: write to virtual media (tape, probably?), load normally.
|
||||
data += 2;
|
||||
while(_rom_length)
|
||||
{
|
||||
uint8_t *ram = _processorWriteMemoryMap[_rom_address >> 10];
|
||||
if(ram) ram[_rom_address & 0x3ff] = *data;
|
||||
data++;
|
||||
_rom_length--;
|
||||
_rom_address++;
|
||||
}
|
||||
// if it's not a ROM then insert it as a tape
|
||||
set_tape(std::shared_ptr<Storage::Tape>(new Storage::TapePRG(file_name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ class Machine:
|
||||
~Machine();
|
||||
|
||||
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_disk(std::shared_ptr<Storage::Disk> disk);
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
4B2A53A11D117D36003C6002 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; };
|
||||
4B2A53A21D117D36003C6002 /* CSElectron.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539C1D117D36003C6002 /* CSElectron.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 */; };
|
||||
4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1004,6 +1007,8 @@
|
||||
4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */,
|
||||
4BC91B811D1F160E00884B76 /* CommodoreTAP.cpp */,
|
||||
4BC91B821D1F160E00884B76 /* CommodoreTAP.hpp */,
|
||||
4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */,
|
||||
4B2BFC5E1D613E0200BA3AA9 /* TapePRG.hpp */,
|
||||
);
|
||||
path = Formats;
|
||||
sourceTree = "<group>";
|
||||
@ -1908,6 +1913,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */,
|
||||
4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */,
|
||||
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */,
|
||||
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,
|
||||
|
@ -47,6 +47,7 @@ class Vic20Document: MachineDocument {
|
||||
case "tap": vic20.openTAPAtURL(url)
|
||||
case "g64": vic20.openG64AtURL(url)
|
||||
case "d64": vic20.openD64AtURL(url)
|
||||
case "prg": vic20.openPRGAtURL(url)
|
||||
default:
|
||||
let fileWrapper = try NSFileWrapper(URL: url, options: NSFileWrapperReadingOptions(rawValue: 0))
|
||||
try self.readFromFileWrapper(fileWrapper, ofType: typeName)
|
||||
@ -59,10 +60,6 @@ class Vic20Document: MachineDocument {
|
||||
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
|
||||
@IBOutlet var loadAutomaticallyButton: NSButton?
|
||||
var autoloadingUserDefaultsKey: String {
|
||||
|
@ -30,7 +30,7 @@ typedef NS_ENUM(NSInteger, CSVic20MemorySize)
|
||||
- (void)setCharactersROM:(nonnull NSData *)rom;
|
||||
- (void)setDriveROM:(nonnull NSData *)rom;
|
||||
|
||||
- (void)setPRG:(nonnull NSData *)prg;
|
||||
- (BOOL)openPRGAtURL:(nonnull NSURL *)URL;
|
||||
- (BOOL)openTAPAtURL:(nonnull NSURL *)URL;
|
||||
- (BOOL)openG64AtURL:(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) {
|
||||
_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