diff options
Diffstat (limited to 'sim/common/hw-events.c')
-rw-r--r-- | sim/common/hw-events.c | 263 |
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 0000000..31c5a40 --- /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 |