mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Merge branch 'master' into WD1770
This commit is contained in:
commit
0e44cfa8a1
@ -272,29 +272,26 @@ void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data)
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::set_prg(const char *file_name, size_t length, const uint8_t *data)
|
||||
{
|
||||
// TEST!
|
||||
StaticAnalyser::GetTargets(file_name);
|
||||
|
||||
if(length > 2)
|
||||
{
|
||||
_rom_address = (uint16_t)(data[0] | (data[1] << 8));
|
||||
_rom_length = (uint16_t)(length - 2);
|
||||
|
||||
// install in the ROM area if this looks like a ROM; otherwise put on tape and throw into that mechanism
|
||||
if(_rom_address == 0xa000)
|
||||
{
|
||||
_rom = new uint8_t[0x2000];
|
||||
memcpy(_rom, &data[2], length - 2);
|
||||
write_to_map(_processorReadMemoryMap, _rom, _rom_address, 0x2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_tape(std::shared_ptr<Storage::Tape::Tape>(new Storage::Tape::PRG(file_name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
//void Machine::set_prg(const char *file_name, size_t length, const uint8_t *data)
|
||||
//{
|
||||
// if(length > 2)
|
||||
// {
|
||||
// _rom_address = (uint16_t)(data[0] | (data[1] << 8));
|
||||
// _rom_length = (uint16_t)(length - 2);
|
||||
//
|
||||
// // install in the ROM area if this looks like a ROM; otherwise put on tape and throw into that mechanism
|
||||
// if(_rom_address == 0xa000)
|
||||
// {
|
||||
// _rom = new uint8_t[0x2000];
|
||||
// memcpy(_rom, &data[2], length - 2);
|
||||
// write_to_map(_processorReadMemoryMap, _rom, _rom_address, 0x2000);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// set_tape(std::shared_ptr<Storage::Tape::Tape>(new Storage::Tape::PRG(file_name)));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
#pragma mar - Tape
|
||||
|
||||
@ -305,6 +302,21 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target)
|
||||
_tape.set_tape(target.tapes.front());
|
||||
}
|
||||
|
||||
if(target.disks.size())
|
||||
{
|
||||
// construct the 1540
|
||||
_c1540.reset(new ::Commodore::C1540::Machine);
|
||||
|
||||
// attach it to the serial bus
|
||||
_c1540->set_serial_bus(_serialBus);
|
||||
|
||||
// hand it the disk
|
||||
_c1540->set_disk(target.disks.front());
|
||||
|
||||
// install the ROM if it was previously set
|
||||
install_disk_rom();
|
||||
}
|
||||
|
||||
if(_should_automatically_load_media)
|
||||
{
|
||||
if(target.loadingCommand.length()) // TODO: and automatic loading option enabled
|
||||
@ -327,11 +339,11 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target)
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::set_tape(std::shared_ptr<Storage::Tape::Tape> tape)
|
||||
{
|
||||
//void Machine::set_tape(std::shared_ptr<Storage::Tape::Tape> tape)
|
||||
//{
|
||||
// _tape.set_tape(tape);
|
||||
// if(_should_automatically_load_media) set_typer_for_string("LOAD\nRUN\n");
|
||||
}
|
||||
//}
|
||||
|
||||
void Machine::tape_did_change_input(Tape *tape)
|
||||
{
|
||||
@ -340,7 +352,7 @@ void Machine::tape_did_change_input(Tape *tape)
|
||||
|
||||
#pragma mark - Disc
|
||||
|
||||
void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk)
|
||||
/*void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk)
|
||||
{
|
||||
// construct the 1540
|
||||
_c1540.reset(new ::Commodore::C1540::Machine);
|
||||
@ -355,7 +367,7 @@ void Machine::set_disk(std::shared_ptr<Storage::Disk::Disk> disk)
|
||||
install_disk_rom();
|
||||
|
||||
if(_should_automatically_load_media) set_typer_for_string("LOAD\"*\",8,1\nRUN\n");
|
||||
}
|
||||
}*/
|
||||
|
||||
void Machine::install_disk_rom()
|
||||
{
|
||||
|
@ -263,9 +263,9 @@ class Machine:
|
||||
|
||||
void set_rom(ROMSlot slot, size_t length, const uint8_t *data);
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
void set_prg(const char *file_name, size_t length, const uint8_t *data);
|
||||
void set_tape(std::shared_ptr<Storage::Tape::Tape> tape);
|
||||
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk);
|
||||
// void set_prg(const char *file_name, size_t length, const uint8_t *data);
|
||||
// void set_tape(std::shared_ptr<Storage::Tape::Tape> tape);
|
||||
// void set_disk(std::shared_ptr<Storage::Disk::Disk> disk);
|
||||
|
||||
void set_key_state(Key key, bool isPressed) { _keyboardVIA->set_key_state(key, isPressed); }
|
||||
void clear_all_keys() { _keyboardVIA->clear_all_keys(); }
|
||||
|
@ -1,36 +0,0 @@
|
||||
//
|
||||
// Factors.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 29/07/2016.
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Factors.hpp"
|
||||
|
||||
unsigned int NumberTheory::greatest_common_divisor(unsigned int a, unsigned int b)
|
||||
{
|
||||
if(a < b)
|
||||
{
|
||||
unsigned int swap = b;
|
||||
b = a;
|
||||
a = swap;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(!a) return b;
|
||||
if(!b) return a;
|
||||
|
||||
unsigned int remainder = a%b;
|
||||
a = b;
|
||||
b = remainder;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NumberTheory::least_common_multiple(unsigned int a, unsigned int b)
|
||||
{
|
||||
if(a == b) return a;
|
||||
|
||||
unsigned int gcd = greatest_common_divisor(a, b);
|
||||
return (a / gcd) * (b / gcd) * gcd;
|
||||
}
|
@ -13,13 +13,33 @@ namespace NumberTheory {
|
||||
/*!
|
||||
@returns The greatest common divisor of @c a and @c b as computed by Euclid's algorithm.
|
||||
*/
|
||||
unsigned int greatest_common_divisor(unsigned int a, unsigned int b);
|
||||
template<class T> T greatest_common_divisor(T a, T b) {
|
||||
if(a < b) {
|
||||
T swap = b;
|
||||
b = a;
|
||||
a = swap;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
if(!a) return b;
|
||||
if(!b) return a;
|
||||
|
||||
T remainder = a%b;
|
||||
a = b;
|
||||
b = remainder;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns The least common multiple of @c a and @c b computed indirectly via Euclid's greatest
|
||||
common divisor algorithm.
|
||||
*/
|
||||
unsigned int least_common_multiple(unsigned int a, unsigned int b);
|
||||
template<class T> T least_common_multiple(T a, T b) {
|
||||
if(a == b) return a;
|
||||
|
||||
T gcd = greatest_common_divisor<T>(a, b);
|
||||
return (a / gcd) * (b / gcd) * gcd;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* Factors_hpp */
|
||||
|
@ -322,7 +322,6 @@
|
||||
4BB299F71B587D8400A49093 /* txan in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298EB1B587D8400A49093 /* txan */; };
|
||||
4BB299F81B587D8400A49093 /* txsn in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298EC1B587D8400A49093 /* txsn */; };
|
||||
4BB299F91B587D8400A49093 /* tyan in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298ED1B587D8400A49093 /* tyan */; };
|
||||
4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C51D4B558F00248BDF /* Factors.cpp */; };
|
||||
4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; };
|
||||
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; };
|
||||
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; };
|
||||
@ -737,7 +736,6 @@
|
||||
4BB298EB1B587D8400A49093 /* txan */ = {isa = PBXFileReference; lastKnownFileType = file; path = txan; sourceTree = "<group>"; };
|
||||
4BB298EC1B587D8400A49093 /* txsn */ = {isa = PBXFileReference; lastKnownFileType = file; path = txsn; sourceTree = "<group>"; };
|
||||
4BB298ED1B587D8400A49093 /* tyan */ = {isa = PBXFileReference; lastKnownFileType = file; path = tyan; sourceTree = "<group>"; };
|
||||
4BB697C51D4B558F00248BDF /* Factors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Factors.cpp; path = ../../NumberTheory/Factors.cpp; sourceTree = "<group>"; };
|
||||
4BB697C61D4B558F00248BDF /* Factors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Factors.hpp; path = ../../NumberTheory/Factors.hpp; sourceTree = "<group>"; };
|
||||
4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = "<group>"; };
|
||||
4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = "<group>"; };
|
||||
@ -1392,7 +1390,6 @@
|
||||
4BB697C81D4B559300248BDF /* NumberTheory */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BB697C51D4B558F00248BDF /* Factors.cpp */,
|
||||
4BB697C61D4B558F00248BDF /* Factors.hpp */,
|
||||
);
|
||||
name = NumberTheory;
|
||||
@ -1490,13 +1487,13 @@
|
||||
4BB73EDC1B587CA500552FC2 /* Machines */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4DC81D1D2C2425003C5BF8 /* Commodore */,
|
||||
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */,
|
||||
4B2E2D961C3A06EC00138695 /* Atari2600 */,
|
||||
4B2E2D9E1C3A070900138695 /* Electron */,
|
||||
4B1E85731D170228001EF87D /* Typer.cpp */,
|
||||
4B1E85741D170228001EF87D /* Typer.hpp */,
|
||||
4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */,
|
||||
4B046DC31CFE651500E9E45E /* CRTMachine.hpp */,
|
||||
4B1E85741D170228001EF87D /* Typer.hpp */,
|
||||
4B2E2D961C3A06EC00138695 /* Atari2600 */,
|
||||
4B4DC81D1D2C2425003C5BF8 /* Commodore */,
|
||||
4B2E2D9E1C3A070900138695 /* Electron */,
|
||||
);
|
||||
name = Machines;
|
||||
path = ../../Machines;
|
||||
@ -2076,7 +2073,6 @@
|
||||
4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */,
|
||||
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */,
|
||||
4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */,
|
||||
4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */,
|
||||
4BA799951D8B656E0045123D /* StaticAnalyser.cpp in Sources */,
|
||||
4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */,
|
||||
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */,
|
||||
|
@ -30,11 +30,6 @@ typedef NS_ENUM(NSInteger, CSVic20MemorySize)
|
||||
- (void)setCharactersROM:(nonnull NSData *)rom;
|
||||
- (void)setDriveROM:(nonnull NSData *)rom;
|
||||
|
||||
- (BOOL)openPRGAtURL:(nonnull NSURL *)URL;
|
||||
- (BOOL)openTAPAtURL:(nonnull NSURL *)URL;
|
||||
- (BOOL)openG64AtURL:(nonnull NSURL *)URL;
|
||||
- (BOOL)openD64AtURL:(nonnull NSURL *)URL;
|
||||
|
||||
@property (nonatomic, assign) BOOL useFastLoadingHack;
|
||||
@property (nonatomic, assign) BOOL shouldLoadAutomatically;
|
||||
@property (nonatomic, assign) CSVic20Region region;
|
||||
|
@ -46,54 +46,6 @@ using namespace Commodore::Vic20;
|
||||
[self setROM:rom slot:Drive];
|
||||
}
|
||||
|
||||
- (BOOL)openTAPAtURL:(NSURL *)URL {
|
||||
@synchronized(self) {
|
||||
try {
|
||||
std::shared_ptr<Storage::Tape::CommodoreTAP> tape(new Storage::Tape::CommodoreTAP([URL fileSystemRepresentation]));
|
||||
_vic20.set_tape(tape);
|
||||
return YES;
|
||||
} catch(...) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)openG64AtURL:(NSURL *)URL {
|
||||
return [self openDisk:^std::shared_ptr<Storage::Disk::Disk>{
|
||||
return std::shared_ptr<Storage::Disk::Disk>(new Storage::Disk::G64([URL fileSystemRepresentation]));
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)openD64AtURL:(NSURL *)URL {
|
||||
return [self openDisk:^std::shared_ptr<Storage::Disk::Disk>{
|
||||
return std::shared_ptr<Storage::Disk::Disk>(new Storage::Disk::D64([URL fileSystemRepresentation]));
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)openDisk:(std::shared_ptr<Storage::Disk::Disk> (^)())opener {
|
||||
@synchronized(self) {
|
||||
try {
|
||||
std::shared_ptr<Storage::Disk::Disk> disk = opener();
|
||||
_vic20.set_disk(disk);
|
||||
return YES;
|
||||
} catch(...) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)openPRGAtURL:(NSURL *)URL {
|
||||
NSData *prg = [NSData dataWithContentsOfURL:URL];
|
||||
@synchronized(self) {
|
||||
try {
|
||||
_vic20.set_prg(URL.fileSystemRepresentation, prg.length, (const uint8_t *)prg.bytes);
|
||||
return YES;
|
||||
} catch(...) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed {
|
||||
static NSDictionary<NSNumber *, NSNumber *> *vicKeysByKeys = @{
|
||||
@(VK_ANSI_1): @(Key::Key1), @(VK_ANSI_2): @(Key::Key2),
|
||||
|
@ -38,7 +38,7 @@ class CommodoreGCRParser: public Storage::Disk::Drive {
|
||||
|
||||
@returns a sector if one was found; @c nullptr otherwise.
|
||||
*/
|
||||
std::unique_ptr<Sector> get_sector(uint8_t track, uint8_t sector)
|
||||
std::shared_ptr<Sector> get_sector(uint8_t track, uint8_t sector)
|
||||
{
|
||||
int difference = (int)track - (int)track_;
|
||||
track_ = track;
|
||||
@ -65,6 +65,7 @@ class CommodoreGCRParser: public Storage::Disk::Drive {
|
||||
int index_count_;
|
||||
int bit_count_;
|
||||
uint8_t track_;
|
||||
std::shared_ptr<Sector> sector_cache_[65536];
|
||||
|
||||
void process_input_bit(int value, unsigned int cycles_since_index_hole)
|
||||
{
|
||||
@ -115,23 +116,26 @@ class CommodoreGCRParser: public Storage::Disk::Drive {
|
||||
index_count_++;
|
||||
}
|
||||
|
||||
std::unique_ptr<Sector> get_sector(uint8_t sector)
|
||||
std::shared_ptr<Sector> get_sector(uint8_t sector)
|
||||
{
|
||||
std::unique_ptr<Sector> first_sector = get_next_sector();
|
||||
uint16_t sector_address = (uint16_t)((track_ << 8) | sector);
|
||||
if(sector_cache_[sector_address]) return sector_cache_[sector_address];
|
||||
|
||||
std::shared_ptr<Sector> first_sector = get_next_sector();
|
||||
if(!first_sector) return first_sector;
|
||||
if(first_sector->sector == sector) return first_sector;
|
||||
|
||||
while(1)
|
||||
{
|
||||
std::unique_ptr<Sector> next_sector = get_next_sector();
|
||||
std::shared_ptr<Sector> next_sector = get_next_sector();
|
||||
if(next_sector->sector == first_sector->sector) return nullptr;
|
||||
if(next_sector->sector == sector) return next_sector;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Sector> get_next_sector()
|
||||
std::shared_ptr<Sector> get_next_sector()
|
||||
{
|
||||
std::unique_ptr<Sector> sector(new Sector);
|
||||
std::shared_ptr<Sector> sector(new Sector);
|
||||
index_count_ = 0;
|
||||
|
||||
while(index_count_ < 2)
|
||||
@ -166,7 +170,12 @@ class CommodoreGCRParser: public Storage::Disk::Drive {
|
||||
checksum ^= sector->data[c];
|
||||
}
|
||||
|
||||
if(checksum == get_next_byte()) return sector;
|
||||
if(checksum == get_next_byte())
|
||||
{
|
||||
uint16_t sector_address = (uint16_t)((sector->track << 8) | sector->sector);
|
||||
sector_cache_[sector_address] = sector;
|
||||
return sector;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -180,7 +189,7 @@ std::list<File> StaticAnalyser::Commodore::GetFiles(const std::shared_ptr<Storag
|
||||
parser.set_disk(disk);
|
||||
|
||||
// find any sector whatsoever to establish the current track
|
||||
std::unique_ptr<CommodoreGCRParser::Sector> sector;
|
||||
std::shared_ptr<CommodoreGCRParser::Sector> sector;
|
||||
|
||||
// assemble directory
|
||||
std::vector<uint8_t> directory;
|
||||
|
@ -85,11 +85,14 @@ void Drive::run_for_cycles(int number_of_cycles)
|
||||
if(has_disk())
|
||||
{
|
||||
number_of_cycles *= _clock_rate_multiplier;
|
||||
while(number_of_cycles--)
|
||||
while(number_of_cycles)
|
||||
{
|
||||
_cycles_since_index_hole ++;
|
||||
_pll->run_for_cycles(1);
|
||||
TimedEventLoop::run_for_cycles(1);
|
||||
int cycles_until_next_event = (int)get_cycles_until_next_event();
|
||||
int cycles_to_run_for = std::min(cycles_until_next_event, number_of_cycles);
|
||||
_cycles_since_index_hole += (unsigned int)cycles_to_run_for;
|
||||
number_of_cycles -= cycles_to_run_for;
|
||||
_pll->run_for_cycles(cycles_to_run_for);
|
||||
TimedEventLoop::run_for_cycles(cycles_to_run_for);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,7 @@
|
||||
static float gzgetfloat(gzFile file)
|
||||
{
|
||||
uint8_t bytes[4];
|
||||
bytes[0] = (uint8_t)gzgetc(file);
|
||||
bytes[1] = (uint8_t)gzgetc(file);
|
||||
bytes[2] = (uint8_t)gzgetc(file);
|
||||
bytes[3] = (uint8_t)gzgetc(file);
|
||||
gzread(file, bytes, 4);
|
||||
|
||||
/* assume a four byte array named Float exists, where Float[0]
|
||||
was the first byte read from the UEF, Float[1] the second, etc */
|
||||
@ -45,25 +42,33 @@ static float gzgetfloat(gzFile file)
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t gzget8(gzFile file)
|
||||
{
|
||||
// This is a workaround for gzgetc, which seems to be broken in ZLib 1.2.8.
|
||||
uint8_t result;
|
||||
gzread(file, &result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int gzget16(gzFile file)
|
||||
{
|
||||
int result = gzgetc(file);
|
||||
result |= (gzgetc(file) << 8);
|
||||
return result;
|
||||
uint8_t bytes[2];
|
||||
gzread(file, bytes, 2);
|
||||
return bytes[0] | (bytes[1] << 8);
|
||||
}
|
||||
|
||||
static int gzget24(gzFile file)
|
||||
{
|
||||
int result = gzget16(file);
|
||||
result |= (gzgetc(file) << 16);
|
||||
return result;
|
||||
uint8_t bytes[3];
|
||||
gzread(file, bytes, 3);
|
||||
return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16);
|
||||
}
|
||||
|
||||
static int gzget32(gzFile file)
|
||||
{
|
||||
int result = gzget16(file);
|
||||
result |= (gzget16(file) << 16);
|
||||
return result;
|
||||
uint8_t bytes[4];
|
||||
gzread(file, bytes, 4);
|
||||
return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
|
||||
}
|
||||
|
||||
using namespace Storage::Tape;
|
||||
@ -83,11 +88,10 @@ UEF::UEF(const char *file_name) :
|
||||
throw ErrorNotUEF;
|
||||
}
|
||||
|
||||
int minor, major;
|
||||
minor = gzgetc(_file);
|
||||
major = gzgetc(_file);
|
||||
uint8_t version[2];
|
||||
gzread(_file, version, 2);
|
||||
|
||||
if(major > 0 || minor > 10 || major < 0 || minor < 0)
|
||||
if(version[1] > 0 || version[0] > 10)
|
||||
{
|
||||
throw ErrorNotUEF;
|
||||
}
|
||||
@ -199,17 +203,17 @@ void UEF::queue_implicit_bit_pattern(uint32_t length)
|
||||
{
|
||||
while(length--)
|
||||
{
|
||||
queue_implicit_byte((uint8_t)gzgetc(_file));
|
||||
queue_implicit_byte(gzget8(_file));
|
||||
}
|
||||
}
|
||||
|
||||
void UEF::queue_explicit_bit_pattern(uint32_t length)
|
||||
{
|
||||
size_t length_in_bits = (length << 3) - (size_t)gzgetc(_file);
|
||||
size_t length_in_bits = (length << 3) - (size_t)gzget8(_file);
|
||||
uint8_t current_byte = 0;
|
||||
for(size_t bit = 0; bit < length_in_bits; bit++)
|
||||
{
|
||||
if(!(bit&7)) current_byte = (uint8_t)gzgetc(_file);
|
||||
if(!(bit&7)) current_byte = gzget8(_file);
|
||||
queue_bit(current_byte&1);
|
||||
current_byte >>= 1;
|
||||
}
|
||||
@ -250,13 +254,13 @@ void UEF::queue_carrier_tone_with_dummy()
|
||||
void UEF::queue_security_cycles()
|
||||
{
|
||||
int number_of_cycles = gzget24(_file);
|
||||
bool first_is_pulse = gzgetc(_file) == 'P';
|
||||
bool last_is_pulse = gzgetc(_file) == 'P';
|
||||
bool first_is_pulse = gzget8(_file) == 'P';
|
||||
bool last_is_pulse = gzget8(_file) == 'P';
|
||||
|
||||
uint8_t current_byte = 0;
|
||||
for(int cycle = 0; cycle < number_of_cycles; cycle++)
|
||||
{
|
||||
if(!(cycle&7)) current_byte = (uint8_t)gzgetc(_file);
|
||||
if(!(cycle&7)) current_byte = gzget8(_file);
|
||||
int bit = (current_byte >> 7);
|
||||
current_byte <<= 1;
|
||||
|
||||
@ -284,9 +288,9 @@ void UEF::queue_defined_data(uint32_t length)
|
||||
{
|
||||
if(length < 3) return;
|
||||
|
||||
int bits_per_packet = gzgetc(_file);
|
||||
char parity_type = (char)gzgetc(_file);
|
||||
int number_of_stop_bits = gzgetc(_file);
|
||||
int bits_per_packet = gzget8(_file);
|
||||
char parity_type = (char)gzget8(_file);
|
||||
int number_of_stop_bits = gzget8(_file);
|
||||
|
||||
bool has_extra_stop_wave = (number_of_stop_bits < 0);
|
||||
number_of_stop_bits = abs(number_of_stop_bits);
|
||||
@ -294,7 +298,7 @@ void UEF::queue_defined_data(uint32_t length)
|
||||
length -= 3;
|
||||
while(length--)
|
||||
{
|
||||
uint8_t byte = (uint8_t)gzgetc(_file);
|
||||
uint8_t byte = gzget8(_file);
|
||||
|
||||
uint8_t parity_value = byte;
|
||||
parity_value ^= (parity_value >> 4);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "TimedEventLoop.hpp"
|
||||
#include "../NumberTheory/Factors.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Storage;
|
||||
|
||||
@ -16,29 +17,27 @@ TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) :
|
||||
|
||||
void TimedEventLoop::run_for_cycles(int number_of_cycles)
|
||||
{
|
||||
_time_into_interval += (unsigned int)_stepper->step((uint64_t)number_of_cycles);
|
||||
while(_time_into_interval >= _event_interval.length)
|
||||
_cycles_until_event -= number_of_cycles;
|
||||
while(_cycles_until_event <= 0)
|
||||
{
|
||||
process_next_event();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int TimedEventLoop::get_cycles_until_next_event()
|
||||
{
|
||||
return (unsigned int)std::max(_cycles_until_event, 0);
|
||||
}
|
||||
|
||||
void TimedEventLoop::reset_timer()
|
||||
{
|
||||
_time_into_interval = 0;
|
||||
_stepper.reset();
|
||||
_subcycles_until_event.set_zero();
|
||||
_cycles_until_event = 0;
|
||||
}
|
||||
|
||||
void TimedEventLoop::reset_timer_to_offset(Time offset)
|
||||
{
|
||||
unsigned int common_clock_rate = NumberTheory::least_common_multiple(offset.clock_rate, _event_interval.clock_rate);
|
||||
_time_into_interval = offset.length * (common_clock_rate / offset.clock_rate);
|
||||
_event_interval.length *= common_clock_rate / _event_interval.clock_rate;
|
||||
_event_interval.clock_rate = common_clock_rate;
|
||||
if(common_clock_rate != _stepper->get_output_rate())
|
||||
{
|
||||
_stepper.reset(new SignalProcessing::Stepper(_event_interval.clock_rate, _input_clock_rate));
|
||||
}
|
||||
// TODO: apply
|
||||
}
|
||||
|
||||
void TimedEventLoop::jump_to_next_event()
|
||||
@ -49,43 +48,27 @@ void TimedEventLoop::jump_to_next_event()
|
||||
|
||||
void TimedEventLoop::set_next_event_time_interval(Time interval)
|
||||
{
|
||||
// figure out how much time has been run since the last bit ended
|
||||
if(_stepper)
|
||||
{
|
||||
_time_into_interval -= _event_interval.length;
|
||||
if(_time_into_interval)
|
||||
{
|
||||
// simplify the quotient
|
||||
unsigned int common_divisor = NumberTheory::greatest_common_divisor(_time_into_interval, _event_interval.clock_rate);
|
||||
_time_into_interval /= common_divisor;
|
||||
_event_interval.clock_rate /= common_divisor;
|
||||
// Calculate [interval]*[input clock rate] + [subcycles until this event].
|
||||
int64_t denominator = (int64_t)interval.clock_rate * (int64_t)_subcycles_until_event.clock_rate;
|
||||
int64_t numerator =
|
||||
(int64_t)_subcycles_until_event.clock_rate * (int64_t)_input_clock_rate * (int64_t)interval.length +
|
||||
(int64_t)interval.clock_rate * (int64_t)_subcycles_until_event.length;
|
||||
|
||||
// build a quotient that is the sum of the time overrun plus the incoming time and adjust the time overrun
|
||||
// to be in terms of the new quotient
|
||||
unsigned int denominator = NumberTheory::least_common_multiple(_event_interval.clock_rate, interval.clock_rate);
|
||||
interval.length *= denominator / interval.clock_rate;
|
||||
interval.clock_rate = denominator;
|
||||
_time_into_interval *= denominator / _event_interval.clock_rate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_time_into_interval = 0;
|
||||
}
|
||||
// Simplify now, to prepare for stuffing into possibly 32-bit quantities
|
||||
int64_t common_divisor = NumberTheory::greatest_common_divisor(numerator % denominator, denominator);
|
||||
denominator /= common_divisor;
|
||||
numerator /= common_divisor;
|
||||
|
||||
// store new interval
|
||||
_event_interval = interval;
|
||||
|
||||
// adjust stepper if required
|
||||
if(!_stepper || _event_interval.clock_rate != _stepper->get_output_rate())
|
||||
{
|
||||
_stepper.reset(new SignalProcessing::Stepper(_event_interval.clock_rate, _input_clock_rate));
|
||||
}
|
||||
// So this event will fire in the integral number of cycles from now, putting us at the remainder
|
||||
// number of subcycles
|
||||
_cycles_until_event = (int)(numerator / denominator);
|
||||
_subcycles_until_event.length = (unsigned int)(numerator % denominator);
|
||||
_subcycles_until_event.clock_rate = (unsigned int)denominator;
|
||||
}
|
||||
|
||||
Time TimedEventLoop::get_time_into_next_event()
|
||||
{
|
||||
Time result = _event_interval;
|
||||
result.length = _time_into_interval;
|
||||
return result;
|
||||
// TODO: calculate, presumably as [length of interval] - ([cycles left] + [subcycles left])
|
||||
Time zero;
|
||||
return zero;
|
||||
}
|
||||
|
@ -48,6 +48,11 @@ namespace Storage {
|
||||
*/
|
||||
void run_for_cycles(int number_of_cycles);
|
||||
|
||||
/*!
|
||||
@returns the number of whole cycles remaining until the next event is triggered.
|
||||
*/
|
||||
unsigned int get_cycles_until_next_event();
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Sets the time interval, as a proportion of a second, until the next event should be triggered.
|
||||
@ -86,9 +91,9 @@ namespace Storage {
|
||||
|
||||
private:
|
||||
unsigned int _input_clock_rate;
|
||||
int _cycles_until_event;
|
||||
Time _subcycles_until_event;
|
||||
Time _event_interval;
|
||||
std::unique_ptr<SignalProcessing::Stepper> _stepper;
|
||||
uint32_t _time_into_interval;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user