#include "sim_time.h"
#include "sim_cycle_timers.h"
-#if 0
-#define DEBUG(__w) __w
-#define DUMP(_pool,_w) { \
- printf("%s:%d %s ",__func__,__LINE__, _w);\
- for (int _i=0;_i<_pool->count;_i++) \
- printf("[%2d:%7d] ",_i,(int)_pool->timer[_i].when);\
- printf("\n");\
-}
-#else
-#define DEBUG(__w)
-#define DUMP(_pool,_w)
-#endif
+#define QUEUE(__q, __e) { (__e)->next = (__q); (__q) = __e; }
+#define DETACH(__q, __l, __e) { \
+ if ((__l)) (__l)->next = (__e)->next; \
+ else (__q) = (__e)->next; \
+ }
+#define INSERT(__q, __l, __e) { \
+ if ((__l)) (__e)->next = (__l)->next; \
+ else { (__e)->next = (__q); (__q) = (__e); } \
+ }
void
avr_cycle_timer_reset(
{
avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
memset(pool, 0, sizeof(*pool));
+ // queue all slots into the free queue
+ for (int i = 0; i < MAX_CYCLE_TIMERS; i++) {
+ avr_cycle_timer_slot_p t = &pool->timer_slots[i];
+ QUEUE(pool->timer_free, t);
+ }
}
// no sanity checks checking here, on purpose
when += avr->cycle;
+ avr_cycle_timer_slot_p t = pool->timer_free;
+
+ if (!t) {
+ AVR_LOG(avr, LOG_ERROR, "CYCLE: %s: ran out of timers (%d)!\n", __func__, MAX_CYCLE_TIMERS);
+ return;
+ }
+ // detach head
+ pool->timer_free = t->next;
+ t->next = NULL;
+ t->timer = timer;
+ t->param = param;
+ t->when = when;
+
// find its place in the list
- int inserti = 0;
- while (inserti < pool->count && pool->timer[inserti].when > when)
- inserti++;
- // make a hole
- int cnt = pool->count - inserti;
- if (cnt)
- memmove(&pool->timer[inserti + 1], &pool->timer[inserti],
- cnt * sizeof(avr_cycle_timer_slot_t));
-
- pool->timer[inserti].timer = timer;
- pool->timer[inserti].param = param;
- pool->timer[inserti].when = when;
- pool->count++;
- DEBUG(printf("%s %2d/%2d when %7d %p/%p\n", __func__, inserti, pool->count, (int)(when - avr->cycle), timer, param);)
- DUMP(pool, "after");
+ avr_cycle_timer_slot_p loop = pool->timer, last = NULL;
+ while (loop) {
+ if (loop->when > when)
+ break;
+ last = loop;
+ loop = loop->next;
+ }
+ INSERT(pool->timer, last, t);
}
void
// remove it if it was already scheduled
avr_cycle_timer_cancel(avr, timer, param);
- if (pool->count == MAX_CYCLE_TIMERS) {
+ if (!pool->timer_free) {
AVR_LOG(avr, LOG_ERROR, "CYCLE: %s: pool is full (%d)!\n", __func__, MAX_CYCLE_TIMERS);
return;
}
{
avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
- for (int i = 0; i < pool->count; i++)
- if (pool->timer[i].timer == timer && pool->timer[i].param == param) {
- int cnt = pool->count - i - 1;
- DEBUG(printf("%s %2d when %7d %p/%p\n", __func__, i, (int)(pool->timer[i].when - avr->cycle), timer, param);)
- if (cnt)
- memmove(&pool->timer[i], &pool->timer[i+1],
- cnt * sizeof(avr_cycle_timer_slot_t));
- pool->count--;
- DUMP(pool, "after");
- return;
+ // find its place in the list
+ avr_cycle_timer_slot_p t = pool->timer, last = NULL;
+ while (t) {
+ if (t->timer == timer && t->param == param) {
+ DETACH(pool->timer, last, t);
+ QUEUE(pool->timer_free, t);
+ break;
}
+ last = t;
+ t = t->next;
+ }
}
/*
{
avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
- for (int i = 0; i < pool->count; i++)
- if (pool->timer[i].timer == timer && pool->timer[i].param == param) {
- return 1 + (pool->timer[i].when - avr->cycle);
+ // find its place in the list
+ avr_cycle_timer_slot_p t = pool->timer;
+ while (t) {
+ if (t->timer == timer && t->param == param) {
+ return 1 + (t->when - avr->cycle);
}
-
+ t->next = pool->timer_free;
+ }
return 0;
}
{
avr_cycle_timer_pool_t * pool = &avr->cycle_timers;
- if (!pool->count)
+ if (!pool->timer)
return (avr_cycle_count_t)1000;
- do {
- // copy it, since the array is volatile
- avr_cycle_timer_slot_t timer = pool->timer[pool->count-1];
- avr_cycle_count_t when = timer.when;
- if (when > avr->cycle)
- return when - avr->cycle;
- pool->count--; // remove the top element now
+ avr_cycle_timer_slot_p t = pool->timer, last = NULL;
+ while (t) {
+ avr_cycle_timer_slot_p next = t->next;
+ if (t->when > avr->cycle)
+ return t->when - avr->cycle;
+
+ // detach from active timers
+ DETACH(pool->timer, last, t);
+ avr_cycle_count_t when = 0;
do {
- DEBUG(printf("%s %2d when %7d %p/%p\n", __func__, pool->count, (int)(when), timer.timer, timer.param););
- when = timer.timer(avr, when, timer.param);
+ when = t->timer(avr, when, t->param);
} while (when && when <= avr->cycle);
- if (when) {
- DEBUG(printf("%s %2d reschedule when %7d %p/%p\n", __func__, pool->count, (int)(when), timer.timer, timer.param);)
- avr_cycle_timer_insert(avr, when - avr->cycle, timer.timer, timer.param);
+ if (when) { // reschedule then
+ avr_cycle_timer_insert(avr, when - avr->cycle, t->timer, t->param);
}
- } while (pool->count);
+ // requeue this one into the free ones
+ QUEUE(pool->timer_free, t);
+ last = t;
+ t = next;
+ };
return (avr_cycle_count_t)1000;
}
extern "C" {
#endif
-#define MAX_CYCLE_TIMERS 32
+#define MAX_CYCLE_TIMERS 64
typedef avr_cycle_count_t (*avr_cycle_timer_t)(
struct avr_t * avr,
avr_cycle_count_t when,
void * param);
+/*
+ * Each timer instance contains the absolute cycle number they
+ * are hoping to run at, a function pointer to call and a parameter
+ *
+ * it will NEVER be the exact cycle specified, as each instruction is
+ * not divisible and might take 2 or more cycles anyway.
+ *
+ * However if there was a LOT of cycle lag, the timer migth be called
+ * repeteadly until it 'caches up'.
+ */
typedef struct avr_cycle_timer_slot_t {
+ struct avr_cycle_timer_slot_t *next;
avr_cycle_count_t when;
avr_cycle_timer_t timer;
void * param;
-} avr_cycle_timer_slot_t;
+} avr_cycle_timer_slot_t, *avr_cycle_timer_slot_p;
+/*
+ * Timer pool contains a pool of timer slots available, they all
+ * start queued into the 'free' qeueue, are migrated to the
+ * 'active' queue when needed and are re-queued to the free one
+ * when done
+ */
typedef struct avr_cycle_timer_pool_t {
- avr_cycle_timer_slot_t timer[MAX_CYCLE_TIMERS];
- uint8_t count;
+ avr_cycle_timer_slot_t timer_slots[MAX_CYCLE_TIMERS];
+ avr_cycle_timer_slot_p timer_free;
+ avr_cycle_timer_slot_p timer;
} avr_cycle_timer_pool_t, *avr_cycle_timer_pool_p;