summaryrefslogtreecommitdiff
path: root/cmt/timebase.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmt/timebase.c')
-rw-r--r--cmt/timebase.c322
1 files changed, 322 insertions, 0 deletions
diff --git a/cmt/timebase.c b/cmt/timebase.c
new file mode 100644
index 0000000..0bb1713
--- /dev/null
+++ b/cmt/timebase.c
@@ -0,0 +1,322 @@
+/* timebase.c -- management of calls, time bases and heaps for moxc */
+
+/*****************************************************************************
+* Change Log
+* Date | Change
+*-----------+-----------------------------------------------------------------
+* 2-Apr-91 | JDW : further changes
+* 21-Mar-92 | GWL : abort recovery
+* 28-Apr-03 | DM : true->TRUE
+*****************************************************************************/
+
+
+#include "stdio.h"
+#include "cext.h"
+#include "userio.h"
+#include "midifns.h"
+#include "timebase.h"
+#include "moxc.h"
+
+
+timebase_type timebase_queue = NULL; /* waiting to run timebase queue */
+call_type callfree = NULL; /* free list */
+
+private void fatal();
+
+
+/****************************************************************************
+* timebase_create
+* Inputs:
+* maxsize is the initial size of the heap
+* Outputs:
+* returns an initialized timebase_type
+****************************************************************************/
+
+timebase_type timebase_create(maxsize)
+ int maxsize;
+{
+ static char *error_msg = "Out of memory in timebase_create()";
+ timebase_type base = (timebase_type) memget(sizeof(timebase_node));
+ if (!base) fatal(error_msg);
+ base->next = NULL;
+ base->next_time = MAXTIME;
+ base->virt_base = 0L;
+ base->real_base = 0L;
+ base->rate = 256L;
+ base->heap_size = 0;
+ base->heap_max = maxsize;
+ base->heap = (call_type *) memget(sizeof(call_type) * maxsize);
+ if (!base->heap) fatal(error_msg);
+ return base;
+}
+
+/****************************************************************************
+* callinsert
+* Inputs:
+* timebase_type base: the time base and heap
+* call_type call: the call to insert in heap
+* Outputs:
+ none
+* Implementation:
+* linear insertion; to be changed to heap
+****************************************************************************/
+
+void callinsert(base, call)
+ timebase_type base;
+ call_type call;
+{
+ int i;
+ register call_type *heap = base->heap;
+
+ /* handle overflow -- this should never be executed if the user
+ * gives the right initial heap size
+ */
+ base->heap_size++;
+ if (base->heap_size >= base->heap_max) {
+ call_type *new_heap = (call_type *)
+ memget((base->heap_max << 1) * sizeof(call_type));
+ int i;
+ call_type *oldptr;
+ call_type *newptr;
+ if (!new_heap) {
+ gprintf(TRANS, "Out of space, can't allocate new heap\n");
+ EXIT(1);
+ }
+
+ oldptr = base->heap;
+ newptr = new_heap;
+
+ for (i = base->heap_max; i > 0; i--) *newptr++ = *oldptr++;
+ memfree((char *) heap, base->heap_max * sizeof(call_type));
+ base->heap = heap = new_heap;
+ base->heap_max = (base->heap_max << 1);
+ }
+
+ /* now do the heap insert */
+ i = base->heap_size;
+ while (i > 1) {
+ int parent = i >> 1;
+ if (heap[parent]->u.e.time < call->u.e.time ||
+ (heap[parent]->u.e.time == call->u.e.time &&
+ heap[parent]->u.e.priority <= call->u.e.priority)) break;
+ heap[i] = heap[parent];
+ i = parent;
+ }
+ heap[i] = call;
+
+ /* if next_time might change, reinsert base into queue */
+ if (heap[1] == call) {
+ remove_base(base);
+ insert_base(base);
+ }
+}
+
+/****************************************************************************
+* callshow
+* Inputs:
+* calltype call: the call to show
+* Effect:
+* prints a description of call
+* Assumes:
+* call is not null
+****************************************************************************/
+void callshow(call)
+ call_type call;
+{
+ int i;
+ gprintf(TRANS,"address: %lx\n", (ulong)call);
+ gprintf(TRANS,"time: %ld\n", call->u.e.time);
+ gprintf(TRANS,"routine: %lx\n", (ulong)call->u.e.routine);
+ gprintf(TRANS,"parameters:");
+ for (i = 0; i < MAX_CALL_ARGS; i++) {
+ gprintf(TRANS, " %d", call->u.e.p.arg[i]);
+ }
+ gprintf(TRANS, "\n");
+}
+
+/***************************************************************
+* fatal
+*
+* Input : msg: a message to be displayed
+* Effect: print message and exit program
+***************************************************************/
+
+private void fatal(msg)
+ char *msg;
+{
+ gprintf(FATAL, msg);
+ EXIT(1);
+}
+
+/***************************************************************
+* timebase_free
+*
+* Input : a time base
+* Effect: deallocate the time base
+***************************************************************/
+
+void timebase_free(timebase)
+ timebase_type timebase;
+{
+ remove_base(timebase);
+ if (timebase->heap) {
+ memfree((char *) timebase->heap,
+ (timebase->heap_max * sizeof(call_type)));
+ }
+ memfree((char *) timebase, sizeof(timebase_node));
+}
+
+/***************************************************************
+* insert_base
+*
+* Input : a time base not in the list
+* Effect: insert timebase at the appropriate spot in the list
+* computes the next_time field from the top of the heap
+***************************************************************/
+
+void insert_base(timebase)
+ timebase_type timebase;
+{
+ register timebase_type *ptr = &timebase_queue;
+ register time_type next_time = MAXTIME;
+ /* compute next_time */
+ if (timebase->heap_size != 0) {
+ register call_type call = timebase->heap[1];
+ /* virt to real calculation */
+ next_time = (virt_to_real_256(timebase, call->u.e.time) &
+ 0xFFFFFF00) + call->u.e.priority;
+/* gprintf(TRANS,
+ "insert next_time is %ld, vt %ld, rb %ld, vb %ld rt %ld\n",
+ next_time, timebase->heap[1]->u.e.time,
+ timebase->real_base, timebase->virt_base, timebase->rate);
+ */
+ }
+ timebase->next_time = next_time;
+
+ if (next_time != MAXTIME) {
+ /* insert into the list */
+ while (TRUE) {
+ if (! *ptr) {
+ *ptr = timebase;
+ timebase->next = NULL;
+ return;
+ } else if ((*ptr)->next_time >= next_time) {
+ timebase->next = *ptr;
+ *ptr = timebase;
+ return;
+ } else ptr = &((*ptr)->next);
+ }
+ }
+}
+
+/***************************************************************
+* remove_base
+*
+* Input : timebase
+* Effect: if timebase is in the queue, remove it
+***************************************************************/
+
+void remove_base(timebase)
+ timebase_type timebase;
+{
+ timebase_type *ptr = &timebase_queue;
+ while (*ptr) {
+ if (*ptr == timebase) {
+ *ptr = timebase->next;
+ return;
+ } else ptr = &((*ptr)->next);
+ }
+}
+
+/***************************************************************
+* remove_call
+*
+* Input : a timebase -- passed as a global
+* Assumes: a_timebase->heap_size > 0
+* Returns: the earliest call in the queue
+* Effect: removes the earliest call in the queue
+***************************************************************/
+
+call_type remove_call(timebase_type a_timebase)
+{
+ register call_type *heap = a_timebase->heap;
+ call_type result = heap[1];
+ register call_type large;
+ int i = 1;
+ int child = i << 1;;
+ large = heap[a_timebase->heap_size--];
+ while (child <= a_timebase->heap_size) {
+ if (child + 1 <= a_timebase->heap_size) {
+ if (heap[child + 1]->u.e.time < heap[child]->u.e.time ||
+ (heap[child + 1]->u.e.time == heap[child]->u.e.time &&
+ heap[child + 1]->u.e.priority < heap[child]->u.e.priority))
+ child++;
+ }
+ /* child is now the index of the least child */
+ if (large->u.e.time < heap[child]->u.e.time ||
+ (large->u.e.time == heap[child]->u.e.time &&
+ large->u.e.priority <= heap[child]->u.e.priority)) break;
+ /* swap */
+ heap[i] = heap[child];
+ i = child;
+ child = i << 1;
+ }
+ heap[i] = large;
+ return result;
+}
+
+/***************************************************************
+* set_rate
+*
+* Input : timebase and new rate
+* Effect: makes the current rate of timebase be rate
+***************************************************************/
+
+void set_rate(base, rate)
+ timebase_type base;
+ time_type rate;
+{
+ if (base == timebase) base->virt_base = virttime;
+ else base->virt_base = real_to_virt(base, eventtime);
+ base->real_base = eventtime;
+ base->rate = rate;
+/* gprintf(TRANS, "new real_base %ld virt_base %ld\n",
+ base->real_base, base->virt_base);
+ */
+ remove_base(base);
+ insert_base(base);
+}
+
+/***************************************************************
+* set_virttime
+*
+* Input : virtual time
+* Effect: makes the current virtual time of timebase be vtime
+***************************************************************/
+
+void set_virttime(base, vtime)
+ timebase_type base;
+ time_type vtime;
+{
+ base->real_base = eventtime;
+ base->virt_base = vtime;
+ if (base == timebase) virttime = vtime;
+ remove_base(base);
+ insert_base(base);
+}
+
+/***************************************************************
+* timebase_use
+*
+* Input : a timebase to use for scheduling
+* Effect: sets up globals: timebase, virttime
+***************************************************************/
+
+void timebase_use(base)
+ register timebase_type base;
+{
+ if (timebase != base) {
+ timebase = base;
+ virttime = real_to_virt(base, eventtime);
+ }
+}