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