timermanager: Pre-allocate TimerInfo.

Remove std::shared_ptr allocation/deallocation of TimerInfo structs.
This commit is contained in:
joevt authored and dingusdev committed 2026-09-25 20:12:05 -07:00
1 parent 3d5e2442d3
commit 529fff7d4d
39 files changed
+281 -200

No files matched your search

+22 -26
View File
@@ -30,51 +30,47 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
TimerManager* TimerManager::timer_manager;
uint32_t TimerManager::add_absolute_timer(uint64_t timeout_ns, uint64_t interval, timer_cb cb)
void TimerManager::add_absolute_timer(TimerInfo &ti, uint64_t timeout_ns, uint64_t interval, timer_cb cb)
{
TimerInfo* ti = new TimerInfo;
ti->id = ++this->id;
ti->timeout_ns = timeout_ns;
ti->interval_ns = interval;
ti->cb = cb;
std::shared_ptr<TimerInfo> timer_desc(ti);
ti.timeout_ns = timeout_ns;
ti.interval_ns = interval;
ti.active = true;
ti.cb = cb;
// add new timer to the timer queue
this->timer_queue.push(timer_desc);
//if (this->timer_queue.remove_by_id(&ti))
// LOG_F(ERROR, "timer was in queue!");
this->timer_queue.push(&ti);
// notify listeners about changes in the timer queue
if (!this->cb_active) {
this->notify_timer_changes();
}
return ti->id;
}
uint32_t TimerManager::add_oneshot_timer(uint64_t timeout, timer_cb cb)
void TimerManager::add_oneshot_timer(TimerInfo &ti, uint64_t timeout, timer_cb cb)
{
return TimerManager::add_absolute_timer(this->get_time_now() + timeout, 0, cb);
TimerManager::add_absolute_timer(ti, this->get_time_now() + timeout, 0, cb);
}
uint32_t TimerManager::add_immediate_timer(timer_cb cb)
void TimerManager::add_immediate_timer(TimerInfo &ti, timer_cb cb)
{
return TimerManager::add_absolute_timer(0, 0, cb);
TimerManager::add_absolute_timer(ti, 0, 0, cb);
}
uint32_t TimerManager::add_cyclic_timer(uint64_t interval, uint64_t delay, timer_cb cb)
void TimerManager::add_cyclic_timer(TimerInfo &ti, uint64_t interval, uint64_t delay, timer_cb cb)
{
return TimerManager::add_absolute_timer(this->get_time_now() + delay, interval, cb);
TimerManager::add_absolute_timer(ti, this->get_time_now() + delay, interval, cb);
}
uint32_t TimerManager::add_cyclic_timer(uint64_t interval, timer_cb cb)
void TimerManager::add_cyclic_timer(TimerInfo &ti, uint64_t interval, timer_cb cb)
{
return this->add_cyclic_timer(interval, interval, cb);
this->add_cyclic_timer(ti, interval, interval, cb);
}
void TimerManager::cancel_timer(uint32_t id)
void TimerManager::cancel_timer(TimerInfo &ti)
{
this->timer_queue.remove_by_id(id);
this->timer_queue.remove_by_id(&ti);
if (!this->cb_active) {
this->notify_timer_changes();
}
@@ -82,7 +78,7 @@ void TimerManager::cancel_timer(uint32_t id)
uint64_t TimerManager::process_timers()
{
std::shared_ptr<TimerInfo> cur_timer;
TimerInfo *cur_timer;
uint64_t time_now = get_time_now();
{ // mtx scope
@@ -95,7 +91,7 @@ uint64_t TimerManager::process_timers()
cur_timer = this->timer_queue.top();
} // ] mtx scope
while (cur_timer->timeout_ns <= time_now) {
this->timer_queue.remove_by_id(cur_timer->id);
this->timer_queue.remove_by_id(cur_timer);
uint64_t timeout_ns = cur_timer->timeout_ns;
timer_cb cb = cur_timer->cb;
@@ -133,10 +129,10 @@ uint64_t TimerManager::process_timers()
void TimerManager::cancel_all_timers()
{
std::shared_ptr<TimerInfo> cur_timer;
TimerInfo *cur_timer;
while (!this->timer_queue.empty()) {
cur_timer = this->timer_queue.top();
LOG_F(WARNING, "Canceling timer id:%u ns:%llu", cur_timer->id, cur_timer->timeout_ns);
LOG_F(WARNING, "Canceling timer id:%llu ns:%llu", uint64_t(cur_timer), cur_timer->timeout_ns);
this->timer_queue.pop();
}
}
+14 -16
View File
@@ -50,17 +50,17 @@ typedef std::function<void()> notify_changes_cb;
template <typename T, class Container = std::vector<T>, class Compare = std::less<typename Container::value_type>>
class my_priority_queue : public std::priority_queue<T, Container, Compare> {
public:
bool remove_by_id(const uint32_t id){
bool remove_by_id(T id){
std::lock_guard<std::recursive_mutex> lk(mtx);
if (this->empty())
return false;
auto el = this->top();
if (el->id == id) {
if (el == id) {
std::priority_queue<T, Container, Compare>::pop();
return true;
}
auto it = std::find_if(
this->c.begin(), this->c.end(), [id](const T& el) { return el->id == id; });
this->c.begin(), this->c.end(), [id](const T& el) { return el == id; });
if (it != this->c.end()) {
this->c.erase(it);
std::make_heap(this->c.begin(), this->c.end(), this->comp);
@@ -93,18 +93,18 @@ private:
};
typedef struct TimerInfo {
uint32_t id;
uint64_t timeout_ns; // timer expiry
uint64_t interval_ns; // 0 for one-shot timers
bool active = false; // set to true when added to the queue
timer_cb cb; // timer callback
} TimerInfo;
// Custom comparator for sorting our timer queue in ascending order
class MyGtComparator {
public:
bool operator()(const std::shared_ptr<TimerInfo>& l, const std::shared_ptr<TimerInfo>& r) const {
return l.get()->timeout_ns > r.get()->timeout_ns ||
(l.get()->timeout_ns == r.get()->timeout_ns && l.get()->id > r.get()->id);
bool operator()(const TimerInfo *l, const TimerInfo *r) const {
return l->timeout_ns > r->timeout_ns ||
(l->timeout_ns == r->timeout_ns && l > r);
}
};
@@ -131,12 +131,12 @@ public:
uint64_t current_time_ns() const { return get_time_now(); }
// creating and cancelling timers
uint32_t add_absolute_timer(uint64_t timeout_ns, uint64_t interval, timer_cb cb);
uint32_t add_oneshot_timer(uint64_t timeout, timer_cb cb);
uint32_t add_immediate_timer(timer_cb cb);
uint32_t add_cyclic_timer(uint64_t interval, timer_cb cb);
uint32_t add_cyclic_timer(uint64_t interval, uint64_t delay, timer_cb cb);
void cancel_timer(uint32_t id);
void add_absolute_timer(TimerInfo &ti, uint64_t timeout_ns, uint64_t interval, timer_cb cb);
void add_oneshot_timer(TimerInfo &ti, uint64_t timeout, timer_cb cb);
void add_immediate_timer(TimerInfo &ti, timer_cb cb);
void add_cyclic_timer(TimerInfo &ti, uint64_t interval, timer_cb cb);
void add_cyclic_timer(TimerInfo &ti, uint64_t interval, uint64_t delay, timer_cb cb);
void cancel_timer(TimerInfo &ti);
void cancel_all_timers();
uint64_t process_timers();
@@ -146,13 +146,11 @@ private:
TimerManager(){} // private constructor to implement a singleton
// timer queue
my_priority_queue<std::shared_ptr<TimerInfo>, std::vector<std::shared_ptr<TimerInfo>>, MyGtComparator> timer_queue;
my_priority_queue<TimerInfo*, std::vector<TimerInfo*>, MyGtComparator> timer_queue;
std::function<uint64_t()> get_time_now;
std::function<void()> notify_timer_changes;
std::atomic<uint32_t> id{0};
// FIXME: Do we need this? It gets written in main thread and read in audio thread.
bool cb_active = false; // true if a timer callback is executing
};
+7 -7
View File
@@ -909,7 +909,7 @@ static void update_timebase(uint64_t mask, uint64_t new_val)
tbr_wr_timestamp = get_virt_time_ns();
}
static uint32_t decrementer_timer_id = 0;
static TimerInfo decrementer_timer;
static void update_decrementer(bool update_time_stamp, uint32_t oldval, uint32_t newval);
@@ -926,7 +926,7 @@ static void trigger_decrementer_exception(uint64_t = 0, uint64_t = 0) {
}
static void trigger_timed_decrementer_exception(uint64_t, uint64_t) {
decrementer_timer_id = 0;
decrementer_timer.active = 0;
uint32_t new_val = calc_dec_value();
if (new_val >= 0 && new_val != uint32_t(-1)) {
new_val = -1;
@@ -936,7 +936,7 @@ static void trigger_timed_decrementer_exception(uint64_t, uint64_t) {
}
static void trigger_immediate_decrementer_exception(uint64_t, uint64_t) {
decrementer_timer_id = 0;
decrementer_timer.active = 0;
update_decrementer(false, ppc_state.spr[SPR::DEC_S], ppc_state.spr[SPR::DEC_S]);
trigger_decrementer_exception();
}
@@ -949,12 +949,12 @@ static void update_decrementer(bool update_time_stamp, uint32_t oldval, uint32_t
dec_exception_pending = false;
if (decrementer_timer_id) {
TimerManager::get_instance()->cancel_timer(decrementer_timer_id);
if (decrementer_timer.active) {
TimerManager::get_instance()->cancel_timer(decrementer_timer);
}
if (bit_changed(oldval, newval, 31) && bit_set(newval, 31)) {
decrementer_timer_id = TimerManager::get_instance()->add_immediate_timer(
TimerManager::get_instance()->add_immediate_timer(decrementer_timer,
trigger_immediate_decrementer_exception
);
return;
@@ -974,7 +974,7 @@ static void update_decrementer(bool update_time_stamp, uint32_t oldval, uint32_t
uint32_t time_out_lo;
_u32xu64(newval, tbr_period_ns, time_out, time_out_lo);
//LOG_F(WARNING, "new decrementer value: 0x%08X, interrupt after %llu ns", newval, time_out);
decrementer_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(decrementer_timer,
time_out,
trigger_timed_decrementer_exception
);
+2 -1
View File
@@ -1167,7 +1167,8 @@ void DppcDebugger::enter_debugger() {
cout << exc.what() << endl;
continue;
}
TimerManager::get_instance()->add_oneshot_timer(0, [irq_bit](uint64_t, uint64_t){
static TimerInfo viaint_timer;
TimerManager::get_instance()->add_oneshot_timer(viaint_timer, 0, [irq_bit](uint64_t, uint64_t){
ViaCuda* via_obj = dynamic_cast<ViaCuda*>(gMachineObj->get_comp_by_name("ViaCuda"));
via_obj->assert_int(irq_bit);
});
+33 -11
View File
@@ -77,8 +77,14 @@ uint16_t AtaBaseDevice::read(const uint8_t reg_addr) {
this->r_status &= ~DRQ;
} else {
this->chunk_cnt = std::min(this->xfer_cnt, this->chunk_size);
TimerManager::get_instance()->add_oneshot_timer(
USECS_TO_NSECS(100), [this](uint64_t, uint64_t) { this->update_intrq(1); });
if (this->read_data_timer.active)
LOG_F(ERROR, "%s: read_data_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(this->read_data_timer,
USECS_TO_NSECS(100), [this](uint64_t, uint64_t) {
this->read_data_timer.active = 0;
this->update_intrq(1);
}
);
}
}
return ret_data;
@@ -121,17 +127,27 @@ void AtaBaseDevice::write(const uint8_t reg_addr, const uint16_t value) {
this->xfer_cnt = 0;
this->r_status &= ~DRQ;
//LOG_F(INFO, "%s: write complete", name.c_str());
TimerManager::get_instance()->add_oneshot_timer(USECS_TO_NSECS(100), [this](uint64_t, uint64_t) {
this->r_status &= ~BSY;
this->update_intrq(1);
});
if (this->write_done_timer.active)
LOG_F(ERROR, "%s: write_done_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(write_done_timer,
USECS_TO_NSECS(100), [this](uint64_t, uint64_t) {
write_done_timer.active = 0;
this->r_status &= ~BSY;
this->update_intrq(1);
}
);
} else {
this->cur_data_ptr = this->data_ptr;
this->chunk_cnt = std::min(this->xfer_cnt, this->chunk_size);
//LOG_F(INFO, "%s: write needs more data (left: 0x%x)", name.c_str(), xfer_cnt);
TimerManager::get_instance()->add_oneshot_timer(USECS_TO_NSECS(100), [this](uint64_t, uint64_t) {
this->signal_data_ready();
});
if (this->write_more_timer.active)
LOG_F(ERROR, "%s: write_more_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(this->write_more_timer,
USECS_TO_NSECS(100), [this](uint64_t, uint64_t) {
this->write_more_timer.active = 0;
this->signal_data_ready();
}
);
}
}
}
@@ -213,7 +229,10 @@ int AtaBaseDevice::pull_data(uint8_t *buf, int len) {
if (!this->xfer_cnt) {
this->is_dma_xfer = false;
this->data_ptr = nullptr;
TimerManager::get_instance()->add_oneshot_timer(500, [this](uint64_t, uint64_t) {
if (this->dma_pull_timer.active)
LOG_F(ERROR, "%s: dma_pull_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(dma_pull_timer, 500, [this](uint64_t, uint64_t) {
dma_pull_timer.active = 0;
this->r_status &= ~(BSY | DRQ);
this->update_intrq(1);
});
@@ -240,7 +259,10 @@ int AtaBaseDevice::push_data(uint8_t *buf, int len) {
this->is_dma_xfer = false;
this->data_ptr = nullptr;
this->cur_data_ptr = nullptr;
TimerManager::get_instance()->add_oneshot_timer(500, [this](uint64_t, uint64_t) {
if (this->dma_push_timer.active)
LOG_F(ERROR, "%s: dma_push_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(dma_push_timer, 500, [this](uint64_t, uint64_t) {
dma_push_timer.active = 0;
this->r_status &= ~(BSY | DRQ);
this->update_intrq(1);
});
+7
View File
@@ -25,6 +25,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define ATA_BASE_DEVICE_H
#include <core/endianswap.h>
#include <core/timermanager.h>
#include <devices/common/ata/atadefs.h>
#include <devices/common/hwcomponent.h>
@@ -108,6 +109,12 @@ protected:
bool is_dma_xfer = false;
std::function<void()> post_xfer_action = nullptr;
TimerInfo read_data_timer;
TimerInfo write_done_timer;
TimerInfo write_more_timer;
TimerInfo dma_pull_timer;
TimerInfo dma_push_timer;
};
#endif // ATA_BASE_DEVICE_H
+3
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef ATA_HARD_DISK_H
#define ATA_HARD_DISK_H
#include <core/timermanager.h>
#include <devices/common/ata/atabasedevice.h>
#include <utils/imgfile.h>
@@ -74,6 +75,8 @@ private:
uint8_t cur_dma_mode = 2; // current multi-word DMA mode
char * buffer = new char[1 <<17];
TimerInfo signal_ready_timer;
};
#endif // ATA_HARD_DISK_H
+4 -1
View File
@@ -91,8 +91,11 @@ int IdeChannel::xfer_to(DmaChannel *ch_obj, uint8_t *buf, int len) {
}
void IdeChannel::assert_dmareq(uint64_t delay) {
TimerManager::get_instance()->add_oneshot_timer(delay, [this](uint64_t, uint64_t) {
if (this->dmareq_timer.active)
LOG_F(WARNING, "%s: dmareq_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(this->dmareq_timer, delay, [this](uint64_t, uint64_t) {
//LOG_F(INFO, "%s: DMAREQ asserted", this->name.c_str());
this->dmareq_timer.active = false;
this->channel_obj->xfer_retry();
});
}
+3
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef IDE_CHANNEL_H
#define IDE_CHANNEL_H
#include <core/timermanager.h>
#include <devices/common/ata/atadefs.h>
#include <devices/common/dmacore.h>
#include <devices/common/hwcomponent.h>
@@ -74,6 +75,8 @@ private:
AtaInterface* devices[2];
std::unique_ptr<AtaInterface> device_stub;
TimerInfo dmareq_timer;
};
/** This class models an IDE channel specific to MacIO ASICs. */
+6 -3
View File
@@ -291,9 +291,12 @@ void DMAChannel::update_irq(uint8_t cmd_bits) {
}
if (cond) {
if (int_ctrl) {
TimerManager::get_instance()->add_immediate_timer([this](uint64_t, uint64_t) {
this->int_ctrl->ack_dma_int(this->irq_id, 1);
});
if (!this->interrupt_timer.active) {
TimerManager::get_instance()->add_immediate_timer(this->interrupt_timer, [this](uint64_t, uint64_t) {
this->interrupt_timer.active = 0;
this->int_ctrl->ack_dma_int(this->irq_id, 1);
});
}
} else
LOG_F(ERROR, "%s Interrupt ignored", this->get_name().c_str());
}
+2
View File
@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef DB_DMA_H
#define DB_DMA_H
#include <core/timermanager.h>
#include <devices/common/dmacore.h>
#include <cinttypes>
@@ -173,6 +174,7 @@ private:
// Interrupt related stuff
InterruptCtrl* int_ctrl = nullptr;
uint64_t irq_id = 0;
TimerInfo interrupt_timer;
};
#endif // DB_DMA_H
+14 -14
View File
@@ -321,14 +321,14 @@ void Sc53C94::exec_command()
// assert RST line
this->bus_obj->assert_ctrl_line(this->my_bus_id, SCSI_CTRL_RST);
// release RST line after 25 us
if (my_timer_id) {
TimerManager::get_instance()->cancel_timer(this->my_timer_id);
my_timer_id = 0;
if (my_timer.active) {
TimerManager::get_instance()->cancel_timer(this->my_timer);
my_timer.active = 0;
}
my_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(my_timer,
USECS_TO_NSECS(25),
[this](uint64_t, uint64_t) {
my_timer_id = 0;
my_timer.active = 0;
this->bus_obj->release_ctrl_line(this->my_bus_id, SCSI_CTRL_RST);
});
if (!(config1 & CFG1_DISR)) {
@@ -477,25 +477,25 @@ uint8_t Sc53C94::fifo_pop()
void Sc53C94::seq_defer_state(uint64_t delay_ns)
{
if (this->seq_timer_id) {
TimerManager::get_instance()->cancel_timer(this->seq_timer_id);
this->seq_timer_id = 0;
if (this->seq_timer.active) {
TimerManager::get_instance()->cancel_timer(this->seq_timer);
this->seq_timer.active = 0;
}
if (delay_ns) {
this->seq_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->seq_timer,
delay_ns,
[this](uint64_t, uint64_t) {
// re-enter the sequencer with the state specified in next_state
this->seq_timer_id = 0;
this->seq_timer.active = 0;
this->cur_state = this->next_state;
this->sequencer();
});
} else {
this->seq_timer_id = TimerManager::get_instance()->add_immediate_timer(
TimerManager::get_instance()->add_immediate_timer(this->seq_timer,
[this](uint64_t, uint64_t) {
// re-enter the sequencer with the state specified in next_state
this->seq_timer_id = 0;
this->seq_timer.active = 0;
this->cur_state = this->next_state;
this->sequencer();
});
@@ -710,8 +710,8 @@ void Sc53C94::notify(ScsiNotification notif_type, int param)
case ScsiNotification::CONFIRM_SEL:
if (this->target_id == param) {
// cancel selection timeout timer
TimerManager::get_instance()->cancel_timer(this->seq_timer_id);
this->seq_timer_id = 0;
TimerManager::get_instance()->cancel_timer(this->seq_timer);
this->seq_timer.active = 0;
this->cur_state = SeqState::SEL_END;
this->sequencer();
} else {
+3 -2
View File
@@ -29,6 +29,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SC_53C94_H
#define SC_53C94_H
#include <core/timermanager.h>
#include <devices/common/scsi/scsi.h>
#include <devices/common/dbdma.h>
@@ -250,7 +251,7 @@ protected:
private:
uint8_t chip_id = 0;
uint8_t my_bus_id = 0;
uint32_t my_timer_id = 0;
TimerInfo my_timer;
uint8_t cmd_fifo[2];
uint8_t data_fifo[DATA_FIFO_MAX];
@@ -278,7 +279,7 @@ private:
uint8_t phase_latch = 0;
// sequencer state
uint32_t seq_timer_id = 0;
TimerInfo seq_timer;
uint32_t cur_state = 0;
uint32_t next_state = 0;
SeqDesc* cmd_steps = nullptr;
+3
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SCSI_H
#define SCSI_H
#include <core/timermanager.h>
#include <devices/common/hwcomponent.h>
#include <devices/common/scsi/scsiphysinterface.h>
@@ -369,6 +370,8 @@ protected:
more_data_cb_t read_more_data = {};
more_data_cb_t write_more_data = {};
TimerInfo bus_settle_timer;
};
/** This class provides a higher level abstraction for the SCSI bus. */
+8 -3
View File
@@ -31,10 +31,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace Scsi_Bus_Controller;
void ScsiBusController::seq_defer_state(uint64_t delay_ns) {
seq_timer_id = TimerManager::get_instance()->add_oneshot_timer(
if (this->seq_timer.active) {
TimerManager::get_instance()->cancel_timer(this->seq_timer);
this->seq_timer.active = 0;
}
TimerManager::get_instance()->add_oneshot_timer(this->seq_timer,
delay_ns,
[this](uint64_t, uint64_t) {
// re-enter the sequencer with the state specified in next_state
this->seq_timer.active = 0;
this->cur_state = this->next_state;
this->sequencer();
});
@@ -170,8 +175,8 @@ void ScsiBusController::notify(ScsiNotification notif_type, int param) {
case ScsiNotification::CONFIRM_SEL:
if (this->dst_id == param) {
// cancel selection timeout timer
TimerManager::get_instance()->cancel_timer(this->seq_timer_id);
seq_timer_id = 0;
TimerManager::get_instance()->cancel_timer(this->seq_timer);
this->seq_timer.active = false;
this->cur_state = SeqState::SEL_END;
this->sequencer();
} else {
+2 -1
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SCSI_BUS_CTRL_H
#define SCSI_BUS_CTRL_H
#include <core/timermanager.h>
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/scsi/scsi.h>
@@ -104,7 +105,7 @@ protected:
uint8_t data_fifo[DATA_FIFO_DEPTH] = {};
// Sequencer state
uint32_t seq_timer_id = 0;
TimerInfo seq_timer;
uint32_t cur_state = Scsi_Bus_Controller::SeqState::IDLE;
uint32_t next_state = Scsi_Bus_Controller::SeqState::IDLE;
int cur_bus_phase = 0;
+4 -1
View File
@@ -177,7 +177,10 @@ void ScsiHardDisk::format() {
if (this->cmd_buf[1] & 0x10)
ABORT_F("%s: defect list isn't supported yet", this->name.c_str());
TimerManager::get_instance()->add_oneshot_timer(NS_PER_SEC, [this](uint64_t, uint64_t) {
if (this->phase_switch_timer.active)
LOG_F(WARNING, "%s: phase_switch_timer is already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(this->phase_switch_timer, NS_PER_SEC, [this](uint64_t, uint64_t) {
this->phase_switch_timer.active = 0;
this->switch_phase(ScsiPhase::STATUS);
});
}
+2
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SCSI_HD_H
#define SCSI_HD_H
#include <core/timermanager.h>
#include <devices/common/scsi/scsi.h>
#include <devices/common/scsi/scsiblockcmds.h>
#include <devices/storage/blockstoragedevice.h>
@@ -55,6 +56,7 @@ protected:
private:
uint8_t data_buf[2048] = {};
TimerInfo phase_switch_timer;
};
#endif // SCSI_HD_H
+4 -1
View File
@@ -37,9 +37,12 @@ void ScsiPhysDevice::notify(ScsiNotification notif_type, int param)
// check if something tries to select us
if (this->bus_obj->get_data_lines() & (1 << scsi_id)) {
LOG_F(9, "device %d selected", this->scsi_id);
TimerManager::get_instance()->add_oneshot_timer(
if (this->bus_settle_timer.active)
LOG_F(ERROR, "%s: bus_settle_timer already active", this->get_name().c_str());
TimerManager::get_instance()->add_oneshot_timer(bus_settle_timer,
BUS_SETTLE_DELAY,
[this](uint64_t, uint64_t) {
this->bus_settle_timer.active = 0;
// don't confirm selection if BSY or I/O are asserted
if (this->bus_obj->test_ctrl_lines(SCSI_CTRL_BSY | SCSI_CTRL_IO))
return;
+32 -30
View File
@@ -99,21 +99,21 @@ ViaCuda::ViaCuda() : I2CBus() {
ViaCuda::~ViaCuda()
{
if (this->sr_timer_id) {
TimerManager::get_instance()->cancel_timer(this->sr_timer_id);
this->sr_timer_id = 0;
if (this->sr_timer.active) {
TimerManager::get_instance()->cancel_timer(this->sr_timer);
this->sr_timer.active = 0;
}
if (this->t1_timer_id) {
TimerManager::get_instance()->cancel_timer(this->t1_timer_id);
this->t1_timer_id = 0;
if (this->t1_timer.active) {
TimerManager::get_instance()->cancel_timer(this->t1_timer);
this->t1_timer.active = 0;
}
if (this->t2_timer_id) {
TimerManager::get_instance()->cancel_timer(this->t2_timer_id);
this->t2_timer_id = 0;
if (this->t2_timer.active) {
TimerManager::get_instance()->cancel_timer(this->t2_timer);
this->t2_timer.active = 0;
}
if (this->treq_timer_id) {
TimerManager::get_instance()->cancel_timer(this->treq_timer_id);
this->treq_timer_id = 0;
if (this->treq_timer.active) {
TimerManager::get_instance()->cancel_timer(this->treq_timer);
this->treq_timer.active = 0;
}
}
@@ -210,9 +210,9 @@ void ViaCuda::write(int reg, uint8_t value) {
break;
case VIA_T1CH:
// cancel active T1 timer task
if (this->t1_timer_id) {
TimerManager::get_instance()->cancel_timer(this->t1_timer_id);
this->t1_timer_id = 0;
if (this->t1_timer.active) {
TimerManager::get_instance()->cancel_timer(this->t1_timer);
this->t1_timer.active = 0;
}
// clear T1 flag in IFR
this->_via_ifr &= ~VIA_IF_T1;
@@ -237,9 +237,9 @@ void ViaCuda::write(int reg, uint8_t value) {
break;
case VIA_T2CH:
// cancel active T2 timer task
if (this->t2_timer_id) {
TimerManager::get_instance()->cancel_timer(this->t2_timer_id);
this->t2_timer_id = 0;
if (this->t2_timer.active) {
TimerManager::get_instance()->cancel_timer(this->t2_timer);
this->t2_timer.active = 0;
}
// clear T2 flag in IFR
this->_via_ifr &= ~VIA_IF_T2;
@@ -250,10 +250,10 @@ void ViaCuda::write(int reg, uint8_t value) {
// sample current vCPU time and remember it
this->t2_start_time = TimerManager::get_instance()->current_time_ns();
// set up timeout timer for T2
this->t2_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->t2_timer,
(this->via_clk_dur * (this->t2_counter + 3) + (uint64_t(1) << 36)) >> 37,
[this](uint64_t, uint64_t) {
this->t2_timer_id = 0;
this->t2_timer.active = 0;
this->assert_t2_int();
}
);
@@ -304,12 +304,12 @@ void ViaCuda::activate_t1() {
// sample current vCPU time and remember it
this->t1_start_time = TimerManager::get_instance()->current_time_ns();
// set up timout timer for T1
this->t1_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->t1_timer,
(this->via_clk_dur * (this->t1_counter + 3) + (uint64_t(1) << 36)) >> 37,
[this](uint64_t, uint64_t) {
// reload the T1 counter from the corresponding latches
this->t1_counter = (this->via_t1lh << 8) | this->via_t1ll;
this->t1_timer_id = 0;
this->t1_timer.active = 0;
this->assert_t1_int();
if (this->via_acr & 0x40)
this->activate_t1();
@@ -382,14 +382,14 @@ void ViaCuda::assert_ctrl_line(ViaLine line)
}
void ViaCuda::schedule_sr_int(uint64_t timeout_ns) {
if (this->sr_timer_id) {
TimerManager::get_instance()->cancel_timer(this->sr_timer_id);
this->sr_timer_id = 0;
if (this->sr_timer.active) {
TimerManager::get_instance()->cancel_timer(this->sr_timer);
this->sr_timer.active = 0;
}
this->sr_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->sr_timer,
timeout_ns,
[this](uint64_t, uint64_t) {
this->sr_timer_id = 0;
this->sr_timer.active = 0;
this->assert_sr_int();
}
);
@@ -420,12 +420,14 @@ void ViaCuda::write(uint8_t new_state) {
process_packet();
// start response transaction
this->treq_timer_id = TimerManager::get_instance()->add_oneshot_timer(
if (this->treq_timer.active)
LOG_F(ERROR, "Cuda: treq_timer is already active");
TimerManager::get_instance()->add_oneshot_timer(this->treq_timer,
USECS_TO_NSECS(13), // delay TREQ assertion for New World
[this](uint64_t, uint64_t) {
this->via_portb &= ~CUDA_TREQ; // assert TREQ
this->treq = 0;
this->treq_timer_id = 0;
this->treq_timer.active = 0;
});
}
@@ -618,7 +620,7 @@ void ViaCuda::autopoll_handler() {
// Don't send one-second packets if a command response is pending.
// Unlike autopoll, time packets are not urgent enough to preempt.
if (!this->treq || this->treq_timer_id || this->sr_timer_id) {
if (!this->treq || this->treq_timer.active || this->sr_timer.active) {
// ERS: track missed ticks for mode $02/$03 fallback
if (this_time != this->last_time)
this->one_sec_missed = true;
+5 -4
View File
@@ -42,6 +42,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef VIACUDA_H
#define VIACUDA_H
#include <core/timermanager.h>
#include <devices/common/i2c/i2c.h>
#include <devices/common/nvram.h>
@@ -198,20 +199,20 @@ private:
uint32_t via_clk_freq; // 0.00078336 VIA clock periods per ns; 0 integer bits, 42 fraction bits (first 10 are implicit zeros)
// VIA internal state
uint32_t sr_timer_id = 0;
TimerInfo sr_timer;
uint8_t last_orb = 0; // last value written to the ORB register.
// timer 1 state
uint8_t via_t1ll; // low-order latch
uint8_t via_t1lh; // high-order latch
uint16_t t1_counter; // internal counter
uint32_t t1_timer_id = 0;
TimerInfo t1_timer;
uint64_t t1_start_time = 0;
// timer 2 state
uint8_t via_t2ll; // low-order latch (write-only)
uint16_t t2_counter; // internal counter
uint32_t t2_timer_id = 0;
TimerInfo t2_timer;
uint64_t t2_start_time = 0;
// VIA interrupt related stuff
@@ -225,7 +226,7 @@ private:
uint8_t old_byteack;
uint8_t treq;
bool is_sync_state = false;
uint32_t treq_timer_id = 0;
TimerInfo treq_timer;
uint8_t in_buf[CUDA_IN_BUF_SIZE];
int32_t in_count;
int max_in_count = 0;
+29 -24
View File
@@ -70,17 +70,17 @@ void Swim3Ctrl::reset()
this->timer_val = 0;
this->phase_lines = 0;
if (this->one_us_timer_id) {
TimerManager::get_instance()->cancel_timer(this->one_us_timer_id);
this->one_us_timer_id = 0;
if (this->one_us_timer.active) {
TimerManager::get_instance()->cancel_timer(this->one_us_timer);
this->one_us_timer.active = 0;
}
if (this->step_timer_id) {
TimerManager::get_instance()->cancel_timer(this->step_timer_id);
this->step_timer_id = 0;
if (this->step_timer.active) {
TimerManager::get_instance()->cancel_timer(this->step_timer);
this->step_timer.active = 0;
}
if (this->access_timer_id) {
TimerManager::get_instance()->cancel_timer(this->access_timer_id);
this->access_timer_id = 0;
if (this->access_timer.active) {
TimerManager::get_instance()->cancel_timer(this->access_timer);
this->access_timer.active = 0;
}
}
@@ -237,7 +237,7 @@ void Swim3Ctrl::do_step()
// instruct the drive to perform single step in current direction
this->int_drive->command(MacSuperdrive::CommandAddr::Do_Step, 0);
if (--this->step_count == 0) {
if (this->step_timer_id) {
if (this->step_timer.active) {
this->stop_stepping();
}
this->int_flags |= INT_STEP_DONE;
@@ -253,12 +253,12 @@ void Swim3Ctrl::start_stepping()
return;
}
if (this->mode_reg & SWIM3_GO_STEP || this->step_timer_id) {
if (this->mode_reg & SWIM3_GO_STEP || this->step_timer.active) {
LOG_F(ERROR, "SWIM3: another stepping action is running!");
return;
}
if (this->mode_reg & SWIM3_GO || this->access_timer_id) {
if (this->mode_reg & SWIM3_GO || this->access_timer.active) {
LOG_F(ERROR, "SWIM3: stepping attempt while disk access is in progress!");
return;
}
@@ -273,7 +273,7 @@ void Swim3Ctrl::start_stepping()
// step count > 1 requires periodic task
if (this->step_count > 1) {
this->step_timer_id = TimerManager::get_instance()->add_cyclic_timer(
TimerManager::get_instance()->add_cyclic_timer(this->step_timer,
USECS_TO_NSECS(80),
[this](uint64_t, uint64_t) {
this->do_step();
@@ -288,21 +288,21 @@ void Swim3Ctrl::start_stepping()
void Swim3Ctrl::stop_stepping()
{
// cancel stepping task
if (this->step_timer_id) {
TimerManager::get_instance()->cancel_timer(this->step_timer_id);
this->step_timer_id = 0;
if (this->step_timer.active) {
TimerManager::get_instance()->cancel_timer(this->step_timer);
this->step_timer.active = 0;
}
this->step_count = 0; // not sure this one is required
}
void Swim3Ctrl::start_disk_access()
{
if (this->mode_reg & SWIM3_GO || this->access_timer_id) {
if (this->mode_reg & SWIM3_GO || this->access_timer.active) {
LOG_F(ERROR, "SWIM3: another disk access is running!");
return;
}
if (this->mode_reg & SWIM3_GO_STEP || this->step_timer_id) {
if (this->mode_reg & SWIM3_GO_STEP || this->step_timer.active) {
LOG_F(ERROR, "SWIM3: disk access attempt while stepping is in progress!");
return;
}
@@ -317,9 +317,10 @@ void Swim3Ctrl::start_disk_access()
this->target_sect = this->first_sec;
this->access_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->access_timer,
this->int_drive->sync_to_disk(),
[this](uint64_t, uint64_t) {
this->access_timer.active = 0;
this->cur_state = SWIM3_ADDR_MARK_SEARCH;
this->disk_access();
}
@@ -369,9 +370,10 @@ void Swim3Ctrl::disk_access()
return;
}
this->access_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->access_timer,
delay,
[this](uint64_t, uint64_t) {
this->access_timer.active = 0;
this->disk_access();
}
);
@@ -380,9 +382,9 @@ void Swim3Ctrl::disk_access()
void Swim3Ctrl::stop_disk_access()
{
// cancel disk access timer
if (this->access_timer_id) {
TimerManager::get_instance()->cancel_timer(this->access_timer_id);
this->access_timer_id = 0;
if (this->access_timer.active) {
TimerManager::get_instance()->cancel_timer(this->access_timer);
this->access_timer.active = 0;
}
}
@@ -399,9 +401,12 @@ void Swim3Ctrl::init_timer(const uint8_t start_val)
this->one_us_timer_start = TimerManager::get_instance()->current_time_ns();
this->one_us_timer_id = TimerManager::get_instance()->add_oneshot_timer(
if( this->one_us_timer.active)
LOG_F(ERROR, "SWIM3: one_us_timer is already active");
TimerManager::get_instance()->add_oneshot_timer(this->one_us_timer,
uint32_t(this->timer_val) * NS_PER_USEC,
[this](uint64_t, uint64_t) {
this->one_us_timer.active = 0;
this->timer_val = 0;
this->int_flags |= INT_TIMER_DONE;
update_irq();
+3 -3
View File
@@ -140,9 +140,9 @@ private:
uint8_t rd_line;
int cur_state;
int one_us_timer_id = 0;
int step_timer_id = 0;
int access_timer_id = 0;
TimerInfo one_us_timer;
TimerInfo step_timer;
TimerInfo access_timer;
uint64_t one_us_timer_start = 0;
+8 -5
View File
@@ -96,9 +96,9 @@ AMIC::AMIC() : MMIODevice()
AMIC::~AMIC()
{
if (this->pseudo_vbl_tid) {
TimerManager::get_instance()->cancel_timer(this->pseudo_vbl_tid);
this->pseudo_vbl_tid = 0;
if (this->pseudo_vbl_timer.active) {
TimerManager::get_instance()->cancel_timer(this->pseudo_vbl_timer);
this->pseudo_vbl_timer.active = 0;
}
}
@@ -113,7 +113,7 @@ int AMIC::device_postinit()
}
// AMIC drives the VIA CA1 internally to generate 60.15 Hz interrupts
this->pseudo_vbl_tid = TimerManager::get_instance()->add_cyclic_timer(
TimerManager::get_instance()->add_cyclic_timer(pseudo_vbl_timer,
static_cast<uint64_t>((1.0f/60.15) * NS_PER_SEC + 0.5f),
[this](uint64_t, uint64_t) {
this->viacuda->assert_ctrl_line(ViaLine::CA1);
@@ -635,7 +635,10 @@ void AmicSndOutDma::update_irq() {
uint8_t new_level = !!((this->dma_out_ctrl >> 4) & this->dma_out_ctrl);
if (new_level != this->irq_level) {
this->irq_level = new_level;
TimerManager::get_instance()->add_immediate_timer([this](uint64_t, uint64_t) {
if (this->interrupt_timer.active)
LOG_F(ERROR, "AMIC: interrupt_timer is already active");
TimerManager::get_instance()->add_immediate_timer(interrupt_timer, [this](uint64_t, uint64_t) {
interrupt_timer.active = 0;
this->int_ctrl->ack_dma_int(this->snd_dma_irq_id, this->irq_level);
});
}
+3 -1
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef AMIC_H
#define AMIC_H
#include <core/timermanager.h>
#include <devices/common/dmacore.h>
#include <devices/common/hwinterrupt.h>
#include <devices/common/mmiodevice.h>
@@ -133,6 +134,7 @@ private:
InterruptCtrl *int_ctrl = nullptr;
uint64_t snd_dma_irq_id = 0;
uint8_t irq_level = 0;
TimerInfo interrupt_timer;
};
/** AMIC-specific floppy DMA implementation. */
@@ -411,7 +413,7 @@ private:
uint8_t via2_slot_ifr = 0x7F; // reverse logic
uint8_t via2_slot_irq = 0; // normal logic
uint32_t pseudo_vbl_tid = 0; // ID for the pseudo-VBL timer
TimerInfo pseudo_vbl_timer; // the pseudo-VBL timer
// AMIC subdevice instances
Sc53C94* scsi;
+3 -3
View File
@@ -586,10 +586,10 @@ void PlatinumCtrl::enable_cursor_int() {
LOG_F(INFO, "%s: cursor interrupt frequency %lld ns", this->name.c_str(),
cursor_int_freq);
if (this->cursor_task_id)
TimerManager::get_instance()->cancel_timer(this->cursor_task_id);
if (this->cursor_timer.active)
TimerManager::get_instance()->cancel_timer(this->cursor_timer);
this->cursor_task_id = TimerManager::get_instance()->add_cyclic_timer(
TimerManager::get_instance()->add_cyclic_timer(this->cursor_timer,
cursor_int_freq,
[this](uint64_t, uint64_t) {
this->update_irq(1, SWATCH_INT_CURSOR); // generate cursor interrupt
+1 -1
View File
@@ -363,7 +363,7 @@ private:
uint32_t swatch_int_mask = 0;
uint32_t swatch_int_stat = 0;
uint32_t cursor_line = 0;
uint32_t cursor_task_id = 0;
TimerInfo cursor_timer;
std::unique_ptr<uint8_t[]> vram_ptr = nullptr;
std::unique_ptr<DisplayID> display_id = nullptr;
+7 -5
View File
@@ -114,11 +114,13 @@ void AwacsBase::dma_in_data() {
dbdma_ch->set_stat(sound_in_status);
LOG_F(INFO, "%s: status:%x", this->name.c_str(), sound_in_status);
this->dma_in_timer_id = TimerManager::get_instance()->add_oneshot_timer(
if (this->dma_in_timer.active)
LOG_F(ERROR, "%s: dma_in_timer is already active", this->name.c_str());
TimerManager::get_instance()->add_oneshot_timer(this->dma_in_timer,
10000,
[this](uint64_t, uint64_t) {
// re-enter the sequencer with the state specified in next_state
this->dma_in_timer_id = 0;
this->dma_in_timer.active = 0;
this->dma_in_data();
});
}
@@ -130,9 +132,9 @@ void AwacsBase::dma_in_start() {
}
void AwacsBase::dma_in_stop() {
if (this->dma_in_timer_id) {
TimerManager::get_instance()->cancel_timer(this->dma_in_timer_id);
this->dma_in_timer_id = 0;
if (this->dma_in_timer.active) {
TimerManager::get_instance()->cancel_timer(this->dma_in_timer);
this->dma_in_timer.active = 0;
}
LOG_F(ERROR, "%s: dma_in_stop", this->name.c_str());
}
+1 -1
View File
@@ -66,7 +66,7 @@ protected:
SoundServer *snd_server; // SoundServer instance pointer
DmaOutChannel *dma_out_ch; // DMA output channel instance pointer
DmaInChannel *dma_in_ch; // DMA input channel instance pointer
uint32_t dma_in_timer_id = 0;
TimerInfo dma_in_timer;
int *sr_table; // pointer to the table of supported sample rates
int max_sr_id; // maximum value for sample rate ID
+4 -1
View File
@@ -113,9 +113,12 @@ void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) {
this->data_byte = ((reg_addr < BURGUNDY_NUM_REGS ? this->reg_array[reg_addr] : 0) >> (cur_byte * 8)) & 0xFFU;
this->first_valid = true;
TimerManager::get_instance()->add_oneshot_timer(
if (this->first_valid_timer.active)
LOG_F(ERROR, "%s: first_valid_timer is already active", this->name.c_str());
TimerManager::get_instance()->add_oneshot_timer(this->first_valid_timer,
USECS_TO_NSECS(22), // average is approximately 22.6 µs on a real B&W G3
[this](uint64_t, uint64_t) {
this->first_valid_timer.active = 0;
this->first_valid = false;
this->byte_counter = (this->byte_counter + 1) & 3;
});
+2
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef BURGUNDY_H
#define BURGUNDY_H
#include <core/timermanager.h>
#include <devices/common/hwcomponent.h>
#include <devices/sound/awacs.h>
@@ -126,6 +127,7 @@ private:
uint8_t byte_counter = 0;
uint8_t reg_addr = 0;
bool first_valid = false;
TimerInfo first_valid_timer;
uint8_t read_pos = 0;
uint8_t data_byte = 0;
uint32_t frame_count = 0;
+8 -8
View File
@@ -51,7 +51,7 @@ public:
cubeb *cubeb_ctx;
cubeb_stream *out_stream;
uint32_t deterministic_poll_timer = 0;
TimerInfo deterministic_poll_timer;
timer_cb deterministic_poll_cb;
};
@@ -228,8 +228,8 @@ int SoundServer::start_out_stream()
{
if (is_deterministic) {
LOG_F(9, "Starting sound output deterministic polling.");
impl->deterministic_poll_timer =
TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(10), impl->deterministic_poll_cb);
TimerManager::get_instance()->add_cyclic_timer(
impl->deterministic_poll_timer, MSECS_TO_NSECS(10), impl->deterministic_poll_cb);
return 0;
}
int res = cubeb_stream_start(impl->out_stream);
@@ -237,9 +237,9 @@ int SoundServer::start_out_stream()
// Fall back to draining the guest sound DMA via a cyclic timer so
// that the guest sound driver does not stall waiting for DMA progress
// that the failed host stream will never provide.
if (!impl->deterministic_poll_timer) {
impl->deterministic_poll_timer =
TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(10), impl->deterministic_poll_cb);
if (!impl->deterministic_poll_timer.active) {
TimerManager::get_instance()->add_cyclic_timer(
impl->deterministic_poll_timer, MSECS_TO_NSECS(10), impl->deterministic_poll_cb);
LOG_F(9, "Host sound output stream start failed; falling back to cyclic DMA drain.");
}
}
@@ -248,9 +248,9 @@ int SoundServer::start_out_stream()
void SoundServer::close_out_stream()
{
if (impl->deterministic_poll_timer) {
if (impl->deterministic_poll_timer.active) {
TimerManager::get_instance()->cancel_timer(impl->deterministic_poll_timer);
impl->deterministic_poll_timer = 0;
impl->deterministic_poll_timer.active = 0;
}
if (!impl->out_stream) {
impl->status = SND_STREAM_CLOSED;
+11 -9
View File
@@ -89,9 +89,9 @@ void AppleRamdac::iodev_write(uint32_t address, uint16_t value) {
switch (this->dac_addr) {
case RamdacRegs::CURSOR_POS_HI:
#ifdef CURSOR_LO_DELAY // HACK: prevents artifacts in some cases, disabled by default
if (this->cursor_timer_id) {
TimerManager::get_instance()->cancel_timer(this->cursor_timer_id);
cursor_timer_id = 0;
if (this->cursor_timer.active) {
TimerManager::get_instance()->cancel_timer(this->cursor_timer);
cursor_timer.active = 0;
}
this->cursor_xpos = (value << 8) | this->cursor_pos_lo;
#else
@@ -100,16 +100,18 @@ void AppleRamdac::iodev_write(uint32_t address, uint16_t value) {
break;
case RamdacRegs::CURSOR_POS_LO:
#ifdef CURSOR_LO_DELAY // HACK: prevents artifacts in some cases, disabled by default
if (this->cursor_timer_id) {
TimerManager::get_instance()->cancel_timer(this->cursor_timer_id);
if (this->cursor_timer.active) {
TimerManager::get_instance()->cancel_timer(this->cursor_timer);
this->cursor_xpos = (this->cursor_xpos & 0xff00) | (this->cursor_pos_lo & 0x00ff);
cursor_timer_id = 0;
cursor_timer.active = 0;
}
this->cursor_pos_lo = value;
this->cursor_timer_id = TimerManager::get_instance()->add_oneshot_timer(
this->cursor_pos_lo = value;
TimerManager::get_instance()->add_oneshot_timer(this->cursor_timer,
NS_PER_SEC / 60, [this](uint64_t, uint64_t) {
this->cursor_xpos = (this->cursor_xpos & 0xff00) | (this->cursor_pos_lo & 0x00ff);
});
cursor_timer.active = 0;
}
);
#else
this->cursor_xpos = (this->cursor_xpos & 0xff00) | (value & 0x00ff);
#endif
+1 -1
View File
@@ -139,7 +139,7 @@ protected:
uint32_t fb_pitch = 0;
#ifdef CURSOR_LO_DELAY
uint8_t cursor_pos_lo = 0;
uint32_t cursor_timer_id = 0;
TimerInfo cursor_timer;
#endif
};
+4 -3
View File
@@ -189,11 +189,12 @@ void ValkyrieVideo::disable_video_internal() {
}
void ValkyrieVideo::schedule_mode_switch() {
if (this->mode_timer_id)
TimerManager::get_instance()->cancel_timer(this->mode_timer_id);
if (this->mode_timer.active)
TimerManager::get_instance()->cancel_timer(this->mode_timer);
this->mode_timer_id = TimerManager::get_instance()->add_oneshot_timer(
TimerManager::get_instance()->add_oneshot_timer(this->mode_timer,
MSECS_TO_NSECS(3), [this](uint64_t, uint64_t) {
this->mode_timer.active = 0;
this->enable_video_internal();
});
}
+1 -1
View File
@@ -101,7 +101,7 @@ private:
uint8_t *vram_ptr = nullptr;
int reg_shift = 3;
uint64_t mode_timer_id = 0;
TimerInfo mode_timer;
void disable_video_internal();
void enable_video_internal();
+8 -8
View File
@@ -102,7 +102,7 @@ void VideoCtrlBase::start_refresh_task() {
this->display.configure(this->active_width, this->active_height);
uint64_t refresh_interval = static_cast<uint64_t>(1.0f / refresh_rate * NS_PER_SEC + 0.5);
this->refresh_task_id = TimerManager::get_instance()->add_cyclic_timer(
TimerManager::get_instance()->add_cyclic_timer(this->refresh_timer,
refresh_interval,
[this](uint64_t, uint64_t) {
// assert VBL interrupt
@@ -117,7 +117,7 @@ void VideoCtrlBase::start_refresh_task() {
}
uint64_t vbl_duration = static_cast<uint64_t>((double)hori_total * vert_blank / this->pixel_clock * NS_PER_SEC + 0.5);
this->vbl_end_task_id = TimerManager::get_instance()->add_cyclic_timer(
TimerManager::get_instance()-> add_cyclic_timer(this->vbl_end_timer,
refresh_interval,
refresh_interval + vbl_duration,
[this](uint64_t, uint64_t) {
@@ -128,13 +128,13 @@ void VideoCtrlBase::start_refresh_task() {
}
void VideoCtrlBase::stop_refresh_task() {
if (this->refresh_task_id) {
TimerManager::get_instance()->cancel_timer(this->refresh_task_id);
this->refresh_task_id = 0;
if (this->refresh_timer.active) {
TimerManager::get_instance()->cancel_timer(this->refresh_timer);
this->refresh_timer.active = 0;
}
if (this->vbl_end_task_id) {
TimerManager::get_instance()->cancel_timer(this->vbl_end_task_id);
this->vbl_end_task_id = 0;
if (this->vbl_end_timer.active) {
TimerManager::get_instance()->cancel_timer(this->vbl_end_timer);
this->vbl_end_timer.active = 0;
}
}
+3 -2
View File
@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef VIDEO_CTRL_H
#define VIDEO_CTRL_H
#include <core/timermanager.h>
#include <devices/common/hwinterrupt.h>
#include <devices/video/display.h>
@@ -113,8 +114,8 @@ protected:
// Framebuffer parameters
uint8_t* fb_ptr = nullptr;
int fb_pitch = 0;
uint32_t refresh_task_id = 0;
uint32_t vbl_end_task_id = 0;
TimerInfo refresh_timer;
TimerInfo vbl_end_timer;
// interrupt suff
InterruptCtrl* int_ctrl = nullptr;
+4 -3
View File
@@ -382,12 +382,12 @@ void run_machine(std::string machine_str, char* rom_data,
}
}
uint32_t deterministic_timer = 0;
static TimerInfo deterministic_timer;
if (is_deterministic && !deterministic_interactive) {
EventManager::get_instance()->disable_input_handlers();
// Log the PC and instruction every second to make it easier to validate
// that execution is the same every time.
deterministic_timer = TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(1000), [](uint64_t, uint64_t) {
TimerManager::get_instance()->add_cyclic_timer(deterministic_timer, MSECS_TO_NSECS(1000), [](uint64_t, uint64_t) {
// We may be running after an exceptions or RFI changed the address
// translation context. In those cases the PC address cannot be
// translated (it would either be stale or invalid).
@@ -410,7 +410,8 @@ void run_machine(std::string machine_str, char* rom_data,
// set up system wide event polling using
// default Macintosh polling rate of 11 ms
uint32_t event_timer = TimerManager::get_instance()->add_cyclic_timer(MSECS_TO_NSECS(11), [](uint64_t, uint64_t) {
static TimerInfo event_timer;
TimerManager::get_instance()->add_cyclic_timer(event_timer, MSECS_TO_NSECS(11), [](uint64_t, uint64_t) {
EventManager::get_instance()->poll_events();
});