1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Expands size of storage in Cycles/HalfCycles; adjusts widely to compensate.

This commit is contained in:
Thomas Harte 2019-10-29 22:36:29 -04:00
parent fd02b6fc18
commit 1c154131f9
55 changed files with 191 additions and 183 deletions

View File

@ -10,6 +10,7 @@
#define ClockReceiver_hpp
#include "ForceInline.hpp"
#include <cstdint>
/*
Informal pattern for all classes that run from a clock cycle:
@ -54,7 +55,9 @@
*/
template <class T> class WrappedInt {
public:
forceinline constexpr WrappedInt(int l) noexcept : length_(l) {}
using IntType = int64_t;
forceinline constexpr WrappedInt(IntType l) noexcept : length_(l) {}
forceinline constexpr WrappedInt() noexcept : length_(0) {}
forceinline T &operator =(const T &rhs) {
@ -133,7 +136,11 @@ template <class T> class WrappedInt {
forceinline constexpr bool operator !() const { return !length_; }
// bool operator () is not supported because it offers an implicit cast to int, which is prone silently to permit misuse
forceinline constexpr int as_int() const { return length_; }
/// @returns The underlying int, cast to an integral type of your choosing.
template<typename Type = IntType> forceinline constexpr Type as() { return Type(length_); }
/// @returns The underlying int, in its native form.
forceinline constexpr IntType as_integral() const { return length_; }
/*!
Severs from @c this the effect of dividing by @c divisor; @c this will end up with
@ -161,13 +168,13 @@ template <class T> class WrappedInt {
// classes that use this template.
protected:
int length_;
IntType length_;
};
/// Describes an integer number of whole cycles: pairs of clock signal transitions.
class Cycles: public WrappedInt<Cycles> {
public:
forceinline constexpr Cycles(int l) noexcept : WrappedInt<Cycles>(l) {}
forceinline constexpr Cycles(IntType l) noexcept : WrappedInt<Cycles>(l) {}
forceinline constexpr Cycles() noexcept : WrappedInt<Cycles>() {}
forceinline constexpr Cycles(const Cycles &cycles) noexcept : WrappedInt<Cycles>(cycles.length_) {}
@ -187,10 +194,10 @@ class Cycles: public WrappedInt<Cycles> {
/// Describes an integer number of half cycles: single clock signal transitions.
class HalfCycles: public WrappedInt<HalfCycles> {
public:
forceinline constexpr HalfCycles(int l) noexcept : WrappedInt<HalfCycles>(l) {}
forceinline constexpr HalfCycles(IntType l) noexcept : WrappedInt<HalfCycles>(l) {}
forceinline constexpr HalfCycles() noexcept : WrappedInt<HalfCycles>() {}
forceinline constexpr HalfCycles(const Cycles &cycles) noexcept : WrappedInt<HalfCycles>(cycles.as_int() * 2) {}
forceinline constexpr HalfCycles(const Cycles &cycles) noexcept : WrappedInt<HalfCycles>(cycles.as_integral() * 2) {}
forceinline constexpr HalfCycles(const HalfCycles &half_cycles) noexcept : WrappedInt<HalfCycles>(half_cycles.length_) {}
/// @returns The number of whole cycles completely covered by this span of half cycles.

View File

@ -107,7 +107,7 @@ void WD1770::run_for(const Cycles cycles) {
Storage::Disk::Controller::run_for(cycles);
if(delay_time_) {
unsigned int number_of_cycles = static_cast<unsigned int>(cycles.as_int());
const auto number_of_cycles = cycles.as_integral();
if(delay_time_ <= number_of_cycles) {
delay_time_ = 0;
posit_event(static_cast<int>(Event1770::Timer));
@ -286,7 +286,7 @@ void WD1770::posit_event(int new_event_type) {
goto verify;
}
get_drive().step(Storage::Disk::HeadPosition(step_direction_ ? 1 : -1));
unsigned int time_to_wait;
Cycles::IntType time_to_wait;
switch(command_ & 3) {
default:
case 0: time_to_wait = 6; break;

View File

@ -121,7 +121,7 @@ class WD1770: public Storage::Disk::MFMController {
void posit_event(int type);
int interesting_event_mask_;
int resume_point_ = 0;
unsigned int delay_time_ = 0;
Cycles::IntType delay_time_ = 0;
// ID buffer
uint8_t header_[6];

View File

@ -346,7 +346,7 @@ template <typename T> void MOS6522<T>::do_phase1() {
/*! Runs for a specified number of half cycles. */
template <typename T> void MOS6522<T>::run_for(const HalfCycles half_cycles) {
int number_of_half_cycles = half_cycles.as_int();
auto number_of_half_cycles = half_cycles.as_integral();
if(!number_of_half_cycles) return;
if(is_phase2_) {
@ -375,7 +375,7 @@ template <typename T> void MOS6522<T>::flush() {
/*! Runs for a specified number of cycles. */
template <typename T> void MOS6522<T>::run_for(const Cycles cycles) {
int number_of_cycles = cycles.as_int();
auto number_of_cycles = cycles.as_integral();
while(number_of_cycles--) {
do_phase1();
do_phase2();

View File

@ -107,7 +107,7 @@ template <class T> class MOS6532 {
}
inline void run_for(const Cycles cycles) {
unsigned int number_of_cycles = static_cast<unsigned int>(cycles.as_int());
unsigned int number_of_cycles = static_cast<unsigned int>(cycles.as_integral());
// permit counting _to_ zero; counting _through_ zero initiates the other behaviour
if(timer_.value >= number_of_cycles) {

View File

@ -170,7 +170,7 @@ template <class BusHandler> class MOS6560 {
// keep track of the amount of time since the speaker was updated; lazy updates are applied
cycles_since_speaker_update_ += cycles;
int number_of_cycles = cycles.as_int();
auto number_of_cycles = cycles.as_integral();
while(number_of_cycles--) {
// keep an old copy of the vertical count because that test is a cycle later than the actual changes
int previous_vertical_counter = vertical_counter_;

View File

@ -111,7 +111,7 @@ template <class T> class CRTC6845 {
}
void run_for(Cycles cycles) {
int cyles_remaining = cycles.as_int();
auto cyles_remaining = cycles.as_integral();
while(cyles_remaining--) {
// check for end of visible characters
if(character_counter_ == registers_[1]) {

View File

@ -15,8 +15,8 @@ const HalfCycles ACIA::SameAsTransmit;
ACIA::ACIA(HalfCycles transmit_clock_rate, HalfCycles receive_clock_rate) :
transmit_clock_rate_(transmit_clock_rate),
receive_clock_rate_((receive_clock_rate != SameAsTransmit) ? receive_clock_rate : transmit_clock_rate) {
transmit.set_writer_clock_rate(transmit_clock_rate.as_int());
request_to_send.set_writer_clock_rate(transmit_clock_rate.as_int());
transmit.set_writer_clock_rate(transmit_clock_rate);
request_to_send.set_writer_clock_rate(transmit_clock_rate);
}
uint8_t ACIA::read(int address) {
@ -84,7 +84,7 @@ void ACIA::write(int address, uint8_t value) {
transmit.write(false);
break;
}
receive.set_read_delegate(this, Storage::Time(divider_ * 2, receive_clock_rate_.as_int()));
receive.set_read_delegate(this, Storage::Time(divider_ * 2, int(receive_clock_rate_.as_integral())));
receive_interrupt_enabled_ = value & 0x80;
}
}
@ -92,27 +92,24 @@ void ACIA::write(int address, uint8_t value) {
}
void ACIA::run_for(HalfCycles length) {
// Transmission.
const int transmit_advance = length.as_int();
if(transmit.transmission_data_time_remaining()) {
if(transmit.transmission_data_time_remaining() > HalfCycles(0)) {
const auto write_data_time_remaining = transmit.write_data_time_remaining();
// There's at most one further byte available to enqueue, so a single 'if'
// rather than a 'while' is correct here. It's the responsibilit of the caller
// to ensure run_for lengths are appropriate for longer sequences.
if(transmit_advance >= write_data_time_remaining) {
if(length >= write_data_time_remaining) {
if(next_transmission_ != NoValueMask) {
transmit.advance_writer(write_data_time_remaining);
consider_transmission();
transmit.advance_writer(transmit_advance - write_data_time_remaining);
transmit.advance_writer(length - write_data_time_remaining);
} else {
transmit.advance_writer(transmit_advance);
transmit.advance_writer(length);
update_clocking_observer();
if(transmit_interrupt_enabled_) add_interrupt_cause(TransmitNeedsWrite);
}
} else {
transmit.advance_writer(transmit_advance);
transmit.advance_writer(length);
}
}
}

View File

@ -207,7 +207,7 @@ void MFP68901::run_for(HalfCycles time) {
cycles_left_ += time;
// TODO: this is the stupidest possible implementation. Improve.
int cycles = cycles_left_.flush<Cycles>().as_int();
int cycles = int(cycles_left_.flush<Cycles>().as_integral());
while(cycles--) {
for(int c = 0; c < 4; ++c) {
if(timers_[c].mode >= TimerMode::Delay) {

View File

@ -95,11 +95,11 @@ void i8272::run_for(Cycles cycles) {
// check for an expired timer
if(delay_time_ > 0) {
if(cycles.as_int() >= delay_time_) {
if(cycles.as_integral() >= delay_time_) {
delay_time_ = 0;
posit_event(static_cast<int>(Event8272::Timer));
} else {
delay_time_ -= cycles.as_int();
delay_time_ -= cycles.as_integral();
}
}
@ -108,8 +108,8 @@ void i8272::run_for(Cycles cycles) {
int drives_left = drives_seeking_;
for(int c = 0; c < 4; c++) {
if(drives_[c].phase == Drive::Seeking) {
drives_[c].step_rate_counter += cycles.as_int();
int steps = drives_[c].step_rate_counter / (8000 * step_rate_time_);
drives_[c].step_rate_counter += cycles.as_integral();
auto steps = drives_[c].step_rate_counter / (8000 * step_rate_time_);
drives_[c].step_rate_counter %= (8000 * step_rate_time_);
while(steps--) {
// Perform a step.
@ -141,12 +141,12 @@ void i8272::run_for(Cycles cycles) {
int head = c&1;
if(drives_[drive].head_unload_delay[head] > 0) {
if(cycles.as_int() >= drives_[drive].head_unload_delay[head]) {
if(cycles.as_integral() >= drives_[drive].head_unload_delay[head]) {
drives_[drive].head_unload_delay[head] = 0;
drives_[drive].head_is_loaded[head] = false;
head_timers_running_--;
} else {
drives_[drive].head_unload_delay[head] -= cycles.as_int();
drives_[drive].head_unload_delay[head] -= cycles.as_integral();
}
timers_left--;
if(!timers_left) break;

View File

@ -73,7 +73,7 @@ class i8272 : public Storage::Disk::MFMController {
bool is_access_command_ = false;
// The counter used for ::Timer events.
int delay_time_ = 0;
Cycles::IntType delay_time_ = 0;
// The connected drives.
struct Drive {
@ -89,12 +89,12 @@ class i8272 : public Storage::Disk::MFMController {
bool seek_failed = false;
// Seeking: transient state.
int step_rate_counter = 0;
Cycles::IntType step_rate_counter = 0;
int steps_taken = 0;
int target_head_position = 0; // either an actual number, or -1 to indicate to step until track zero
// Head state.
int head_unload_delay[2] = {0, 0};
Cycles::IntType head_unload_delay[2] = {0, 0};
bool head_is_loaded[2] = {false, false};
} drives_[4];

View File

@ -166,7 +166,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
// Convert 456 clocked half cycles per line to 342 internal cycles per line;
// the internal clock is 1.5 times the nominal 3.579545 Mhz that I've advertised
// for this part. So multiply by three quarters.
int int_cycles = (cycles.as_int() * 3) + cycles_error_;
int int_cycles = int(cycles.as_integral() * 3) + cycles_error_;
cycles_error_ = int_cycles & 3;
int_cycles >>= 2;
if(!int_cycles) return;

View File

@ -78,7 +78,7 @@ void DiskII::select_drive(int drive) {
void DiskII::run_for(const Cycles cycles) {
if(preferred_clocking() == ClockingHint::Preference::None) return;
int integer_cycles = cycles.as_int();
auto integer_cycles = cycles.as_integral();
while(integer_cycles--) {
const int address = (state_ & 0xf0) | inputs_ | ((shift_register_&0x80) >> 6);
if(flux_duration_) {
@ -124,7 +124,7 @@ void DiskII::run_for(const Cycles cycles) {
// motor switch being flipped and the drive motor actually switching off.
// This models that, accepting overrun as a risk.
if(motor_off_time_ >= 0) {
motor_off_time_ -= cycles.as_int();
motor_off_time_ -= cycles.as_integral();
if(motor_off_time_ < 0) {
set_control(Control::Motor, false);
}
@ -266,7 +266,7 @@ int DiskII::read_address(int address) {
break;
case 0xf:
if(!(inputs_ & input_mode))
drives_[active_drive_].begin_writing(Storage::Time(1, clock_rate_), false);
drives_[active_drive_].begin_writing(Storage::Time(1, int(clock_rate_)), false);
inputs_ |= input_mode;
break;
}

View File

@ -101,7 +101,7 @@ class DiskII final:
void process_event(const Storage::Disk::Drive::Event &event) override;
void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) override;
const int clock_rate_ = 0;
const Cycles::IntType clock_rate_ = 0;
uint8_t state_ = 0;
uint8_t inputs_ = 0;
@ -109,7 +109,7 @@ class DiskII final:
int stepper_mask_ = 0;
int stepper_position_ = 0;
int motor_off_time_ = -1;
Cycles::IntType motor_off_time_ = -1;
bool is_write_protected();
std::array<uint8_t, 256> state_machine_;

View File

@ -233,7 +233,7 @@ void IWM::run_for(const Cycles cycles) {
}
// Activity otherwise depends on mode and motor state.
int integer_cycles = cycles.as_int();
auto integer_cycles = cycles.as_integral();
switch(shift_mode_) {
case ShiftMode::Reading: {
// Per the IWM patent, column 7, around line 35 onwards: "The expected time
@ -241,7 +241,7 @@ void IWM::run_for(const Cycles cycles) {
// expected time since the data is not precisely spaced when read due to
// variations in drive speed and other external factors". The error_margin
// here implements the 'after' part of that contract.
const auto error_margin = Cycles(bit_length_.as_int() >> 1);
const auto error_margin = Cycles(bit_length_.as_integral() >> 1);
if(drive_is_rotating_[active_drive_]) {
while(integer_cycles--) {
@ -254,7 +254,7 @@ void IWM::run_for(const Cycles cycles) {
} else {
while(cycles_since_shift_ + integer_cycles >= bit_length_ + error_margin) {
const auto run_length = bit_length_ + error_margin - cycles_since_shift_;
integer_cycles -= run_length.as_int();
integer_cycles -= run_length.as_integral();
cycles_since_shift_ += run_length;
propose_shift(0);
}
@ -272,7 +272,7 @@ void IWM::run_for(const Cycles cycles) {
drives_[active_drive_]->write_bit(shift_register_ & 0x80);
shift_register_ <<= 1;
integer_cycles -= cycles_until_write.as_int();
integer_cycles -= cycles_until_write.as_integral();
cycles_since_shift_ = Cycles(0);
--output_bits_remaining_;
@ -333,7 +333,7 @@ void IWM::select_shift_mode() {
// If writing mode just began, set the drive into write mode and cue up the first output byte.
if(drives_[active_drive_] && old_shift_mode != ShiftMode::Writing && shift_mode_ == ShiftMode::Writing) {
drives_[active_drive_]->begin_writing(Storage::Time(1, clock_rate_ / bit_length_.as_int()), false);
drives_[active_drive_]->begin_writing(Storage::Time(1, clock_rate_ / bit_length_.as_integral()), false);
shift_register_ = next_output_;
write_handshake_ |= 0x80 | 0x40;
output_bits_remaining_ = 8;
@ -369,7 +369,7 @@ void IWM::propose_shift(uint8_t bit) {
// shift in a 1 and start a new window wherever the first found 1 was.
//
// If no 1s are found, shift in a 0 and don't alter expectations as to window placement.
const auto error_margin = Cycles(bit_length_.as_int() >> 1);
const auto error_margin = Cycles(bit_length_.as_integral() >> 1);
if(bit && cycles_since_shift_ < error_margin) return;
shift_register_ = uint8_t((shift_register_ << 1) | bit);

View File

@ -10,18 +10,19 @@
using namespace Serial;
void Line::set_writer_clock_rate(int clock_rate) {
void Line::set_writer_clock_rate(HalfCycles clock_rate) {
clock_rate_ = clock_rate;
}
void Line::advance_writer(int cycles) {
if(!cycles) return;
void Line::advance_writer(HalfCycles cycles) {
if(cycles == HalfCycles(0)) return;
remaining_delays_ = std::max(remaining_delays_ - cycles, 0);
const auto integral_cycles = cycles.as_integral();
remaining_delays_ = std::max(remaining_delays_ - integral_cycles, Cycles::IntType(0));
if(events_.empty()) {
write_cycles_since_delegate_call_ += cycles;
write_cycles_since_delegate_call_ += integral_cycles;
if(transmission_extra_) {
transmission_extra_ -= cycles;
transmission_extra_ -= integral_cycles;
if(transmission_extra_ <= 0) {
transmission_extra_ = 0;
update_delegate(level_);
@ -29,7 +30,7 @@ void Line::advance_writer(int cycles) {
}
} else {
while(!events_.empty()) {
if(events_.front().delay <= cycles) {
if(events_.front().delay <= integral_cycles) {
cycles -= events_.front().delay;
write_cycles_since_delegate_call_ += events_.front().delay;
const auto old_level = level_;
@ -51,8 +52,8 @@ void Line::advance_writer(int cycles) {
transmission_extra_ = minimum_write_cycles_for_read_delegate_bit();
}
} else {
events_.front().delay -= cycles;
write_cycles_since_delegate_call_ += cycles;
events_.front().delay -= integral_cycles;
write_cycles_since_delegate_call_ += integral_cycles;
break;
}
}
@ -69,26 +70,26 @@ void Line::write(bool level) {
}
}
void Line::write(int cycles, int count, int levels) {
remaining_delays_ += count*cycles;
void Line::write(HalfCycles cycles, int count, int levels) {
remaining_delays_ += count * cycles.as_integral();
auto event = events_.size();
events_.resize(events_.size() + size_t(count)*2);
while(count--) {
events_[event].type = Event::Delay;
events_[event].delay = cycles;
events_[event].delay = int(cycles.as_integral());
events_[event+1].type = (levels&1) ? Event::SetHigh : Event::SetLow;
levels >>= 1;
event += 2;
}
}
int Line::write_data_time_remaining() {
return remaining_delays_;
HalfCycles Line::write_data_time_remaining() {
return HalfCycles(remaining_delays_);
}
int Line::transmission_data_time_remaining() {
return remaining_delays_ + transmission_extra_;
HalfCycles Line::transmission_data_time_remaining() {
return HalfCycles(remaining_delays_ + transmission_extra_);
}
void Line::reset_writing() {
@ -125,7 +126,7 @@ void Line::update_delegate(bool level) {
}
// Forward as many bits as occur.
Storage::Time time_left(cycles_to_forward, clock_rate_);
Storage::Time time_left(cycles_to_forward, int(clock_rate_.as_integral()));
const int bit = level ? 1 : 0;
int bits = 0;
while(time_left >= time_left_in_bit_) {
@ -141,7 +142,7 @@ void Line::update_delegate(bool level) {
time_left_in_bit_ -= time_left;
}
int Line::minimum_write_cycles_for_read_delegate_bit() {
Cycles::IntType Line::minimum_write_cycles_for_read_delegate_bit() {
if(!read_delegate_) return 0;
return 1 + (read_delegate_bit_length_ * static_cast<unsigned int>(clock_rate_)).get<int>();
return 1 + (read_delegate_bit_length_ * static_cast<unsigned int>(clock_rate_.as_integral())).get<int>();
}

View File

@ -11,6 +11,7 @@
#include <vector>
#include "../../Storage/Storage.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
namespace Serial {
@ -25,11 +26,11 @@ namespace Serial {
*/
class Line {
public:
void set_writer_clock_rate(int clock_rate);
void set_writer_clock_rate(HalfCycles clock_rate);
/// Advances the read position by @c cycles relative to the writer's
/// clock rate.
void advance_writer(int cycles);
void advance_writer(HalfCycles cycles);
/// Sets the line to @c level.
void write(bool level);
@ -40,14 +41,14 @@ class Line {
/// is scheduled after the final output. The levels to output are
/// taken from @c levels which is read from lsb to msb. @c cycles is
/// relative to the writer's clock rate.
void write(int cycles, int count, int levels);
void write(HalfCycles cycles, int count, int levels);
/// @returns the number of cycles until currently enqueued write data is exhausted.
int write_data_time_remaining();
HalfCycles write_data_time_remaining();
/// @returns the number of cycles left until it is guaranteed that a passive reader
/// has received all currently-enqueued bits.
int transmission_data_time_remaining();
HalfCycles transmission_data_time_remaining();
/// Eliminates all future write states, leaving the output at whatever it is now.
void reset_writing();
@ -77,10 +78,10 @@ class Line {
int delay;
};
std::vector<Event> events_;
int remaining_delays_ = 0;
int transmission_extra_ = 0;
HalfCycles::IntType remaining_delays_ = 0;
HalfCycles::IntType transmission_extra_ = 0;
bool level_ = true;
int clock_rate_ = 0;
HalfCycles clock_rate_ = 0;
ReadDelegate *read_delegate_ = nullptr;
Storage::Time read_delegate_bit_length_, time_left_in_bit_;
@ -91,7 +92,7 @@ class Line {
} read_delegate_phase_ = ReadDelegatePhase::WaitingForZero;
void update_delegate(bool level);
int minimum_write_cycles_for_read_delegate_bit();
HalfCycles::IntType minimum_write_cycles_for_read_delegate_bit();
};
/*!

View File

@ -872,7 +872,7 @@ template <bool has_fdc> class ConcreteMachine:
// TODO (in the player, not here): adapt it to accept an input clock rate and
// run_for as HalfCycles
if(!tape_player_is_sleeping_) tape_player_.run_for(cycle.length.as_int());
if(!tape_player_is_sleeping_) tape_player_.run_for(cycle.length.as_integral());
// Pump the AY
ay_.run_for(cycle.length);
@ -1157,7 +1157,7 @@ template <bool has_fdc> class ConcreteMachine:
void flush_fdc() {
// Clock the FDC, if connected, using a lazy scale by two
if(has_fdc && !fdc_is_sleeping_) {
fdc_.run_for(Cycles(time_since_fdc_update_.as_int()));
fdc_.run_for(Cycles(time_since_fdc_update_.as_integral()));
}
time_since_fdc_update_ = HalfCycles(0);
}

View File

@ -52,7 +52,7 @@ void DiskIICard::perform_bus_operation(Select select, bool is_read, uint16_t add
void DiskIICard::run_for(Cycles cycles, int stretches) {
if(diskii_clocking_preference_ == ClockingHint::Preference::None) return;
diskii_.run_for(Cycles(cycles.as_int() * 2));
diskii_.run_for(Cycles(cycles.as_integral() * 2));
}
void DiskIICard::set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk, int drive) {

View File

@ -284,7 +284,7 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
// Source: Have an Apple Split by Bob Bishop; http://rich12345.tripod.com/aiivideo/softalk.html
// Determine column at offset.
int mapped_column = column_ + offset.as_int();
int mapped_column = column_ + int(offset.as_integral());
// Map that backwards from the internal pixels-at-start generation to pixels-at-end
// (so what was column 0 is now column 25).
@ -315,7 +315,7 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
bool get_is_vertical_blank(Cycles offset) {
// Map that backwards from the internal pixels-at-start generation to pixels-at-end
// (so what was column 0 is now column 25).
int mapped_column = column_ + offset.as_int();
int mapped_column = column_ + int(offset.as_integral());
// Map that backwards from the internal pixels-at-start generation to pixels-at-end
// (so what was column 0 is now column 25).
@ -343,7 +343,7 @@ template <class BusHandler, bool is_iie> class Video: public VideoBase {
static const int first_sync_column = 49; // Also a guess.
static const int sync_length = 4; // One of the two likely candidates.
int int_cycles = cycles.as_int();
int int_cycles = int(cycles.as_integral());
while(int_cycles) {
const int cycles_this_line = std::min(65 - column_, int_cycles);
const int ending_column = column_ + cycles_this_line;

View File

@ -576,7 +576,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
forceinline void advance_time(HalfCycles duration) {
time_since_video_update_ += duration;
iwm_ += duration;
ram_subcycle_ = (ram_subcycle_ + duration.as_int()) & 15;
ram_subcycle_ = (ram_subcycle_ + duration.as_integral()) & 15;
// The VIA runs at one-tenth of the 68000's clock speed, in sync with the E clock.
// See: Guide to the Macintosh Hardware Family p149 (PDF p188). Some extra division
@ -633,7 +633,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
// Consider updating the real-time clock.
real_time_clock_ += duration;
auto ticks = real_time_clock_.divide_cycles(Cycles(CLOCK_RATE)).as_int();
auto ticks = real_time_clock_.divide_cycles(Cycles(CLOCK_RATE)).as_integral();
while(ticks--) {
clock_.update();
// TODO: leave a delay between toggling the input rather than using this coupled hack.
@ -750,7 +750,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
void run_for(HalfCycles duration) {
// The 6522 enjoys a divide-by-ten, so multiply back up here to make the
// divided-by-two clock the audio works on.
audio_.time_since_update += HalfCycles(duration.as_int() * 5);
audio_.time_since_update += HalfCycles(duration.as_integral() * 5);
}
void flush() {

View File

@ -47,7 +47,7 @@ void Video::run_for(HalfCycles duration) {
// the number of fetches.
while(duration > HalfCycles(0)) {
const auto pixel_start = frame_position_ % line_length;
const int line = (frame_position_ / line_length).as_int();
const int line = int((frame_position_ / line_length).as_integral());
const auto cycles_left_in_line = std::min(line_length - pixel_start, duration);
@ -62,8 +62,8 @@ void Video::run_for(HalfCycles duration) {
//
// Then 12 lines of border, 3 of sync, 11 more of border.
const int first_word = pixel_start.as_int() >> 4;
const int final_word = (pixel_start + cycles_left_in_line).as_int() >> 4;
const int first_word = int(pixel_start.as_integral()) >> 4;
const int final_word = int((pixel_start + cycles_left_in_line).as_integral()) >> 4;
if(first_word != final_word) {
if(line < 342) {
@ -153,12 +153,12 @@ void Video::run_for(HalfCycles duration) {
}
bool Video::vsync() {
const int line = (frame_position_ / line_length).as_int();
const auto line = (frame_position_ / line_length).as_integral();
return line >= 353 && line < 356;
}
HalfCycles Video::get_next_sequence_point() {
const int line = (frame_position_ / line_length).as_int();
const auto line = (frame_position_ / line_length).as_integral();
if(line >= 353 && line < 356) {
// Currently in vsync, so get time until start of line 357,
// when vsync will end.

View File

@ -69,8 +69,8 @@ class Video {
*/
bool is_outputting(HalfCycles offset = HalfCycles(0)) {
const auto offset_position = frame_position_ + offset % frame_length;
const int column = (offset_position % line_length).as_int() >> 4;
const int line = (offset_position / line_length).as_int();
const int column = int((offset_position % line_length).as_integral()) >> 4;
const int line = int((offset_position / line_length).as_integral());
return line < 342 && column < 32;
}

View File

@ -51,7 +51,7 @@ template<class T> class Cartridge:
Adjusts @c confidence_counter according to the results of the most recent run_for.
*/
void apply_confidence(Analyser::Dynamic::ConfidenceCounter &confidence_counter) {
if(cycle_count_.as_int() < 200) return;
if(cycle_count_.as_integral() < 200) return;
if(horizontal_counter_resets_ > 10)
confidence_counter.add_miss();
}

View File

@ -101,7 +101,7 @@ class Pitfall2: public BusExtender {
inline uint8_t update_audio() {
const unsigned int clock_divisor = 57;
int cycles_to_run_for = cycles_since_audio_update_.divide(clock_divisor).as_int();
int cycles_to_run_for = int(cycles_since_audio_update_.divide(clock_divisor).as_integral());
int table_position = 0;
for(int c = 0; c < 3; c++) {

View File

@ -143,7 +143,7 @@ void TIA::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
}
void TIA::run_for(const Cycles cycles) {
int number_of_cycles = cycles.as_int();
int number_of_cycles = int(cycles.as_integral());
// if part way through a line, definitely perform a partial, at most up to the end of the line
if(horizontal_counter_) {
@ -176,7 +176,7 @@ void TIA::reset_horizontal_counter() {
}
int TIA::get_cycles_until_horizontal_blank(const Cycles from_offset) {
return (cycles_per_line - (horizontal_counter_ + from_offset.as_int()) % cycles_per_line) % cycles_per_line;
return (cycles_per_line - (horizontal_counter_ + from_offset.as_integral()) % cycles_per_line) % cycles_per_line;
}
void TIA::set_background_colour(uint8_t colour) {

View File

@ -64,11 +64,11 @@ class IntelligentKeyboard:
}
ClockingHint::Preference preferred_clocking() final {
return output_line_.transmission_data_time_remaining() ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None;
return output_line_.transmission_data_time_remaining().as_integral() ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None;
}
void run_for(HalfCycles duration) {
output_line_.advance_writer(duration.as_int());
output_line_.advance_writer(duration);
}
private:

View File

@ -62,7 +62,7 @@ void Video::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
}
void Video::run_for(HalfCycles duration) {
int integer_duration = duration.as_int();
int integer_duration = int(duration.as_integral());
const auto mode_params = mode_params_for_mode();
#define Period(lower, upper, type) \

View File

@ -166,7 +166,7 @@ class ConcreteMachine:
// for the entire frame, RAM is accessible only on odd cycles; in modes below 4
// it's also accessible only outside of the pixel regions
cycles += video_output_.get_cycles_until_next_ram_availability(cycles_since_display_update_.as_int() + 1);
cycles += video_output_.get_cycles_until_next_ram_availability(int(cycles_since_display_update_.as_integral()) + 1);
} else {
switch(address & 0xff0f) {
case 0xfe00:

View File

@ -80,7 +80,7 @@ void Tape::run_for(const Cycles cycles) {
TapePlayer::run_for(cycles);
}
} else {
output_.cycles_into_pulse += static_cast<unsigned int>(cycles.as_int());
output_.cycles_into_pulse += static_cast<unsigned int>(cycles.as_integral());
while(output_.cycles_into_pulse > 1664) { // 1664 = the closest you can get to 1200 baud if you're looking for something
output_.cycles_into_pulse -= 1664; // that divides the 125,000Hz clock that the sound divider runs off.
push_tape_bit(1);

View File

@ -225,7 +225,7 @@ void VideoOutput::output_pixels(int number_of_cycles) {
}
void VideoOutput::run_for(const Cycles cycles) {
int number_of_cycles = cycles.as_int();
int number_of_cycles = int(cycles.as_integral());
output_position_ = (output_position_ + number_of_cycles) % cycles_per_frame;
while(number_of_cycles) {
int draw_action_length = screen_map_[screen_map_pointer_].length;

View File

@ -53,7 +53,7 @@ void DiskROM::run_for(HalfCycles half_cycles) {
// Input clock is going to be 7159090/2 Mhz, but the drive controller
// needs an 8Mhz clock, so scale up. 8000000/7159090 simplifies to
// 800000/715909.
controller_cycles_ += 800000 * half_cycles.as_int();
controller_cycles_ += 800000 * half_cycles.as_integral();
WD::WD1770::run_for(Cycles(static_cast<int>(controller_cycles_ / 715909)));
controller_cycles_ %= 715909;
}

View File

@ -599,7 +599,7 @@ class ConcreteMachine:
}
if(!tape_player_is_sleeping_)
tape_player_.run_for(cycle.length.as_int());
tape_player_.run_for(int(cycle.length.as_integral()));
if(time_until_interrupt_ > 0) {
time_until_interrupt_ -= total_length;

View File

@ -15,7 +15,7 @@ namespace {
// by comparing the amount of time this emulator took to show a directory versus a video of
// a real Oric. It therefore assumes all other timing measurements were correct on the day
// of the test. More work to do, I think.
const int head_load_request_counter_target = 7653333;
const Cycles::IntType head_load_request_counter_target = 7653333;
}
Microdisc::Microdisc() : WD1770(P1793) {
@ -114,7 +114,7 @@ void Microdisc::set_head_load_request(bool head_load) {
void Microdisc::run_for(const Cycles cycles) {
if(head_load_request_counter_ < head_load_request_counter_target) {
head_load_request_counter_ += cycles.as_int();
head_load_request_counter_ += cycles.as_integral();
if(head_load_request_counter_ >= head_load_request_counter_target) set_head_loaded(true);
}
WD::WD1770::run_for(cycles);

View File

@ -58,7 +58,7 @@ class Microdisc: public WD::WD1770 {
size_t selected_drive_;
bool irq_enable_ = false;
int paging_flags_ = BASICDisable;
int head_load_request_counter_ = -1;
Cycles::IntType head_load_request_counter_ = -1;
bool head_load_request_ = false;
Delegate *delegate_ = nullptr;
uint8_t last_control_ = 0;

View File

@ -94,7 +94,7 @@ void VideoOutput::run_for(const Cycles cycles) {
#define clamp(action) \
if(cycles_run_for <= number_of_cycles) { action; } else cycles_run_for = number_of_cycles;
int number_of_cycles = cycles.as_int();
int number_of_cycles = int(cycles.as_integral());
while(number_of_cycles) {
int h_counter = counter_ & 63;
int cycles_run_for = 0;

View File

@ -42,7 +42,7 @@ void Video::flush() {
void Video::flush(bool next_sync) {
if(sync_) {
// If in sync, that takes priority. Output the proper amount of sync.
crt_.output_sync(time_since_update_.as_int());
crt_.output_sync(int(time_since_update_.as_integral()));
} else {
// If not presently in sync, then...
@ -50,8 +50,8 @@ void Video::flush(bool next_sync) {
// If there is output data queued, output it either if it's being interrupted by
// sync, or if we're past its end anyway. Otherwise let it be.
int data_length = static_cast<int>(line_data_pointer_ - line_data_);
if(data_length < time_since_update_.as_int() || next_sync) {
auto output_length = std::min(data_length, time_since_update_.as_int());
if(data_length < int(time_since_update_.as_integral()) || next_sync) {
auto output_length = std::min(data_length, int(time_since_update_.as_integral()));
crt_.output_data(output_length);
line_data_pointer_ = line_data_ = nullptr;
time_since_update_ -= HalfCycles(output_length);
@ -61,7 +61,7 @@ void Video::flush(bool next_sync) {
// Any pending pixels being dealt with, pad with the white level.
uint8_t *colour_pointer = static_cast<uint8_t *>(crt_.begin_data(1));
if(colour_pointer) *colour_pointer = 0xff;
crt_.output_level(time_since_update_.as_int());
crt_.output_level(int(time_since_update_.as_integral()));
}
time_since_update_ = 0;

View File

@ -79,7 +79,7 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg)
}
- (uint32_t)timestamp {
return _processor->get_timestamp().as_int();
return uint32_t(_processor->get_timestamp().as_integral());
}
- (void)setIrqLine:(BOOL)irqLine {

View File

@ -155,7 +155,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
}
- (int)completedHalfCycles {
return _processor->get_timestamp().as_int();
return int(_processor->get_timestamp().as_integral());
}
- (void)setNmiLine:(BOOL)nmiLine {
@ -216,7 +216,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) {
}
capture.address = address;
capture.value = value;
capture.timeStamp = timeStamp.as_int();
capture.timeStamp = int(timeStamp.as_integral());
[_busOperationCaptures addObject:capture];
}

View File

@ -31,14 +31,14 @@
int c = 5;
bool vsync = _video->vsync();
while(c--) {
int remaining_time_in_state = _video->get_next_sequence_point().as_int();
auto remaining_time_in_state = _video->get_next_sequence_point().as_integral();
NSLog(@"Vsync %@ expected for %@ half-cycles", vsync ? @"on" : @"off", @(remaining_time_in_state));
while(remaining_time_in_state--) {
XCTAssertEqual(vsync, _video->vsync());
_video->run_for(HalfCycles(1));
if(remaining_time_in_state)
XCTAssertEqual(remaining_time_in_state, _video->get_next_sequence_point().as_int());
XCTAssertEqual(remaining_time_in_state, _video->get_next_sequence_point().as_integral());
}
vsync ^= true;
}

View File

@ -55,7 +55,7 @@
vdp.set_register(1, 0x8a);
// Get time until interrupt.
int time_until_interrupt = vdp.get_time_until_interrupt().as_int() - 1;
auto time_until_interrupt = vdp.get_time_until_interrupt().as_integral() - 1;
// Check that an interrupt is now scheduled.
NSAssert(time_until_interrupt != -2, @"No interrupt scheduled");
@ -74,7 +74,7 @@
NSAssert(!vdp.get_interrupt_line(), @"Interrupt wasn't reset by status read");
// Check interrupt flag isn't set prior to the reported time.
time_until_interrupt = vdp.get_time_until_interrupt().as_int() - 1;
time_until_interrupt = vdp.get_time_until_interrupt().as_integral() - 1;
vdp.run_for(HalfCycles(time_until_interrupt));
NSAssert(!vdp.get_interrupt_line(), @"Interrupt line went active early [2]");
@ -101,7 +101,7 @@
// Clear the pending interrupt and ask about the next one (i.e. the first one).
vdp.get_register(1);
int time_until_interrupt = vdp.get_time_until_interrupt().as_int() - 1;
auto time_until_interrupt = vdp.get_time_until_interrupt().as_integral() - 1;
// Check that an interrupt is now scheduled.
NSAssert(time_until_interrupt != -2, @"No interrupt scheduled");
@ -135,7 +135,7 @@
// Now run through an entire frame...
int half_cycles = 262*228*2;
int last_time_until_interrupt = vdp.get_time_until_interrupt().as_int();
auto last_time_until_interrupt = vdp.get_time_until_interrupt().as_integral();
while(half_cycles--) {
// Validate that an interrupt happened if one was expected, and clear anything that's present.
NSAssert(vdp.get_interrupt_line() == (last_time_until_interrupt == 0), @"Unexpected interrupt state change; expected %d but got %d; position %d %d @ %d", (last_time_until_interrupt == 0), vdp.get_interrupt_line(), c, with_eof, half_cycles);
@ -144,7 +144,7 @@
vdp.run_for(HalfCycles(1));
// Get the time until interrupt.
int time_until_interrupt = vdp.get_time_until_interrupt().as_int();
auto time_until_interrupt = vdp.get_time_until_interrupt().as_integral();
NSAssert(time_until_interrupt != -1, @"No interrupt scheduled; position %d %d @ %d", c, with_eof, half_cycles);
NSAssert(time_until_interrupt >= 0, @"Interrupt is scheduled in the past; position %d %d @ %d", c, with_eof, half_cycles);
@ -160,11 +160,11 @@
- (void)testTimeUntilLine {
TI::TMS::TMS9918 vdp(TI::TMS::Personality::SMSVDP);
int time_until_line = vdp.get_time_until_line(-1).as_int();
auto time_until_line = vdp.get_time_until_line(-1).as_integral();
for(int c = 0; c < 262*228*5; ++c) {
vdp.run_for(HalfCycles(1));
const int time_remaining_until_line = vdp.get_time_until_line(-1).as_int();
const auto time_remaining_until_line = vdp.get_time_until_line(-1).as_integral();
--time_until_line;
if(time_until_line) {
NSAssert(time_remaining_until_line == time_until_line, @"Discontinuity found in distance-to-line prediction; expected %d but got %d", time_until_line, time_remaining_until_line);

View File

@ -128,7 +128,7 @@ class RAM68000: public CPU::MC68000::BusHandler {
}
int get_cycle_count() {
return duration_.as_int() >> 1;
return int(duration_.as_integral()) >> 1;
}
private:

View File

@ -106,7 +106,7 @@ template <typename T> class LowpassSpeaker: public Speaker {
void run_for(const Cycles cycles) {
if(!delegate_) return;
std::size_t cycles_remaining = size_t(cycles.as_int());
std::size_t cycles_remaining = size_t(cycles.as_integral());
if(!cycles_remaining) return;
FilterParameters filter_parameters;

View File

@ -941,7 +941,7 @@ template < class T,
operation_indices.push_back(target.all_operations.size());
for(std::size_t t = 0; t < lengths[c];) {
// Skip zero-length bus cycles.
if(table[c][t].type == MicroOp::BusOperation && table[c][t].machine_cycle.length.as_int() == 0) {
if(table[c][t].type == MicroOp::BusOperation && table[c][t].machine_cycle.length.as_integral() == 0) {
t++;
continue;
}

View File

@ -13,9 +13,9 @@
using namespace Storage::Disk;
Controller::Controller(Cycles clock_rate) :
clock_rate_multiplier_(128000000 / clock_rate.as_int()),
clock_rate_(clock_rate.as_int() * clock_rate_multiplier_),
empty_drive_(new Drive(clock_rate.as_int(), 1, 1)) {
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
empty_drive_(new Drive(int(clock_rate.as_integral()), 1, 1)) {
// seed this class with a PLL, any PLL, so that it's safe to assume non-nullptr later
Time one(1);
set_expected_bit_length(one);
@ -48,7 +48,7 @@ void Controller::process_event(const Drive::Event &event) {
}
void Controller::advance(const Cycles cycles) {
if(is_reading_) pll_->run_for(Cycles(cycles.as_int() * clock_rate_multiplier_));
if(is_reading_) pll_->run_for(Cycles(cycles.as_integral() * clock_rate_multiplier_));
}
void Controller::process_write_completed() {
@ -61,7 +61,7 @@ void Controller::set_expected_bit_length(Time bit_length) {
bit_length_ = bit_length;
bit_length_.simplify();
Time cycles_per_bit = Storage::Time(clock_rate_) * bit_length;
Time cycles_per_bit = Storage::Time(int(clock_rate_)) * bit_length;
cycles_per_bit.simplify();
// this conversion doesn't need to be exact because there's a lot of variation to be taken

View File

@ -106,8 +106,8 @@ class Controller:
private:
Time bit_length_;
int clock_rate_multiplier_ = 1;
int clock_rate_ = 1;
Cycles::IntType clock_rate_multiplier_ = 1;
Cycles::IntType clock_rate_ = 1;
bool is_reading_ = true;

View File

@ -18,14 +18,14 @@ DigitalPhaseLockedLoop::DigitalPhaseLockedLoop(int clocks_per_bit, std::size_t l
clocks_per_bit_(clocks_per_bit) {}
void DigitalPhaseLockedLoop::run_for(const Cycles cycles) {
offset_ += cycles.as_int();
phase_ += cycles.as_int();
offset_ += cycles.as_integral();
phase_ += cycles.as_integral();
if(phase_ >= window_length_) {
int windows_crossed = phase_ / window_length_;
auto windows_crossed = phase_ / window_length_;
// check whether this triggers any 0s, if anybody cares
if(delegate_) {
if(window_was_filled_) windows_crossed--;
if(window_was_filled_) --windows_crossed;
for(int c = 0; c < windows_crossed; c++)
delegate_->digital_phase_locked_loop_output_bit(0);
}
@ -44,16 +44,16 @@ void DigitalPhaseLockedLoop::add_pulse() {
}
}
void DigitalPhaseLockedLoop::post_phase_offset(int new_phase, int new_offset) {
void DigitalPhaseLockedLoop::post_phase_offset(Cycles::IntType new_phase, Cycles::IntType new_offset) {
offset_history_[offset_history_pointer_] = new_offset;
offset_history_pointer_ = (offset_history_pointer_ + 1) % offset_history_.size();
// use an unweighted average of the stored offsets to compute current window size,
// bucketing them by rounding to the nearest multiple of the base clocks per bit
int total_spacing = 0;
int total_divisor = 0;
for(int offset : offset_history_) {
int multiple = (offset + (clocks_per_bit_ >> 1)) / clocks_per_bit_;
Cycles::IntType total_spacing = 0;
Cycles::IntType total_divisor = 0;
for(auto offset : offset_history_) {
auto multiple = (offset + (clocks_per_bit_ >> 1)) / clocks_per_bit_;
if(!multiple) continue;
total_divisor += multiple;
total_spacing += offset;
@ -62,7 +62,7 @@ void DigitalPhaseLockedLoop::post_phase_offset(int new_phase, int new_offset) {
window_length_ = total_spacing / total_divisor;
}
int error = new_phase - (window_length_ >> 1);
auto error = new_phase - (window_length_ >> 1);
// use a simple spring mechanism as a lowpass filter for phase
phase_ -= (error + 1) >> 1;

View File

@ -52,14 +52,14 @@ class DigitalPhaseLockedLoop {
private:
Delegate *delegate_ = nullptr;
void post_phase_offset(int phase, int offset);
void post_phase_offset(Cycles::IntType phase, Cycles::IntType offset);
std::vector<int> offset_history_;
std::vector<Cycles::IntType> offset_history_;
std::size_t offset_history_pointer_ = 0;
int offset_ = 0;
Cycles::IntType offset_ = 0;
int phase_ = 0;
int window_length_ = 0;
Cycles::IntType phase_ = 0;
Cycles::IntType window_length_ = 0;
bool window_was_filled_ = false;
int clocks_per_bit_ = 0;

View File

@ -94,7 +94,8 @@ int WOZ::get_head_count() {
long WOZ::file_offset(Track::Address address) {
// Calculate table position; if this track is defined to be unformatted, return no track.
const int table_position = address.head * (is_3_5_disk_ ? 80 : 160) + (is_3_5_disk_ ? address.position.as_int() : address.position.as_quarter());
const int table_position = address.head * (is_3_5_disk_ ? 80 : 160) +
(is_3_5_disk_ ? address.position.as_int() : address.position.as_quarter());
if(track_map_[table_position] == 0xff) return NoSuchTrack;
// Seek to the real track.

View File

@ -173,7 +173,7 @@ void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) {
}
void Drive::advance(const Cycles cycles) {
cycles_since_index_hole_ += cycles.as_int();
cycles_since_index_hole_ += cycles.as_integral();
if(event_delegate_) event_delegate_->advance(cycles);
}
@ -182,20 +182,20 @@ void Drive::run_for(const Cycles cycles) {
if(has_disk_) {
Time zero(0);
int number_of_cycles = cycles.as_int();
auto number_of_cycles = cycles.as_integral();
while(number_of_cycles) {
int cycles_until_next_event = static_cast<int>(get_cycles_until_next_event());
int cycles_to_run_for = std::min(cycles_until_next_event, number_of_cycles);
auto cycles_until_next_event = get_cycles_until_next_event();
auto cycles_to_run_for = std::min(cycles_until_next_event, number_of_cycles);
if(!is_reading_ && cycles_until_bits_written_ > zero) {
int write_cycles_target = cycles_until_bits_written_.get<int>();
if(cycles_until_bits_written_.length % cycles_until_bits_written_.clock_rate) write_cycles_target++;
auto write_cycles_target = cycles_until_bits_written_.get<Cycles::IntType>();
if(cycles_until_bits_written_.length % cycles_until_bits_written_.clock_rate) ++write_cycles_target;
cycles_to_run_for = std::min(cycles_to_run_for, write_cycles_target);
}
number_of_cycles -= cycles_to_run_for;
if(!is_reading_) {
if(cycles_until_bits_written_ > zero) {
Storage::Time cycles_to_run_for_time(cycles_to_run_for);
Storage::Time cycles_to_run_for_time(static_cast<int>(cycles_to_run_for));
if(cycles_until_bits_written_ <= cycles_to_run_for_time) {
if(event_delegate_) event_delegate_->process_write_completed();
if(cycles_until_bits_written_ <= cycles_to_run_for_time)
@ -345,7 +345,7 @@ void Drive::begin_writing(Time bit_length, bool clamp_to_index_hole) {
is_reading_ = false;
clamp_writing_to_index_hole_ = clamp_to_index_hole;
cycles_per_bit_ = Storage::Time(get_input_clock_rate()) * bit_length;
cycles_per_bit_ = Storage::Time(int(get_input_clock_rate())) * bit_length;
cycles_per_bit_.simplify();
write_segment_.length_of_a_bit = bit_length / Time(rotational_multiplier_);

View File

@ -196,7 +196,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
// A count of time since the index hole was last seen. Which is used to
// determine how far the drive is into a full rotation when switching to
// a new track.
int cycles_since_index_hole_ = 0;
Cycles::IntType cycles_since_index_hole_ = 0;
// The number of cycles that should fall within one revolution at the
// current rotation speed.

View File

@ -11,20 +11,21 @@
using namespace SCSI;
Bus::Bus(HalfCycles clock_rate) {
cycles_to_time_ = 1.0 / double(clock_rate.as_int());
cycles_to_time_ = 1.0 / double(clock_rate.as_integral());
// NB: note that the dispatch times below are **ORDERED**
// from least to greatest. Each box should contain the number
// of whole clock periods it will take to get the the first
// discrete moment after the required delay interval has been met.
dispatch_times_[0] = 1 + int(CableSkew / cycles_to_time_);
dispatch_times_[1] = 1 + int(DeskewDelay / cycles_to_time_);
dispatch_times_[2] = 1 + int(BusFreeDelay / cycles_to_time_);
dispatch_times_[3] = 1 + int(BusSettleDelay / cycles_to_time_);
dispatch_times_[4] = 1 + int(BusClearDelay / cycles_to_time_);
dispatch_times_[5] = 1 + int(BusSetDelay / cycles_to_time_);
dispatch_times_[6] = 1 + int(ArbitrationDelay / cycles_to_time_);
dispatch_times_[7] = 1 + int(ResetHoldTime / cycles_to_time_);
using IntType = Cycles::IntType;
dispatch_times_[0] = 1 + IntType(CableSkew / cycles_to_time_);
dispatch_times_[1] = 1 + IntType(DeskewDelay / cycles_to_time_);
dispatch_times_[2] = 1 + IntType(BusFreeDelay / cycles_to_time_);
dispatch_times_[3] = 1 + IntType(BusSettleDelay / cycles_to_time_);
dispatch_times_[4] = 1 + IntType(BusClearDelay / cycles_to_time_);
dispatch_times_[5] = 1 + IntType(BusSetDelay / cycles_to_time_);
dispatch_times_[6] = 1 + IntType(ArbitrationDelay / cycles_to_time_);
dispatch_times_[7] = 1 + IntType(ResetHoldTime / cycles_to_time_);
}
size_t Bus::add_device() {
@ -86,7 +87,7 @@ ClockingHint::Preference Bus::preferred_clocking() {
}
void Bus::update_observers() {
const auto time_elapsed = double(time_in_state_.as_int()) * cycles_to_time_;
const auto time_elapsed = double(time_in_state_.as_integral()) * cycles_to_time_;
for(auto &observer: observers_) {
observer->scsi_bus_did_change(this, state_, time_elapsed);
}
@ -97,7 +98,7 @@ void Bus::run_for(HalfCycles time) {
time_in_state_ += time;
const auto old_index = dispatch_index_;
const auto time_as_int = time_in_state_.as_int();
const auto time_as_int = time_in_state_.as_integral();
while(time_as_int >= dispatch_times_[dispatch_index_] && dispatch_index_ < dispatch_times_.size()) {
++dispatch_index_;
}

View File

@ -148,7 +148,7 @@ class Bus: public ClockingHint::Source, public Activity::Source {
HalfCycles time_in_state_;
double cycles_to_time_ = 1.0;
size_t dispatch_index_ = 0;
std::array<int, 8> dispatch_times_;
std::array<Cycles::IntType, 8> dispatch_times_;
std::vector<BusState> device_states_;
BusState state_ = DefaultBusState;

View File

@ -15,13 +15,13 @@
using namespace Storage;
TimedEventLoop::TimedEventLoop(int input_clock_rate) :
TimedEventLoop::TimedEventLoop(Cycles::IntType input_clock_rate) :
input_clock_rate_(input_clock_rate) {}
void TimedEventLoop::run_for(const Cycles cycles) {
int remaining_cycles = cycles.as_int();
auto remaining_cycles = cycles.as_integral();
#ifndef NDEBUG
int cycles_advanced = 0;
decltype(remaining_cycles) cycles_advanced = 0;
#endif
while(cycles_until_event_ <= remaining_cycles) {
@ -42,15 +42,15 @@ void TimedEventLoop::run_for(const Cycles cycles) {
advance(remaining_cycles);
}
assert(cycles_advanced == cycles.as_int());
assert(cycles_advanced == cycles.as_integral());
assert(cycles_until_event_ > 0);
}
int TimedEventLoop::get_cycles_until_next_event() {
return std::max(cycles_until_event_, 0);
Cycles::IntType TimedEventLoop::get_cycles_until_next_event() {
return std::max(cycles_until_event_, Cycles::IntType(0));
}
int TimedEventLoop::get_input_clock_rate() {
Cycles::IntType TimedEventLoop::get_input_clock_rate() {
return input_clock_rate_;
}
@ -74,7 +74,7 @@ void TimedEventLoop::set_next_event_time_interval(float interval) {
// So this event will fire in the integral number of cycles from now, putting us at the remainder
// number of subcycles
const int addition = int(float_interval);
const Cycles::IntType addition = Cycles::IntType(float_interval);
cycles_until_event_ += addition;
subcycles_until_event_ = fmodf(float_interval, 1.0);

View File

@ -42,7 +42,7 @@ namespace Storage {
/*!
Constructs a timed event loop that will be clocked at @c input_clock_rate.
*/
TimedEventLoop(int input_clock_rate);
TimedEventLoop(Cycles::IntType input_clock_rate);
/*!
Advances the event loop by @c number_of_cycles cycles.
@ -52,12 +52,12 @@ namespace Storage {
/*!
@returns the number of whole cycles remaining until the next event is triggered.
*/
int get_cycles_until_next_event();
Cycles::IntType get_cycles_until_next_event();
/*!
@returns the input clock rate.
*/
int get_input_clock_rate();
Cycles::IntType get_input_clock_rate();
protected:
/*!
@ -101,8 +101,8 @@ namespace Storage {
Time get_time_into_next_event();
private:
int input_clock_rate_ = 0;
int cycles_until_event_ = 0;
Cycles::IntType input_clock_rate_ = 0;
Cycles::IntType cycles_until_event_ = 0;
float subcycles_until_event_ = 0.0;
};