mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Implemented seeking on tapes, mucked about a bit more with the Commodore analyser, at least temporarily removed cropping from the Vic emulator.
This commit is contained in:
parent
1ca4a2a012
commit
eeec516fa6
@ -65,9 +65,6 @@ template <class T> class MOS6560 {
|
|||||||
|
|
||||||
// default to NTSC
|
// default to NTSC
|
||||||
set_output_mode(OutputMode::NTSC);
|
set_output_mode(OutputMode::NTSC);
|
||||||
|
|
||||||
// show only the centre
|
|
||||||
_crt->set_visible_area(_crt->get_rect_for_area(16, 237, 11*4, 55*4, 4.0f / 3.0f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_clock_rate(double clock_rate)
|
void set_clock_rate(double clock_rate)
|
||||||
@ -125,6 +122,18 @@ template <class T> class MOS6560 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_crt->set_new_display_type((unsigned int)(_timing.cycles_per_line*4), display_type);
|
_crt->set_new_display_type((unsigned int)(_timing.cycles_per_line*4), display_type);
|
||||||
|
// _crt->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f));
|
||||||
|
|
||||||
|
// switch(output_mode)
|
||||||
|
// {
|
||||||
|
// case OutputMode::PAL:
|
||||||
|
// _crt->set_visible_area(_crt->get_rect_for_area(16, 237, 15*4, 55*4, 4.0f / 3.0f));
|
||||||
|
// break;
|
||||||
|
// case OutputMode::NTSC:
|
||||||
|
// _crt->set_visible_area(_crt->get_rect_for_area(16, 237, 11*4, 55*4, 4.0f / 3.0f));
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
for(int c = 0; c < 16; c++)
|
for(int c = 0; c < 16; c++)
|
||||||
{
|
{
|
||||||
_colours[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]);
|
_colours[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]);
|
||||||
|
@ -269,6 +269,10 @@ void Machine::set_prg(const char *file_name, size_t length, const uint8_t *data)
|
|||||||
|
|
||||||
#pragma mar - Tape
|
#pragma mar - Tape
|
||||||
|
|
||||||
|
// LAB_FBDB = new tape byte setup;
|
||||||
|
// loops at LAB_F92F
|
||||||
|
// LAB_F8C0 = initiate tape read
|
||||||
|
|
||||||
void Machine::configure_as_target(const StaticAnalyser::Target &target)
|
void Machine::configure_as_target(const StaticAnalyser::Target &target)
|
||||||
{
|
{
|
||||||
if(target.tapes.size())
|
if(target.tapes.size())
|
||||||
|
@ -347,6 +347,7 @@
|
|||||||
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; };
|
4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */; };
|
||||||
4BD14B111D74627C0088EAD6 /* AcornAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD14B0F1D74627C0088EAD6 /* AcornAnalyser.cpp */; };
|
4BD14B111D74627C0088EAD6 /* AcornAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD14B0F1D74627C0088EAD6 /* AcornAnalyser.cpp */; };
|
||||||
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; };
|
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; };
|
||||||
|
4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE77A2C1D84ADFB00BC3827 /* File.cpp */; };
|
||||||
4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */; };
|
4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */; };
|
||||||
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; };
|
4BEE0A701D72496600532C7B /* PRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6D1D72496600532C7B /* PRG.cpp */; };
|
||||||
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; };
|
4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; };
|
||||||
@ -786,6 +787,8 @@
|
|||||||
4BD328FD1D7E3EB5003B8C44 /* TapeParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = TapeParser.hpp; path = ../../StaticAnalyser/TapeParser.hpp; sourceTree = "<group>"; };
|
4BD328FD1D7E3EB5003B8C44 /* TapeParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = TapeParser.hpp; path = ../../StaticAnalyser/TapeParser.hpp; sourceTree = "<group>"; };
|
||||||
4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = "<group>"; };
|
4BD5F1931D13528900631CD1 /* CSBestEffortUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSBestEffortUpdater.h; path = Updater/CSBestEffortUpdater.h; sourceTree = "<group>"; };
|
||||||
4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = "<group>"; };
|
4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = "<group>"; };
|
||||||
|
4BE77A2C1D84ADFB00BC3827 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = File.cpp; path = ../../StaticAnalyser/Commodore/File.cpp; sourceTree = "<group>"; };
|
||||||
|
4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = "<group>"; };
|
||||||
4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = "<group>"; };
|
4BEE0A6A1D72496600532C7B /* Cartridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cartridge.cpp; sourceTree = "<group>"; };
|
||||||
4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
|
4BEE0A6B1D72496600532C7B /* Cartridge.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cartridge.hpp; sourceTree = "<group>"; };
|
||||||
4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = "<group>"; };
|
4BEE0A6D1D72496600532C7B /* PRG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PRG.cpp; sourceTree = "<group>"; };
|
||||||
@ -1529,6 +1532,8 @@
|
|||||||
4BC830D01D6E7C690000A26F /* Tape.hpp */,
|
4BC830D01D6E7C690000A26F /* Tape.hpp */,
|
||||||
4BC5E4931D7EE0E0008CF980 /* Utilities.cpp */,
|
4BC5E4931D7EE0E0008CF980 /* Utilities.cpp */,
|
||||||
4BC5E4941D7EE0E0008CF980 /* Utilities.hpp */,
|
4BC5E4941D7EE0E0008CF980 /* Utilities.hpp */,
|
||||||
|
4BE77A2C1D84ADFB00BC3827 /* File.cpp */,
|
||||||
|
4BE77A2D1D84ADFB00BC3827 /* File.hpp */,
|
||||||
);
|
);
|
||||||
name = Commodore;
|
name = Commodore;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2055,6 +2060,7 @@
|
|||||||
4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */,
|
4BC830D11D6E7C690000A26F /* Tape.cpp in Sources */,
|
||||||
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */,
|
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */,
|
||||||
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */,
|
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */,
|
||||||
|
4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */,
|
||||||
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */,
|
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */,
|
||||||
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
|
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
|
||||||
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
|
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
|
||||||
|
@ -36,54 +36,25 @@ void StaticAnalyser::Commodore::AddTargets(
|
|||||||
// continue if there are any files
|
// continue if there are any files
|
||||||
if(files.size())
|
if(files.size())
|
||||||
{
|
{
|
||||||
bool is_basic = true;
|
target.tapes = tapes;
|
||||||
|
|
||||||
// decide whether this is a BASIC file based on the proposition that:
|
|
||||||
// (1) they're always relocatable; and
|
|
||||||
// (2) they have a per-line structure of:
|
|
||||||
// [4 bytes: address of start of next line]
|
|
||||||
// [4 bytes: this line number]
|
|
||||||
// ... null-terminated code ...
|
|
||||||
// (with a next line address of 0000 indicating end of program)ß
|
|
||||||
if(files.front().type != File::RelocatableProgram) is_basic = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint16_t line_address = 0;
|
|
||||||
int line_number = -1;
|
|
||||||
|
|
||||||
uint16_t starting_address = files.front().starting_address;
|
|
||||||
line_address = starting_address;
|
|
||||||
is_basic = false;
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
if(line_address - starting_address >= files.front().data.size() + 2) break;
|
|
||||||
|
|
||||||
uint16_t next_line_address = files.front().data[line_address - starting_address];
|
|
||||||
next_line_address |= files.front().data[line_address - starting_address + 1] << 8;
|
|
||||||
|
|
||||||
if(!next_line_address)
|
|
||||||
{
|
|
||||||
is_basic = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(next_line_address < line_address + 5) break;
|
|
||||||
|
|
||||||
if(line_address - starting_address >= files.front().data.size() + 5) break;
|
|
||||||
uint16_t next_line_number = files.front().data[line_address - starting_address + 2];
|
|
||||||
next_line_number |= files.front().data[line_address - starting_address + 3] << 8;
|
|
||||||
|
|
||||||
if(next_line_number <= line_number) break;
|
|
||||||
|
|
||||||
line_number = (uint16_t)next_line_number;
|
|
||||||
line_address = next_line_address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target.vic20.memory_model = Vic20MemoryModel::Unexpanded;
|
target.vic20.memory_model = Vic20MemoryModel::Unexpanded;
|
||||||
if(is_basic)
|
if(files.front().is_basic())
|
||||||
{
|
{
|
||||||
target.loadingCommand = "LOAD\"\",1,0\nRUN\n";
|
target.loadingCommand = "LOAD\"\",1,0\nRUN\n";
|
||||||
|
|
||||||
|
// make a first guess based on file size
|
||||||
|
size_t file_size = files.front().data.size();
|
||||||
|
if(file_size > 6655) target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
||||||
|
else if(file_size > 3583) target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
||||||
|
else target.vic20.memory_model = Vic20MemoryModel::Unexpanded;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: this is machine code. So, ummm?
|
||||||
|
printf("Need to deal with machine code from %04x to %04x???\n", files.front().starting_address, files.front().ending_address);
|
||||||
|
target.loadingCommand = "LOAD\"\",1,1\nRUN\n";
|
||||||
|
|
||||||
// make a first guess based on loading address
|
// make a first guess based on loading address
|
||||||
switch(files.front().starting_address)
|
switch(files.front().starting_address)
|
||||||
{
|
{
|
||||||
@ -96,30 +67,49 @@ void StaticAnalyser::Commodore::AddTargets(
|
|||||||
target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// An unexpanded machine has 3583 bytes free for BASIC;
|
|
||||||
// a 3kb expanded machine has 6655 bytes free.
|
|
||||||
|
|
||||||
// we'll be relocating though, so up size if necessary
|
// General approach: increase memory size conservatively such that the largest file found will fit.
|
||||||
size_t file_size = files.front().data.size();
|
for(File &file : files)
|
||||||
if(file_size > 6655)
|
{
|
||||||
|
size_t file_size = file.data.size();
|
||||||
|
//bool is_basic = file.is_basic();
|
||||||
|
|
||||||
|
/*if(is_basic)
|
||||||
{
|
{
|
||||||
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
// BASIC files may be relocated, so the only limit is size.
|
||||||
}
|
//
|
||||||
else if(file_size > 3583)
|
// An unexpanded machine has 3583 bytes free for BASIC;
|
||||||
{
|
// a 3kb expanded machine has 6655 bytes free.
|
||||||
if(target.vic20.memory_model == Vic20MemoryModel::Unexpanded)
|
if(file_size > 6655)
|
||||||
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
||||||
|
else if(target.vic20.memory_model == Vic20MemoryModel::Unexpanded && file_size > 3583)
|
||||||
target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
target.vic20.memory_model = Vic20MemoryModel::EightKB;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{*/
|
||||||
{
|
// if(!file.type == File::NonRelocatableProgram)
|
||||||
// TODO: this is machine code. So, ummm?
|
// {
|
||||||
printf("Need to deal with machine code from %04x to %04x???\n", files.front().starting_address, files.front().ending_address);
|
// Non-BASIC files may be relocatable but, if so, by what logic?
|
||||||
target.loadingCommand = "LOAD\"\",1,1\nRUN\n";
|
// Given that this is unknown, take starting address as literal
|
||||||
}
|
// and check against memory windows.
|
||||||
|
//
|
||||||
|
// (ignoring colour memory...)
|
||||||
|
// An unexpanded Vic has memory between 0x0000 and 0x0400; and between 0x1000 and 0x2000.
|
||||||
|
// A 3kb expanded Vic fills in the gap and has memory between 0x0000 and 0x2000.
|
||||||
|
// A 32kb expanded Vic has memory in the entire low 32kb.
|
||||||
|
uint16_t starting_address = file.starting_address;
|
||||||
|
|
||||||
target.tapes = tapes;
|
// If anything above the 8kb mark is touched, mark as a 32kb machine; otherwise if the
|
||||||
|
// region 0x0400 to 0x1000 is touched and this is an unexpanded machine, mark as 3kb.
|
||||||
|
if(starting_address + file_size > 0x2000)
|
||||||
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
||||||
|
else if(target.vic20.memory_model == Vic20MemoryModel::Unexpanded && !(starting_address >= 0x1000 || starting_address+file_size < 0x0400))
|
||||||
|
target.vic20.memory_model = Vic20MemoryModel::ThirtyTwoKB;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
StaticAnalyser/Commodore/File.cpp
Normal file
50
StaticAnalyser/Commodore/File.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// File.cpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 10/09/2016.
|
||||||
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "File.hpp"
|
||||||
|
|
||||||
|
bool StaticAnalyser::Commodore::File::is_basic()
|
||||||
|
{
|
||||||
|
// BASIC files are always relocatable (?)
|
||||||
|
if(type != File::RelocatableProgram) return false;
|
||||||
|
|
||||||
|
uint16_t line_address = starting_address;
|
||||||
|
int line_number = -1;
|
||||||
|
|
||||||
|
// decide whether this is a BASIC file based on the proposition that:
|
||||||
|
// (1) they're always relocatable; and
|
||||||
|
// (2) they have a per-line structure of:
|
||||||
|
// [4 bytes: address of start of next line]
|
||||||
|
// [4 bytes: this line number]
|
||||||
|
// ... null-terminated code ...
|
||||||
|
// (with a next line address of 0000 indicating end of program)ß
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
if(line_address - starting_address >= data.size() + 2) break;
|
||||||
|
|
||||||
|
uint16_t next_line_address = data[line_address - starting_address];
|
||||||
|
next_line_address |= data[line_address - starting_address + 1] << 8;
|
||||||
|
|
||||||
|
if(!next_line_address)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(next_line_address < line_address + 5) break;
|
||||||
|
|
||||||
|
if(line_address - starting_address >= data.size() + 5) break;
|
||||||
|
uint16_t next_line_number = data[line_address - starting_address + 2];
|
||||||
|
next_line_number |= data[line_address - starting_address + 3] << 8;
|
||||||
|
|
||||||
|
if(next_line_number <= line_number) break;
|
||||||
|
|
||||||
|
line_number = (uint16_t)next_line_number;
|
||||||
|
line_address = next_line_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
36
StaticAnalyser/Commodore/File.hpp
Normal file
36
StaticAnalyser/Commodore/File.hpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// File.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 10/09/2016.
|
||||||
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef File_hpp
|
||||||
|
#define File_hpp
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace StaticAnalyser {
|
||||||
|
namespace Commodore {
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
std::wstring name;
|
||||||
|
std::vector<uint8_t> raw_name;
|
||||||
|
uint16_t starting_address;
|
||||||
|
uint16_t ending_address;
|
||||||
|
enum {
|
||||||
|
RelocatableProgram,
|
||||||
|
NonRelocatableProgram,
|
||||||
|
DataSequence,
|
||||||
|
} type;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
bool is_basic();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* File_hpp */
|
@ -11,23 +11,11 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "../StaticAnalyser.hpp"
|
#include "../StaticAnalyser.hpp"
|
||||||
|
#include "File.hpp"
|
||||||
|
|
||||||
namespace StaticAnalyser {
|
namespace StaticAnalyser {
|
||||||
namespace Commodore {
|
namespace Commodore {
|
||||||
|
|
||||||
struct File {
|
|
||||||
std::wstring name;
|
|
||||||
std::vector<uint8_t> raw_name;
|
|
||||||
uint16_t starting_address;
|
|
||||||
uint16_t ending_address;
|
|
||||||
enum {
|
|
||||||
RelocatableProgram,
|
|
||||||
NonRelocatableProgram,
|
|
||||||
DataSequence,
|
|
||||||
} type;
|
|
||||||
std::vector<uint8_t> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::list<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
std::list<File> GetFiles(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ CommodoreTAP::~CommodoreTAP()
|
|||||||
fclose(_file);
|
fclose(_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommodoreTAP::reset()
|
void CommodoreTAP::virtual_reset()
|
||||||
{
|
{
|
||||||
fseek(_file, 0x14, SEEK_SET);
|
fseek(_file, 0x14, SEEK_SET);
|
||||||
_current_pulse.type = Pulse::High;
|
_current_pulse.type = Pulse::High;
|
||||||
@ -70,7 +70,7 @@ bool CommodoreTAP::is_at_end()
|
|||||||
return _is_at_end;
|
return _is_at_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::Tape::Tape::Pulse CommodoreTAP::get_next_pulse()
|
Storage::Tape::Tape::Pulse CommodoreTAP::virtual_get_next_pulse()
|
||||||
{
|
{
|
||||||
if(_is_at_end)
|
if(_is_at_end)
|
||||||
{
|
{
|
||||||
|
@ -33,11 +33,12 @@ class CommodoreTAP: public Tape {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// implemented to satisfy @c Tape
|
// implemented to satisfy @c Tape
|
||||||
Pulse get_next_pulse();
|
|
||||||
void reset();
|
|
||||||
bool is_at_end();
|
bool is_at_end();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void virtual_reset();
|
||||||
|
Pulse virtual_get_next_pulse();
|
||||||
|
|
||||||
FILE *_file;
|
FILE *_file;
|
||||||
bool _updated_layout;
|
bool _updated_layout;
|
||||||
uint32_t _file_size;
|
uint32_t _file_size;
|
||||||
|
@ -74,7 +74,7 @@ PRG::~PRG()
|
|||||||
if(_file) fclose(_file);
|
if(_file) fclose(_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::Tape::Tape::Pulse PRG::get_next_pulse()
|
Storage::Tape::Tape::Pulse PRG::virtual_get_next_pulse()
|
||||||
{
|
{
|
||||||
// these are all microseconds per pole
|
// these are all microseconds per pole
|
||||||
static const unsigned int leader_zero_length = 179;
|
static const unsigned int leader_zero_length = 179;
|
||||||
@ -100,7 +100,7 @@ Storage::Tape::Tape::Pulse PRG::get_next_pulse()
|
|||||||
return pulse;
|
return pulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PRG::reset()
|
void PRG::virtual_reset()
|
||||||
{
|
{
|
||||||
_bitPhase = 3;
|
_bitPhase = 3;
|
||||||
fseek(_file, 2, SEEK_SET);
|
fseek(_file, 2, SEEK_SET);
|
||||||
|
@ -35,11 +35,12 @@ class PRG: public Tape {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// implemented to satisfy @c Tape
|
// implemented to satisfy @c Tape
|
||||||
Pulse get_next_pulse();
|
|
||||||
void reset();
|
|
||||||
bool is_at_end();
|
bool is_at_end();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Pulse virtual_get_next_pulse();
|
||||||
|
void virtual_reset();
|
||||||
|
|
||||||
FILE *_file;
|
FILE *_file;
|
||||||
uint16_t _load_address;
|
uint16_t _load_address;
|
||||||
uint16_t _length;
|
uint16_t _length;
|
||||||
|
@ -102,7 +102,7 @@ UEF::~UEF()
|
|||||||
|
|
||||||
#pragma mark - Public methods
|
#pragma mark - Public methods
|
||||||
|
|
||||||
void UEF::reset()
|
void UEF::virtual_reset()
|
||||||
{
|
{
|
||||||
gzseek(_file, 12, SEEK_SET);
|
gzseek(_file, 12, SEEK_SET);
|
||||||
_is_at_end = false;
|
_is_at_end = false;
|
||||||
@ -114,7 +114,7 @@ bool UEF::is_at_end()
|
|||||||
return _is_at_end;
|
return _is_at_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::Tape::Tape::Pulse UEF::get_next_pulse()
|
Storage::Tape::Tape::Pulse UEF::virtual_get_next_pulse()
|
||||||
{
|
{
|
||||||
Pulse next_pulse;
|
Pulse next_pulse;
|
||||||
|
|
||||||
|
@ -35,11 +35,12 @@ class UEF : public Tape {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// implemented to satisfy @c Tape
|
// implemented to satisfy @c Tape
|
||||||
Pulse get_next_pulse();
|
|
||||||
void reset();
|
|
||||||
bool is_at_end();
|
bool is_at_end();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void virtual_reset();
|
||||||
|
Pulse virtual_get_next_pulse();
|
||||||
|
|
||||||
gzFile _file;
|
gzFile _file;
|
||||||
unsigned int _time_base;
|
unsigned int _time_base;
|
||||||
bool _is_at_end;
|
bool _is_at_end;
|
||||||
|
@ -11,15 +11,38 @@
|
|||||||
|
|
||||||
using namespace Storage::Tape;
|
using namespace Storage::Tape;
|
||||||
|
|
||||||
void Storage::Tape::Tape::seek(Time seek_time)
|
#pragma mark - Lifecycle
|
||||||
{
|
|
||||||
// TODO: as best we can
|
|
||||||
}
|
|
||||||
|
|
||||||
TapePlayer::TapePlayer(unsigned int input_clock_rate) :
|
TapePlayer::TapePlayer(unsigned int input_clock_rate) :
|
||||||
TimedEventLoop(input_clock_rate)
|
TimedEventLoop(input_clock_rate)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
#pragma mark - Seeking
|
||||||
|
|
||||||
|
void Storage::Tape::Tape::seek(Time &seek_time)
|
||||||
|
{
|
||||||
|
_current_time.set_zero();
|
||||||
|
_next_time.set_zero();
|
||||||
|
while(_next_time < seek_time) get_next_pulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Storage::Tape::Tape::reset()
|
||||||
|
{
|
||||||
|
_current_time.set_zero();
|
||||||
|
_next_time.set_zero();
|
||||||
|
virtual_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tape::Pulse Tape::get_next_pulse()
|
||||||
|
{
|
||||||
|
Tape::Pulse pulse = virtual_get_next_pulse();
|
||||||
|
_current_time = _next_time;
|
||||||
|
_next_time += pulse.length;
|
||||||
|
return pulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Player
|
||||||
|
|
||||||
void TapePlayer::set_tape(std::shared_ptr<Storage::Tape::Tape> tape)
|
void TapePlayer::set_tape(std::shared_ptr<Storage::Tape::Tape> tape)
|
||||||
{
|
{
|
||||||
_tape = tape;
|
_tape = tape;
|
||||||
|
@ -38,12 +38,31 @@ class Tape {
|
|||||||
Pulse() {}
|
Pulse() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual Pulse get_next_pulse() = 0;
|
/*!
|
||||||
|
If at the start of the tape returns the first stored pulse. Otherwise advances past
|
||||||
|
the last-returned pulse and returns the next.
|
||||||
|
|
||||||
virtual void reset() = 0;
|
@returns the pulse that begins at the current cursor position.
|
||||||
|
*/
|
||||||
|
Pulse get_next_pulse();
|
||||||
|
|
||||||
|
/// Returns the tape to the beginning.
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// @returns @c true if the tape has progressed beyond all recorded content; @c false otherwise.
|
||||||
virtual bool is_at_end() = 0;
|
virtual bool is_at_end() = 0;
|
||||||
|
|
||||||
virtual void seek(Time seek_time); // TODO
|
/// @returns the amount of time preceeding the most recently-returned pulse.
|
||||||
|
virtual Time get_current_time() { return _current_time; }
|
||||||
|
|
||||||
|
/// Advances or reverses the tape to the last time before or at @c time from which a pulse starts.
|
||||||
|
virtual void seek(Time &time);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Time _current_time, _next_time;
|
||||||
|
|
||||||
|
virtual Pulse virtual_get_next_pulse() = 0;
|
||||||
|
virtual void virtual_reset() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user