1 /* Hardware event manager. 2 Copyright (C) 1998-2024 Free Software Foundation, Inc. 3 Contributed by Cygnus Support. 4 5 This file is part of GDB, the GNU debugger. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 /* This must come before any other includes. */ 21 #include "defs.h" 22 23 #include <stdarg.h> 24 #include <string.h> 25 26 #include "sim/callback.h" 27 28 #include "hw-main.h" 29 #include "hw-base.h" 30 31 #include "sim-events.h" 32 33 /* The hw-events object is implemented using sim-events */ 34 35 struct hw_event 36 { 37 void *data; 38 struct hw *me; 39 hw_event_callback *callback; 40 sim_event *real; 41 struct hw_event_data *entry; 42 }; 43 44 struct hw_event_data 45 { 46 struct hw_event event; 47 struct hw_event_data *next; 48 }; 49 50 void 51 create_hw_event_data (struct hw *me) 52 { 53 if (me->events_of_hw != NULL) 54 hw_abort (me, "stray events"); 55 /* NOP */ 56 } 57 58 void 59 delete_hw_event_data (struct hw *me) 60 { 61 /* Remove the scheduled event. */ 62 while (me->events_of_hw) 63 hw_event_queue_deschedule (me, &me->events_of_hw->event); 64 } 65 66 67 /* Pass the H/W event onto the real callback */ 68 69 static void 70 bounce_hw_event (SIM_DESC sd, 71 void *data) 72 { 73 /* save the data */ 74 struct hw_event_data *entry = (struct hw_event_data *) data; 75 struct hw *me = entry->event.me; 76 void *event_data = entry->event.data; 77 hw_event_callback *callback = entry->event.callback; 78 struct hw_event_data **prev = &me->events_of_hw; 79 while ((*prev) != entry) 80 prev = &(*prev)->next; 81 (*prev) = entry->next; 82 hw_free (me, entry); 83 callback (me, event_data); /* may not return */ 84 } 85 86 87 88 /* Map onto the event functions */ 89 90 struct hw_event * 91 hw_event_queue_schedule (struct hw *me, 92 int64_t delta_time, 93 hw_event_callback *callback, 94 void *data) 95 { 96 return hw_event_queue_schedule_tracef (me, delta_time, callback, data, NULL); 97 } 98 99 struct hw_event * 100 hw_event_queue_schedule_tracef (struct hw *me, 101 int64_t delta_time, 102 hw_event_callback *callback, 103 void *data, 104 const char *fmt, 105 ...) 106 { 107 struct hw_event *event; 108 va_list ap; 109 va_start (ap, fmt); 110 event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap); 111 va_end (ap); 112 return event; 113 } 114 115 struct hw_event * 116 hw_event_queue_schedule_vtracef (struct hw *me, 117 int64_t delta_time, 118 hw_event_callback *callback, 119 void *data, 120 const char *fmt, 121 va_list ap) 122 { 123 struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data); 124 entry->next = me->events_of_hw; 125 me->events_of_hw = entry; 126 /* fill it in */ 127 entry->event.entry = entry; 128 entry->event.data = data; 129 entry->event.callback = callback; 130 entry->event.me = me; 131 entry->event.real = sim_events_schedule_vtracef (hw_system (me), 132 delta_time, 133 bounce_hw_event, 134 entry, 135 fmt, ap); 136 return &entry->event; 137 } 138 139 140 void 141 hw_event_queue_deschedule (struct hw *me, 142 struct hw_event *event_to_remove) 143 { 144 /* ZAP the event but only if it is still in the event queue. Note 145 that event_to_remove is only de-referenced after its validity has 146 been confirmed. */ 147 struct hw_event_data **prev; 148 for (prev = &me->events_of_hw; 149 (*prev) != NULL; 150 prev = &(*prev)->next) 151 { 152 struct hw_event_data *entry = (*prev); 153 if (&entry->event == event_to_remove) 154 { 155 sim_events_deschedule (hw_system (me), 156 entry->event.real); 157 (*prev) = entry->next; 158 hw_free (me, entry); 159 return; 160 } 161 } 162 } 163 164 165 int64_t 166 hw_event_queue_time (struct hw *me) 167 { 168 return sim_events_time (hw_system (me)); 169 } 170 171 /* Returns the time that remains before the event is raised. */ 172 int64_t 173 hw_event_remain_time (struct hw *me, struct hw_event *event) 174 { 175 int64_t t; 176 177 t = sim_events_remain_time (hw_system (me), event->real); 178 return t; 179 } 180 181 /* Only worry about this compling on ANSI systems. 182 Build with `make test-hw-events' in sim/<cpu> directory*/ 183 184 #if defined (MAIN) 185 #include <stdio.h> 186 #include <stdlib.h> 187 #include <string.h> 188 189 #include "sim-main.h" 190 191 static void 192 test_handler (struct hw *me, 193 void *data) 194 { 195 int *n = data; 196 if (*n != hw_event_queue_time (me)) 197 abort (); 198 *n = -(*n); 199 } 200 201 int 202 main (int argc, 203 char **argv) 204 { 205 host_callback *cb = ZALLOC (host_callback); 206 struct sim_state *sd = sim_state_alloc (0, cb); 207 struct hw *me = ZALLOC (struct hw); 208 sim_pre_argv_init (sd, "test-hw-events"); 209 sim_post_argv_init (sd); 210 me->system_of_hw = sd; 211 212 printf ("Create hw-event-data\n"); 213 { 214 create_hw_alloc_data (me); 215 create_hw_event_data (me); 216 delete_hw_event_data (me); 217 delete_hw_alloc_data (me); 218 } 219 220 printf ("Create hw-events\n"); 221 { 222 struct hw_event *a; 223 struct hw_event *b; 224 struct hw_event *c; 225 struct hw_event *d; 226 create_hw_alloc_data (me); 227 create_hw_event_data (me); 228 a = hw_event_queue_schedule (me, 0, NULL, NULL); 229 b = hw_event_queue_schedule (me, 1, NULL, NULL); 230 c = hw_event_queue_schedule (me, 2, NULL, NULL); 231 d = hw_event_queue_schedule (me, 1, NULL, NULL); 232 hw_event_queue_deschedule (me, c); 233 hw_event_queue_deschedule (me, b); 234 hw_event_queue_deschedule (me, a); 235 hw_event_queue_deschedule (me, d); 236 c = HW_ZALLOC (me, struct hw_event); 237 hw_event_queue_deschedule (me, b); /* OOPS! */ 238 hw_free (me, c); 239 delete_hw_event_data (me); 240 delete_hw_alloc_data (me); 241 } 242 243 printf ("Schedule hw-events\n"); 244 { 245 struct hw_event **e; 246 int *n; 247 int i; 248 int nr = 4; 249 e = HW_NZALLOC (me, struct hw_event *, nr); 250 n = HW_NZALLOC (me, int, nr); 251 create_hw_alloc_data (me); 252 create_hw_event_data (me); 253 for (i = 0; i < nr; i++) 254 { 255 n[i] = i; 256 e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]); 257 } 258 sim_events_preprocess (sd, 1, 1); 259 for (i = 0; i < nr; i++) 260 { 261 if (sim_events_tick (sd)) 262 sim_events_process (sd); 263 } 264 for (i = 0; i < nr; i++) 265 { 266 if (n[i] != -i) 267 abort (); 268 hw_event_queue_deschedule (me, e[i]); 269 } 270 hw_free (me, n); 271 hw_free (me, e); 272 delete_hw_event_data (me); 273 delete_hw_alloc_data (me); 274 } 275 276 return 0; 277 } 278 #endif 279