mirror of
https://github.com/dingusdev/dingusppc.git
synced 2026-10-22 12:02:34 +00:00
timermanager: Pre-allocate TimerInfo.
Remove std::shared_ptr allocation/deallocation of TimerInfo structs.
This commit is contained in:
1 parent
3d5e2442d3
commit
529fff7d4d
39 files changed
+281
-200
No files matched your search
+22
-26
@@ -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
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user