mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-22 12:33:29 +00:00
Splits out the queue management stuff from queue+action.
Temporarily breaks ST video in the endeavour.
This commit is contained in:
parent
8c4fb0f688
commit
f0a6e0f3d5
@ -13,17 +13,10 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
A DeferredQueue maintains a list of ordered actions and the times at which
|
Provides the logic to insert into and traverse a list of future scheduled items.
|
||||||
they should happen, and divides a total execution period up into the portions
|
|
||||||
that occur between those actions, triggering each action when it is reached.
|
|
||||||
|
|
||||||
This list is efficient only for short queues.
|
|
||||||
*/
|
*/
|
||||||
template <typename TimeUnit> class DeferredQueue {
|
template <typename TimeUnit> class DeferredQueue {
|
||||||
public:
|
public:
|
||||||
/// Constructs a DeferredQueue that will call target(period) in between deferred actions.
|
|
||||||
DeferredQueue(std::function<void(TimeUnit)> &&target) : target_(std::move(target)) {}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Schedules @c action to occur in @c delay units of time.
|
Schedules @c action to occur in @c delay units of time.
|
||||||
*/
|
*/
|
||||||
@ -53,26 +46,23 @@ template <typename TimeUnit> class DeferredQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Runs for @c length units of time.
|
@returns The amount of time until the next enqueued action will occur,
|
||||||
|
or TimeUnit(-1) if the queue is empty.
|
||||||
The constructor-supplied target will be called with one or more periods that add up to @c length;
|
|
||||||
any scheduled actions will be called between periods.
|
|
||||||
*/
|
*/
|
||||||
void run_for(TimeUnit length) {
|
TimeUnit time_until_next_action() {
|
||||||
// If there are no pending actions, just run for the entire length.
|
if(pending_actions_.empty()) return TimeUnit(-1);
|
||||||
// This should be the normal branch.
|
return pending_actions_.front().delay;
|
||||||
if(pending_actions_.empty()) {
|
}
|
||||||
target_(length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divide the time to run according to the pending actions.
|
/*!
|
||||||
|
Advances the queue the specified amount of time, performing any actions it reaches.
|
||||||
|
*/
|
||||||
|
void advance(TimeUnit time) {
|
||||||
auto erase_iterator = pending_actions_.begin();
|
auto erase_iterator = pending_actions_.begin();
|
||||||
while(erase_iterator != pending_actions_.end()) {
|
while(erase_iterator != pending_actions_.end()) {
|
||||||
erase_iterator->delay -= length;
|
erase_iterator->delay -= time;
|
||||||
if(erase_iterator->delay <= TimeUnit(0)) {
|
if(erase_iterator->delay <= TimeUnit(0)) {
|
||||||
target_(length + erase_iterator->delay);
|
time = -erase_iterator->delay;
|
||||||
length = -erase_iterator->delay;
|
|
||||||
erase_iterator->action();
|
erase_iterator->action();
|
||||||
++erase_iterator;
|
++erase_iterator;
|
||||||
} else {
|
} else {
|
||||||
@ -82,14 +72,23 @@ template <typename TimeUnit> class DeferredQueue {
|
|||||||
if(erase_iterator != pending_actions_.begin()) {
|
if(erase_iterator != pending_actions_.begin()) {
|
||||||
pending_actions_.erase(pending_actions_.begin(), erase_iterator);
|
pending_actions_.erase(pending_actions_.begin(), erase_iterator);
|
||||||
}
|
}
|
||||||
if(length != TimeUnit(0)) {
|
}
|
||||||
target_(length);
|
|
||||||
|
/*!
|
||||||
|
Advances the queue by @c min(time_until_next_action(),duration) time.
|
||||||
|
*/
|
||||||
|
void advance_to_next(TimeUnit duration) {
|
||||||
|
if(pending_actions_.empty()) return;
|
||||||
|
|
||||||
|
auto front = pending_actions_.front();
|
||||||
|
front.delay -= duration;
|
||||||
|
if(front.delay <= TimeUnit(0)) {
|
||||||
|
front.action();
|
||||||
|
pending_actions_.erase(pending_actions_.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::function<void(TimeUnit)> target_;
|
|
||||||
|
|
||||||
// The list of deferred actions.
|
// The list of deferred actions.
|
||||||
struct DeferredAction {
|
struct DeferredAction {
|
||||||
TimeUnit delay;
|
TimeUnit delay;
|
||||||
@ -100,4 +99,38 @@ template <typename TimeUnit> class DeferredQueue {
|
|||||||
std::vector<DeferredAction> pending_actions_;
|
std::vector<DeferredAction> pending_actions_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A DeferredQueue maintains a list of ordered actions and the times at which
|
||||||
|
they should happen, and divides a total execution period up into the portions
|
||||||
|
that occur between those actions, triggering each action when it is reached.
|
||||||
|
|
||||||
|
This list is efficient only for short queues.
|
||||||
|
*/
|
||||||
|
template <typename TimeUnit> class DeferredQueuePerformer: public DeferredQueue<TimeUnit> {
|
||||||
|
public:
|
||||||
|
/// Constructs a DeferredQueue that will call target(period) in between deferred actions.
|
||||||
|
DeferredQueuePerformer(std::function<void(TimeUnit)> &&target) : target_(std::move(target)) {}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Runs for @c length units of time.
|
||||||
|
|
||||||
|
The constructor-supplied target will be called with one or more periods that add up to @c length;
|
||||||
|
any scheduled actions will be called between periods.
|
||||||
|
*/
|
||||||
|
void run_for(TimeUnit length) {
|
||||||
|
auto time_to_next = DeferredQueue<TimeUnit>::time_until_next_action();
|
||||||
|
while(time_to_next != TimeUnit(-1) && time_to_next <= length) {
|
||||||
|
target_(time_to_next);
|
||||||
|
length -= time_to_next;
|
||||||
|
DeferredQueue<TimeUnit>::advance_to_next(time_to_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeferredQueue<TimeUnit>::advance_to_next(length);
|
||||||
|
target_(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void(TimeUnit)> target_;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* DeferredQueue_h */
|
#endif /* DeferredQueue_h */
|
||||||
|
@ -255,7 +255,7 @@ class VideoBase {
|
|||||||
void output_fat_low_resolution(uint8_t *target, const uint8_t *source, size_t length, int column, int row) const;
|
void output_fat_low_resolution(uint8_t *target, const uint8_t *source, size_t length, int column, int row) const;
|
||||||
|
|
||||||
// Maintain a DeferredQueue for delayed mode switches.
|
// Maintain a DeferredQueue for delayed mode switches.
|
||||||
DeferredQueue<Cycles> deferrer_;
|
DeferredQueuePerformer<Cycles> deferrer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class BusHandler, bool is_iie> class Video: public VideoBase {
|
template <class BusHandler, bool is_iie> class Video: public VideoBase {
|
||||||
|
@ -327,7 +327,7 @@ void Video::advance(HalfCycles duration) {
|
|||||||
const bool next_display_enable = vertical_.enable && horizontal_.enable;
|
const bool next_display_enable = vertical_.enable && horizontal_.enable;
|
||||||
if(display_enable != next_display_enable) {
|
if(display_enable != next_display_enable) {
|
||||||
// Schedule change in outwardly-visible DE line.
|
// Schedule change in outwardly-visible DE line.
|
||||||
add_event(de_delay_period - integer_duration, next_display_enable ? Event::Type::SetDisplayEnable : Event::Type::ResetDisplayEnable);
|
// add_event(de_delay_period - integer_duration, next_display_enable ? Event::Type::SetDisplayEnable : Event::Type::ResetDisplayEnable);
|
||||||
|
|
||||||
// Schedule change in inwardly-visible effect.
|
// Schedule change in inwardly-visible effect.
|
||||||
next_load_toggle_ = x_ + 8; // 4 cycles = 8 half-cycles
|
next_load_toggle_ = x_ + 8; // 4 cycles = 8 half-cycles
|
||||||
@ -335,35 +335,35 @@ void Video::advance(HalfCycles duration) {
|
|||||||
|
|
||||||
if(horizontal_.sync != hsync) {
|
if(horizontal_.sync != hsync) {
|
||||||
// Schedule change in outwardly-visible hsync line.
|
// Schedule change in outwardly-visible hsync line.
|
||||||
add_event(hsync_delay_period - integer_duration, horizontal_.sync ? Event::Type::SetHsync : Event::Type::ResetHsync);
|
// add_event(hsync_delay_period - integer_duration, horizontal_.sync ? Event::Type::SetHsync : Event::Type::ResetHsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vertical_.sync != vsync) {
|
if(vertical_.sync != vsync) {
|
||||||
// Schedule change in outwardly-visible hsync line.
|
// Schedule change in outwardly-visible hsync line.
|
||||||
add_event(vsync_delay_period - integer_duration, vertical_.sync ? Event::Type::SetVsync : Event::Type::ResetVsync);
|
// add_event(vsync_delay_period - integer_duration, vertical_.sync ? Event::Type::SetVsync : Event::Type::ResetVsync);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effect any changes in visible state out here; they've been supplied as sequence points, so
|
// Effect any changes in visible state out here; they've been supplied as sequence points, so
|
||||||
// a conforming caller can't hit them within the inner loop.
|
// a conforming caller can't hit them within the inner loop.
|
||||||
integer_duration = int(duration.as_integral());
|
// integer_duration = int(duration.as_integral());
|
||||||
if(!pending_events_.empty()) {
|
// if(!pending_events_.empty()) {
|
||||||
auto erase_iterator = pending_events_.begin();
|
// auto erase_iterator = pending_events_.begin();
|
||||||
int duration_remaining = integer_duration;
|
// int duration_remaining = integer_duration;
|
||||||
while(erase_iterator != pending_events_.end()) {
|
// while(erase_iterator != pending_events_.end()) {
|
||||||
erase_iterator->delay -= duration_remaining;
|
// erase_iterator->delay -= duration_remaining;
|
||||||
if(erase_iterator->delay <= 0) {
|
// if(erase_iterator->delay <= 0) {
|
||||||
duration_remaining = -erase_iterator->delay;
|
// duration_remaining = -erase_iterator->delay;
|
||||||
erase_iterator->apply(public_state_);
|
// erase_iterator->apply(public_state_);
|
||||||
++erase_iterator;
|
// ++erase_iterator;
|
||||||
} else {
|
// } else {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if(erase_iterator != pending_events_.begin()) {
|
// if(erase_iterator != pending_events_.begin()) {
|
||||||
pending_events_.erase(pending_events_.begin(), erase_iterator);
|
// pending_events_.erase(pending_events_.begin(), erase_iterator);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::push_latched_data() {
|
void Video::push_latched_data() {
|
||||||
@ -417,8 +417,9 @@ HalfCycles Video::get_next_sequence_point() {
|
|||||||
int event_time = line_length_.length; // Worst case: report end of line.
|
int event_time = line_length_.length; // Worst case: report end of line.
|
||||||
|
|
||||||
// If any events are pending, give the first of those the chance to be next.
|
// If any events are pending, give the first of those the chance to be next.
|
||||||
if(!pending_events_.empty()) {
|
const auto next_deferred_item = deferrer_.time_until_next_action();
|
||||||
event_time = std::min(event_time, x_ + pending_events_.front().delay);
|
if(next_deferred_item != HalfCycles(-1)) {
|
||||||
|
event_time = std::min(event_time, next_deferred_item.as<int>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a vertically-enabled line, check for the display enable boundaries, + the standard delay.
|
// If this is a vertically-enabled line, check for the display enable boundaries, + the standard delay.
|
||||||
|
@ -122,7 +122,7 @@ class Video {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void advance(HalfCycles duration);
|
void advance(HalfCycles duration);
|
||||||
DeferredQueue<HalfCycles> deferrer_;
|
DeferredQueuePerformer<HalfCycles> deferrer_;
|
||||||
|
|
||||||
Outputs::CRT::CRT crt_;
|
Outputs::CRT::CRT crt_;
|
||||||
RangeObserver *range_observer_ = nullptr;
|
RangeObserver *range_observer_ = nullptr;
|
||||||
@ -270,7 +270,7 @@ class Video {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Event> pending_events_;
|
/* std::vector<Event> pending_events_;
|
||||||
void add_event(int delay, Event::Type type) {
|
void add_event(int delay, Event::Type type) {
|
||||||
// Apply immediately if there's no delay (or a negative delay).
|
// Apply immediately if there's no delay (or a negative delay).
|
||||||
if(delay <= 0) {
|
if(delay <= 0) {
|
||||||
@ -294,7 +294,7 @@ class Video {
|
|||||||
} else {
|
} else {
|
||||||
pending_events_.emplace_back(type, delay);
|
pending_events_.emplace_back(type, delay);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
friend class ::VideoTester;
|
friend class ::VideoTester;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user