1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-11-02 02:16:18 +00:00

Switches the Electron to JustInTimeActor video.

Also reorders template parameters; I think that specifying a different time base is likely to be more common than using a divider.
This commit is contained in:
Thomas Harte
2021-04-04 17:33:49 -04:00
parent 9ff392279a
commit d77ddaf4fa
8 changed files with 69 additions and 78 deletions

View File

@@ -25,6 +25,8 @@
#include "../Utility/Typer.hpp"
#include "../../Analyser/Static/Acorn/Target.hpp"
#include "../../ClockReceiver/JustInTime.hpp"
#include "Interrupts.hpp"
#include "Keyboard.hpp"
#include "Plus3.hpp"
@@ -54,7 +56,7 @@ template <bool has_scsi_bus> class ConcreteMachine:
scsi_bus_(4'000'000),
hard_drive_(scsi_bus_, 0),
scsi_device_(scsi_bus_.add_device()),
video_output_(ram_),
video_(ram_),
sound_generator_(audio_queue_),
speaker_(sound_generator_) {
memset(key_states_, 0, sizeof(key_states_));
@@ -230,13 +232,15 @@ template <bool has_scsi_bus> class ConcreteMachine:
if(isReadOperation(operation)) {
*value = ram_[address];
} else {
if(address >= video_access_range_.low_address && address <= video_access_range_.high_address) update_display();
if(address >= video_access_range_.low_address && address <= video_access_range_.high_address) {
video_.flush();
}
ram_[address] = *value;
}
// 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(int(cycles_since_display_update_.as_integral()) + 1);
// 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_.last_valid()->get_cycles_until_next_ram_availability(video_.time_since_flush().template as<int>() + 1);
} else {
switch(address & 0xff0f) {
case 0xfe00:
@@ -274,10 +278,8 @@ template <bool has_scsi_bus> class ConcreteMachine:
case 0xfe08: case 0xfe09: case 0xfe0a: case 0xfe0b:
case 0xfe0c: case 0xfe0d: case 0xfe0e: case 0xfe0f:
if(!isReadOperation(operation)) {
update_display();
video_output_.write(address, *value);
video_access_range_ = video_output_.get_memory_access_range();
queue_next_display_interrupt();
video_->write(address, *value);
video_access_range_ = video_.last_valid()->get_memory_access_range();
}
break;
case 0xfe04:
@@ -483,18 +485,14 @@ template <bool has_scsi_bus> class ConcreteMachine:
}
}
cycles_since_display_update_ += Cycles(int(cycles));
if(video_ += Cycles(int(cycles))) {
signal_interrupt(video_.last_valid()->get_interrupts());
}
cycles_since_audio_update_ += Cycles(int(cycles));
if(cycles_since_audio_update_ > Cycles(16384)) update_audio();
tape_.run_for(Cycles(int(cycles)));
cycles_until_display_interrupt_ -= cycles;
if(cycles_until_display_interrupt_ < 0) {
signal_interrupt(next_display_interrupt_);
update_display();
queue_next_display_interrupt();
}
if(typer_) typer_->run_for(Cycles(int(cycles)));
if(plus3_) plus3_->run_for(Cycles(4*int(cycles)));
if(shift_restart_counter_) {
@@ -517,25 +515,25 @@ template <bool has_scsi_bus> class ConcreteMachine:
}
forceinline void flush() {
update_display();
video_.flush();
update_audio();
audio_queue_.perform();
}
void set_scan_target(Outputs::Display::ScanTarget *scan_target) final {
video_output_.set_scan_target(scan_target);
video_->set_scan_target(scan_target);
}
Outputs::Display::ScanStatus get_scaled_scan_status() const final {
return video_output_.get_scaled_scan_status();
return video_->get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) final {
video_output_.set_display_type(display_type);
video_->set_display_type(display_type);
}
Outputs::Display::DisplayType get_display_type() const final {
return video_output_.get_display_type();
return video_->get_display_type();
}
Outputs::Speaker::Speaker *get_speaker() final {
@@ -693,18 +691,6 @@ template <bool has_scsi_bus> class ConcreteMachine:
}
// MARK: - Work deferral updates.
inline void update_display() {
if(cycles_since_display_update_ > 0) {
video_output_.run_for(cycles_since_display_update_.flush<Cycles>());
}
}
inline void queue_next_display_interrupt() {
VideoOutput::Interrupt next_interrupt = video_output_.get_next_interrupt();
cycles_until_display_interrupt_ = next_interrupt.cycles;
next_display_interrupt_ = next_interrupt.interrupt;
}
inline void update_audio() {
speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(SoundGenerator::clock_rate_divider)));
}
@@ -754,10 +740,7 @@ template <bool has_scsi_bus> class ConcreteMachine:
Electron::KeyboardMapper keyboard_mapper_;
// Counters related to simultaneous subsystems
Cycles cycles_since_display_update_ = 0;
Cycles cycles_since_audio_update_ = 0;
int cycles_until_display_interrupt_ = 0;
Interrupt next_display_interrupt_ = Interrupt::RealTimeClock;
VideoOutput::Range video_access_range_ = {0, 0xffff};
// Tape
@@ -794,7 +777,7 @@ template <bool has_scsi_bus> class ConcreteMachine:
}
// Outputs
VideoOutput video_output_;
JustInTimeActor<VideoOutput, Cycles> video_;
Concurrency::DeferringAsyncTaskQueue audio_queue_;
SoundGenerator sound_generator_;