summaryrefslogtreecommitdiff
path: root/sim/common/hw-events.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/common/hw-events.c')
-rw-r--r--sim/common/hw-events.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/sim/common/hw-events.c b/sim/common/hw-events.c
new file mode 100644
index 00000000000..31c5a4026ab
--- /dev/null
+++ b/sim/common/hw-events.c
@@ -0,0 +1,263 @@
+/* Hardware event manager.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Support.
+
+This file is part of GDB, the GNU debugger.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+
+#include "hw-main.h"
+#include "hw-base.h"
+
+#include "sim-events.h"
+
+
+/* The hw-events object is implemented using sim-events */
+
+struct hw_event {
+ void *data;
+ struct hw *me;
+ hw_event_callback *callback;
+ sim_event *real;
+ struct hw_event_data *entry;
+};
+
+struct hw_event_data {
+ struct hw_event event;
+ struct hw_event_data *next;
+};
+
+void
+create_hw_event_data (struct hw *me)
+{
+ if (me->events_of_hw != NULL)
+ hw_abort (me, "stray events");
+ /* NOP */
+}
+
+void
+delete_hw_event_data (struct hw *me)
+{
+ if (me->events_of_hw != NULL)
+ hw_abort (me, "stray events");
+}
+
+
+/* Pass the H/W event onto the real callback */
+
+static void
+bounce_hw_event (SIM_DESC sd,
+ void *data)
+{
+ /* save the data */
+ struct hw_event_data *entry = (struct hw_event_data *) data;
+ struct hw *me = entry->event.me;
+ void *event_data = entry->event.data;
+ hw_event_callback *callback = entry->event.callback;
+ struct hw_event_data **prev = &me->events_of_hw;
+ while ((*prev) != entry)
+ prev = &(*prev)->next;
+ (*prev) = entry->next;
+ hw_free (me, entry);
+ callback (me, event_data); /* may not return */
+}
+
+
+
+/* Map onto the event functions */
+
+struct hw_event *
+hw_event_queue_schedule (struct hw *me,
+ signed64 delta_time,
+ hw_event_callback *callback,
+ void *data)
+{
+ struct hw_event *event;
+ va_list dummy;
+ event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data,
+ NULL, dummy);
+ return event;
+}
+
+struct hw_event *
+hw_event_queue_schedule_tracef (struct hw *me,
+ signed64 delta_time,
+ hw_event_callback *callback,
+ void *data,
+ const char *fmt,
+ ...)
+{
+ struct hw_event *event;
+ va_list ap;
+ va_start (ap, fmt);
+ event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap);
+ va_end (ap);
+ return event;
+}
+
+struct hw_event *
+hw_event_queue_schedule_vtracef (struct hw *me,
+ signed64 delta_time,
+ hw_event_callback *callback,
+ void *data,
+ const char *fmt,
+ va_list ap)
+{
+ struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data);
+ entry->next = me->events_of_hw;
+ me->events_of_hw = entry;
+ /* fill it in */
+ entry->event.entry = entry;
+ entry->event.data = data;
+ entry->event.callback = callback;
+ entry->event.me = me;
+ entry->event.real = sim_events_schedule_vtracef (hw_system (me),
+ delta_time,
+ bounce_hw_event,
+ entry,
+ fmt, ap);
+ return &entry->event;
+}
+
+
+void
+hw_event_queue_deschedule (struct hw *me,
+ struct hw_event *event_to_remove)
+{
+/* ZAP the event but only if it is still in the event queue. Note
+ that event_to_remove is only de-referenced after its validity has
+ been confirmed. */
+ struct hw_event_data **prev;
+ for (prev = &me->events_of_hw;
+ (*prev) != NULL;
+ prev = &(*prev)->next)
+ {
+ struct hw_event_data *entry = (*prev);
+ if (&entry->event == event_to_remove)
+ {
+ sim_events_deschedule (hw_system (me),
+ entry->event.real);
+ (*prev) = entry->next;
+ hw_free (me, entry);
+ return;
+ }
+ }
+}
+
+
+signed64
+hw_event_queue_time (struct hw *me)
+{
+ return sim_events_time (hw_system (me));
+}
+
+
+/* Only worry about this compling on ANSI systems.
+ Build with `make test-hw-events' in sim/<cpu> directory*/
+
+#if defined (MAIN)
+#include "sim-main.h"
+#include <string.h>
+#include <stdio.h>
+
+static void
+test_handler (struct hw *me,
+ void *data)
+{
+ int *n = data;
+ if (*n != hw_event_queue_time (me))
+ abort ();
+ *n = -(*n);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ host_callback *cb = ZALLOC (host_callback);
+ struct sim_state *sd = sim_state_alloc (0, cb);
+ struct hw *me = ZALLOC (struct hw);
+ sim_pre_argv_init (sd, "test-hw-events");
+ sim_post_argv_init (sd);
+ me->system_of_hw = sd;
+
+ printf ("Create hw-event-data\n");
+ {
+ create_hw_alloc_data (me);
+ create_hw_event_data (me);
+ delete_hw_event_data (me);
+ delete_hw_alloc_data (me);
+ }
+
+ printf ("Create hw-events\n");
+ {
+ struct hw_event *a;
+ struct hw_event *b;
+ struct hw_event *c;
+ struct hw_event *d;
+ create_hw_alloc_data (me);
+ create_hw_event_data (me);
+ a = hw_event_queue_schedule (me, 0, NULL, NULL);
+ b = hw_event_queue_schedule (me, 1, NULL, NULL);
+ c = hw_event_queue_schedule (me, 2, NULL, NULL);
+ d = hw_event_queue_schedule (me, 1, NULL, NULL);
+ hw_event_queue_deschedule (me, c);
+ hw_event_queue_deschedule (me, b);
+ hw_event_queue_deschedule (me, a);
+ hw_event_queue_deschedule (me, d);
+ c = HW_ZALLOC (me, struct hw_event);
+ hw_event_queue_deschedule (me, b); /* OOPS! */
+ hw_free (me, c);
+ delete_hw_event_data (me);
+ delete_hw_alloc_data (me);
+ }
+
+ printf ("Schedule hw-events\n");
+ {
+ struct hw_event **e;
+ int *n;
+ int i;
+ int nr = 4;
+ e = HW_NZALLOC (me, struct hw_event *, nr);
+ n = HW_NZALLOC (me, int, nr);
+ create_hw_alloc_data (me);
+ create_hw_event_data (me);
+ for (i = 0; i < nr; i++)
+ {
+ n[i] = i;
+ e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]);
+ }
+ sim_events_preprocess (sd, 1, 1);
+ for (i = 0; i < nr; i++)
+ {
+ if (sim_events_tick (sd))
+ sim_events_process (sd);
+ }
+ for (i = 0; i < nr; i++)
+ {
+ if (n[i] != -i)
+ abort ();
+ hw_event_queue_deschedule (me, e[i]);
+ }
+ hw_free (me, n);
+ hw_free (me, e);
+ delete_hw_event_data (me);
+ delete_hw_alloc_data (me);
+ }
+
+ return 0;
+}
+#endif