mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-25 16:31:42 +00:00
This is correct from the Enterprise's side of things, I think.
I just need to complete the missing part of JustInTimeActor. After I do some empirical testing of this.
This commit is contained in:
parent
f2d7b9f6a9
commit
81e9ba5608
@ -145,13 +145,21 @@ template <class T, class LocalTimeScale = HalfCycles, int multiplier = 1, int di
|
||||
|
||||
/// @returns the amount of time since the object was last flushed, in the target time scale.
|
||||
[[nodiscard]] forceinline TargetTimeScale time_since_flush() const {
|
||||
// TODO: does this handle conversions properly where TargetTimeScale != LocalTimeScale?
|
||||
if constexpr (divider == 1) {
|
||||
return time_since_update_;
|
||||
}
|
||||
return TargetTimeScale(time_since_update_.as_integral() / divider);
|
||||
}
|
||||
|
||||
/// @returns the amount of time since the object was last flushed, plus the local time scale @c offset,
|
||||
/// converted to the target time scale.
|
||||
[[nodiscard]] forceinline TargetTimeScale time_since_flush(LocalTimeScale offset) const {
|
||||
if constexpr (divider == 1) {
|
||||
return time_since_update_ + offset;
|
||||
}
|
||||
return TargetTimeScale((time_since_update_ + offset).as_integral() / divider);
|
||||
}
|
||||
|
||||
/// Flushes all accumulated time.
|
||||
///
|
||||
/// This does not affect this actor's record of when the next sequence point will occur.
|
||||
@ -196,6 +204,13 @@ template <class T, class LocalTimeScale = HalfCycles, int multiplier = 1, int di
|
||||
return rhs >= time_until_event_;
|
||||
}
|
||||
|
||||
/// Indicates the amount of time, in the local time scale, until the first local slot that falls wholly
|
||||
/// after the amount of time provided in the target time scale.
|
||||
[[nodiscard]] forceinline LocalTimeScale back_map(TargetTimeScale time) const {
|
||||
// TODO.
|
||||
return LocalTimeScale(0);
|
||||
}
|
||||
|
||||
/// Updates this template's record of the next sequence point.
|
||||
void update_sequence_point() {
|
||||
if constexpr (has_sequence_points<T>::value) {
|
||||
|
@ -221,6 +221,17 @@ template <bool has_disk_controller> class ConcreteMachine:
|
||||
}
|
||||
|
||||
// MARK: - Z80::BusHandler.
|
||||
forceinline void advance_nick(HalfCycles duration) {
|
||||
if(nick_ += duration) {
|
||||
const auto nick = nick_.last_valid();
|
||||
const bool nick_interrupt_line = nick->get_interrupt_line();
|
||||
if(nick_interrupt_line && !previous_nick_interrupt_line_) {
|
||||
set_interrupt(Interrupt::Nick, nick_.last_sequence_point_overrun());
|
||||
}
|
||||
previous_nick_interrupt_line_ = nick_interrupt_line;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
|
||||
using PartialMachineCycle = CPU::Z80::PartialMachineCycle;
|
||||
const uint16_t address = cycle.address ? *cycle.address : 0x0000;
|
||||
@ -240,36 +251,46 @@ template <bool has_disk_controller> class ConcreteMachine:
|
||||
case CPU::Z80::PartialMachineCycle::ReadOpcodeStart:
|
||||
if(!is_video_[address >> 14] && wait_mode_ != WaitMode::None) {
|
||||
penalty = HalfCycles(2);
|
||||
} else {
|
||||
// Query Nick for the amount of delay that would occur with one cycle left
|
||||
// in this read opcode.
|
||||
const auto delay = nick_.last_valid()->get_time_until_z80_slot(nick_.time_since_flush(HalfCycles(2)));
|
||||
penalty = nick_.back_map(delay);
|
||||
}
|
||||
break;
|
||||
|
||||
// Video pauses: insert right at the end of the bus cycle.
|
||||
case CPU::Z80::PartialMachineCycle::ReadOpcode:
|
||||
case CPU::Z80::PartialMachineCycle::Read:
|
||||
case CPU::Z80::PartialMachineCycle::Write:
|
||||
// Ensure all video that should have been collected prior to
|
||||
// this write has been.
|
||||
if(is_video_[address >> 14]) {
|
||||
// TODO.
|
||||
nick_.flush();
|
||||
}
|
||||
[[fallthrough]];
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Read:
|
||||
if(is_video_[address >> 14]) {
|
||||
// Get delay, in Nick cycles, for a Z80 access that occurs in 0.5
|
||||
// cycles from now (i.e. with one cycle left to run).
|
||||
const auto delay = nick_.last_valid()->get_time_until_z80_slot(nick_.time_since_flush(HalfCycles(1)));
|
||||
penalty = nick_.back_map(delay);
|
||||
}
|
||||
break;
|
||||
|
||||
case CPU::Z80::PartialMachineCycle::Input:
|
||||
case CPU::Z80::PartialMachineCycle::Output: {
|
||||
if((address & 0xf0) == 0x80) {
|
||||
// TODO.
|
||||
// Get delay, in Nick cycles, for a Z80 access that occurs in 0.5
|
||||
// cycles from now (i.e. with one cycle left to run).
|
||||
const auto delay = nick_.last_valid()->get_time_until_z80_slot(nick_.time_since_flush(HalfCycles(1)));
|
||||
penalty = nick_.back_map(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const HalfCycles full_length = cycle.length + penalty;
|
||||
time_since_audio_update_ += full_length;
|
||||
if(nick_ += full_length) {
|
||||
const auto nick = nick_.last_valid();
|
||||
const bool nick_interrupt_line = nick->get_interrupt_line();
|
||||
if(nick_interrupt_line && !previous_nick_interrupt_line_) {
|
||||
set_interrupt(Interrupt::Nick, nick_.last_sequence_point_overrun());
|
||||
}
|
||||
previous_nick_interrupt_line_ = nick_interrupt_line;
|
||||
}
|
||||
advance_nick(full_length);
|
||||
|
||||
// The WD/etc runs at a nominal 8Mhz.
|
||||
if constexpr (has_disk_controller) {
|
||||
|
Loading…
Reference in New Issue
Block a user