1
0
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:
Thomas Harte 2016-09-18 10:34:11 -04:00
commit 0e44cfa8a1
12 changed files with 160 additions and 217 deletions

View File

@ -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()
{

View File

@ -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(); }

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */,

View File

@ -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;

View File

@ -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),

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
};
}