14e98e3e1Schristos /* Hardware event manager. 2*88241920Schristos Copyright (C) 1998-2024 Free Software Foundation, Inc. 34e98e3e1Schristos Contributed by Cygnus Support. 44e98e3e1Schristos 54e98e3e1Schristos This file is part of GDB, the GNU debugger. 64e98e3e1Schristos 74e98e3e1Schristos This program is free software; you can redistribute it and/or modify 84e98e3e1Schristos it under the terms of the GNU General Public License as published by 94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 104e98e3e1Schristos (at your option) any later version. 114e98e3e1Schristos 124e98e3e1Schristos This program is distributed in the hope that it will be useful, 134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154e98e3e1Schristos GNU General Public License for more details. 164e98e3e1Schristos 174e98e3e1Schristos You should have received a copy of the GNU General Public License 184e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 194e98e3e1Schristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224b169a6bSchristos 234b169a6bSchristos #include <stdarg.h> 244b169a6bSchristos #include <string.h> 254e98e3e1Schristos 26*88241920Schristos #include "sim/callback.h" 27*88241920Schristos 284e98e3e1Schristos #include "hw-main.h" 294e98e3e1Schristos #include "hw-base.h" 304e98e3e1Schristos 314e98e3e1Schristos #include "sim-events.h" 324e98e3e1Schristos 334e98e3e1Schristos /* The hw-events object is implemented using sim-events */ 344e98e3e1Schristos 354e98e3e1Schristos struct hw_event 364e98e3e1Schristos { 374e98e3e1Schristos void *data; 384e98e3e1Schristos struct hw *me; 394e98e3e1Schristos hw_event_callback *callback; 404e98e3e1Schristos sim_event *real; 414e98e3e1Schristos struct hw_event_data *entry; 424e98e3e1Schristos }; 434e98e3e1Schristos 444e98e3e1Schristos struct hw_event_data 454e98e3e1Schristos { 464e98e3e1Schristos struct hw_event event; 474e98e3e1Schristos struct hw_event_data *next; 484e98e3e1Schristos }; 494e98e3e1Schristos 504e98e3e1Schristos void 514e98e3e1Schristos create_hw_event_data (struct hw *me) 524e98e3e1Schristos { 534e98e3e1Schristos if (me->events_of_hw != NULL) 544e98e3e1Schristos hw_abort (me, "stray events"); 554e98e3e1Schristos /* NOP */ 564e98e3e1Schristos } 574e98e3e1Schristos 584e98e3e1Schristos void 594e98e3e1Schristos delete_hw_event_data (struct hw *me) 604e98e3e1Schristos { 614e98e3e1Schristos /* Remove the scheduled event. */ 624e98e3e1Schristos while (me->events_of_hw) 634e98e3e1Schristos hw_event_queue_deschedule (me, &me->events_of_hw->event); 644e98e3e1Schristos } 654e98e3e1Schristos 664e98e3e1Schristos 674e98e3e1Schristos /* Pass the H/W event onto the real callback */ 684e98e3e1Schristos 694e98e3e1Schristos static void 704e98e3e1Schristos bounce_hw_event (SIM_DESC sd, 714e98e3e1Schristos void *data) 724e98e3e1Schristos { 734e98e3e1Schristos /* save the data */ 744e98e3e1Schristos struct hw_event_data *entry = (struct hw_event_data *) data; 754e98e3e1Schristos struct hw *me = entry->event.me; 764e98e3e1Schristos void *event_data = entry->event.data; 774e98e3e1Schristos hw_event_callback *callback = entry->event.callback; 784e98e3e1Schristos struct hw_event_data **prev = &me->events_of_hw; 794e98e3e1Schristos while ((*prev) != entry) 804e98e3e1Schristos prev = &(*prev)->next; 814e98e3e1Schristos (*prev) = entry->next; 824e98e3e1Schristos hw_free (me, entry); 834e98e3e1Schristos callback (me, event_data); /* may not return */ 844e98e3e1Schristos } 854e98e3e1Schristos 864e98e3e1Schristos 874e98e3e1Schristos 884e98e3e1Schristos /* Map onto the event functions */ 894e98e3e1Schristos 904e98e3e1Schristos struct hw_event * 914e98e3e1Schristos hw_event_queue_schedule (struct hw *me, 924b169a6bSchristos int64_t delta_time, 934e98e3e1Schristos hw_event_callback *callback, 944e98e3e1Schristos void *data) 954e98e3e1Schristos { 964b169a6bSchristos return hw_event_queue_schedule_tracef (me, delta_time, callback, data, NULL); 974e98e3e1Schristos } 984e98e3e1Schristos 994e98e3e1Schristos struct hw_event * 1004e98e3e1Schristos hw_event_queue_schedule_tracef (struct hw *me, 1014b169a6bSchristos int64_t delta_time, 1024e98e3e1Schristos hw_event_callback *callback, 1034e98e3e1Schristos void *data, 1044e98e3e1Schristos const char *fmt, 1054e98e3e1Schristos ...) 1064e98e3e1Schristos { 1074e98e3e1Schristos struct hw_event *event; 1084e98e3e1Schristos va_list ap; 1094e98e3e1Schristos va_start (ap, fmt); 1104e98e3e1Schristos event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap); 1114e98e3e1Schristos va_end (ap); 1124e98e3e1Schristos return event; 1134e98e3e1Schristos } 1144e98e3e1Schristos 1154e98e3e1Schristos struct hw_event * 1164e98e3e1Schristos hw_event_queue_schedule_vtracef (struct hw *me, 1174b169a6bSchristos int64_t delta_time, 1184e98e3e1Schristos hw_event_callback *callback, 1194e98e3e1Schristos void *data, 1204e98e3e1Schristos const char *fmt, 1214e98e3e1Schristos va_list ap) 1224e98e3e1Schristos { 1234e98e3e1Schristos struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data); 1244e98e3e1Schristos entry->next = me->events_of_hw; 1254e98e3e1Schristos me->events_of_hw = entry; 1264e98e3e1Schristos /* fill it in */ 1274e98e3e1Schristos entry->event.entry = entry; 1284e98e3e1Schristos entry->event.data = data; 1294e98e3e1Schristos entry->event.callback = callback; 1304e98e3e1Schristos entry->event.me = me; 1314e98e3e1Schristos entry->event.real = sim_events_schedule_vtracef (hw_system (me), 1324e98e3e1Schristos delta_time, 1334e98e3e1Schristos bounce_hw_event, 1344e98e3e1Schristos entry, 1354e98e3e1Schristos fmt, ap); 1364e98e3e1Schristos return &entry->event; 1374e98e3e1Schristos } 1384e98e3e1Schristos 1394e98e3e1Schristos 1404e98e3e1Schristos void 1414e98e3e1Schristos hw_event_queue_deschedule (struct hw *me, 1424e98e3e1Schristos struct hw_event *event_to_remove) 1434e98e3e1Schristos { 1444e98e3e1Schristos /* ZAP the event but only if it is still in the event queue. Note 1454e98e3e1Schristos that event_to_remove is only de-referenced after its validity has 1464e98e3e1Schristos been confirmed. */ 1474e98e3e1Schristos struct hw_event_data **prev; 1484e98e3e1Schristos for (prev = &me->events_of_hw; 1494e98e3e1Schristos (*prev) != NULL; 1504e98e3e1Schristos prev = &(*prev)->next) 1514e98e3e1Schristos { 1524e98e3e1Schristos struct hw_event_data *entry = (*prev); 1534e98e3e1Schristos if (&entry->event == event_to_remove) 1544e98e3e1Schristos { 1554e98e3e1Schristos sim_events_deschedule (hw_system (me), 1564e98e3e1Schristos entry->event.real); 1574e98e3e1Schristos (*prev) = entry->next; 1584e98e3e1Schristos hw_free (me, entry); 1594e98e3e1Schristos return; 1604e98e3e1Schristos } 1614e98e3e1Schristos } 1624e98e3e1Schristos } 1634e98e3e1Schristos 1644e98e3e1Schristos 1654b169a6bSchristos int64_t 1664e98e3e1Schristos hw_event_queue_time (struct hw *me) 1674e98e3e1Schristos { 1684e98e3e1Schristos return sim_events_time (hw_system (me)); 1694e98e3e1Schristos } 1704e98e3e1Schristos 1714e98e3e1Schristos /* Returns the time that remains before the event is raised. */ 1724b169a6bSchristos int64_t 1734e98e3e1Schristos hw_event_remain_time (struct hw *me, struct hw_event *event) 1744e98e3e1Schristos { 1754b169a6bSchristos int64_t t; 1764e98e3e1Schristos 1774e98e3e1Schristos t = sim_events_remain_time (hw_system (me), event->real); 1784e98e3e1Schristos return t; 1794e98e3e1Schristos } 1804e98e3e1Schristos 1814e98e3e1Schristos /* Only worry about this compling on ANSI systems. 1824e98e3e1Schristos Build with `make test-hw-events' in sim/<cpu> directory*/ 1834e98e3e1Schristos 1844e98e3e1Schristos #if defined (MAIN) 1854e98e3e1Schristos #include <stdio.h> 1864b169a6bSchristos #include <stdlib.h> 1874b169a6bSchristos #include <string.h> 1884b169a6bSchristos 1894b169a6bSchristos #include "sim-main.h" 1904e98e3e1Schristos 1914e98e3e1Schristos static void 1924e98e3e1Schristos test_handler (struct hw *me, 1934e98e3e1Schristos void *data) 1944e98e3e1Schristos { 1954e98e3e1Schristos int *n = data; 1964e98e3e1Schristos if (*n != hw_event_queue_time (me)) 1974e98e3e1Schristos abort (); 1984e98e3e1Schristos *n = -(*n); 1994e98e3e1Schristos } 2004e98e3e1Schristos 2014e98e3e1Schristos int 2024e98e3e1Schristos main (int argc, 2034e98e3e1Schristos char **argv) 2044e98e3e1Schristos { 2054e98e3e1Schristos host_callback *cb = ZALLOC (host_callback); 2064e98e3e1Schristos struct sim_state *sd = sim_state_alloc (0, cb); 2074e98e3e1Schristos struct hw *me = ZALLOC (struct hw); 2084e98e3e1Schristos sim_pre_argv_init (sd, "test-hw-events"); 2094e98e3e1Schristos sim_post_argv_init (sd); 2104e98e3e1Schristos me->system_of_hw = sd; 2114e98e3e1Schristos 2124e98e3e1Schristos printf ("Create hw-event-data\n"); 2134e98e3e1Schristos { 2144e98e3e1Schristos create_hw_alloc_data (me); 2154e98e3e1Schristos create_hw_event_data (me); 2164e98e3e1Schristos delete_hw_event_data (me); 2174e98e3e1Schristos delete_hw_alloc_data (me); 2184e98e3e1Schristos } 2194e98e3e1Schristos 2204e98e3e1Schristos printf ("Create hw-events\n"); 2214e98e3e1Schristos { 2224e98e3e1Schristos struct hw_event *a; 2234e98e3e1Schristos struct hw_event *b; 2244e98e3e1Schristos struct hw_event *c; 2254e98e3e1Schristos struct hw_event *d; 2264e98e3e1Schristos create_hw_alloc_data (me); 2274e98e3e1Schristos create_hw_event_data (me); 2284e98e3e1Schristos a = hw_event_queue_schedule (me, 0, NULL, NULL); 2294e98e3e1Schristos b = hw_event_queue_schedule (me, 1, NULL, NULL); 2304e98e3e1Schristos c = hw_event_queue_schedule (me, 2, NULL, NULL); 2314e98e3e1Schristos d = hw_event_queue_schedule (me, 1, NULL, NULL); 2324e98e3e1Schristos hw_event_queue_deschedule (me, c); 2334e98e3e1Schristos hw_event_queue_deschedule (me, b); 2344e98e3e1Schristos hw_event_queue_deschedule (me, a); 2354e98e3e1Schristos hw_event_queue_deschedule (me, d); 2364e98e3e1Schristos c = HW_ZALLOC (me, struct hw_event); 2374e98e3e1Schristos hw_event_queue_deschedule (me, b); /* OOPS! */ 2384e98e3e1Schristos hw_free (me, c); 2394e98e3e1Schristos delete_hw_event_data (me); 2404e98e3e1Schristos delete_hw_alloc_data (me); 2414e98e3e1Schristos } 2424e98e3e1Schristos 2434e98e3e1Schristos printf ("Schedule hw-events\n"); 2444e98e3e1Schristos { 2454e98e3e1Schristos struct hw_event **e; 2464e98e3e1Schristos int *n; 2474e98e3e1Schristos int i; 2484e98e3e1Schristos int nr = 4; 2494e98e3e1Schristos e = HW_NZALLOC (me, struct hw_event *, nr); 2504e98e3e1Schristos n = HW_NZALLOC (me, int, nr); 2514e98e3e1Schristos create_hw_alloc_data (me); 2524e98e3e1Schristos create_hw_event_data (me); 2534e98e3e1Schristos for (i = 0; i < nr; i++) 2544e98e3e1Schristos { 2554e98e3e1Schristos n[i] = i; 2564e98e3e1Schristos e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]); 2574e98e3e1Schristos } 2584e98e3e1Schristos sim_events_preprocess (sd, 1, 1); 2594e98e3e1Schristos for (i = 0; i < nr; i++) 2604e98e3e1Schristos { 2614e98e3e1Schristos if (sim_events_tick (sd)) 2624e98e3e1Schristos sim_events_process (sd); 2634e98e3e1Schristos } 2644e98e3e1Schristos for (i = 0; i < nr; i++) 2654e98e3e1Schristos { 2664e98e3e1Schristos if (n[i] != -i) 2674e98e3e1Schristos abort (); 2684e98e3e1Schristos hw_event_queue_deschedule (me, e[i]); 2694e98e3e1Schristos } 2704e98e3e1Schristos hw_free (me, n); 2714e98e3e1Schristos hw_free (me, e); 2724e98e3e1Schristos delete_hw_event_data (me); 2734e98e3e1Schristos delete_hw_alloc_data (me); 2744e98e3e1Schristos } 2754e98e3e1Schristos 2764e98e3e1Schristos return 0; 2774e98e3e1Schristos } 2784e98e3e1Schristos #endif 279