1 /* Hardware event manager. 2 Copyright (C) 1998-2020 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 21 #include "hw-main.h" 22 #include "hw-base.h" 23 24 #include "sim-events.h" 25 26 #if HAVE_STRING_H 27 #include <string.h> 28 #endif 29 30 /* The hw-events object is implemented using sim-events */ 31 32 struct hw_event 33 { 34 void *data; 35 struct hw *me; 36 hw_event_callback *callback; 37 sim_event *real; 38 struct hw_event_data *entry; 39 }; 40 41 struct hw_event_data 42 { 43 struct hw_event event; 44 struct hw_event_data *next; 45 }; 46 47 void 48 create_hw_event_data (struct hw *me) 49 { 50 if (me->events_of_hw != NULL) 51 hw_abort (me, "stray events"); 52 /* NOP */ 53 } 54 55 void 56 delete_hw_event_data (struct hw *me) 57 { 58 /* Remove the scheduled event. */ 59 while (me->events_of_hw) 60 hw_event_queue_deschedule (me, &me->events_of_hw->event); 61 } 62 63 64 /* Pass the H/W event onto the real callback */ 65 66 static void 67 bounce_hw_event (SIM_DESC sd, 68 void *data) 69 { 70 /* save the data */ 71 struct hw_event_data *entry = (struct hw_event_data *) data; 72 struct hw *me = entry->event.me; 73 void *event_data = entry->event.data; 74 hw_event_callback *callback = entry->event.callback; 75 struct hw_event_data **prev = &me->events_of_hw; 76 while ((*prev) != entry) 77 prev = &(*prev)->next; 78 (*prev) = entry->next; 79 hw_free (me, entry); 80 callback (me, event_data); /* may not return */ 81 } 82 83 84 85 /* Map onto the event functions */ 86 87 struct hw_event * 88 hw_event_queue_schedule (struct hw *me, 89 signed64 delta_time, 90 hw_event_callback *callback, 91 void *data) 92 { 93 struct hw_event *event; 94 va_list dummy; 95 memset (&dummy, 0, sizeof dummy); 96 event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, 97 NULL, dummy); 98 return event; 99 } 100 101 struct hw_event * 102 hw_event_queue_schedule_tracef (struct hw *me, 103 signed64 delta_time, 104 hw_event_callback *callback, 105 void *data, 106 const char *fmt, 107 ...) 108 { 109 struct hw_event *event; 110 va_list ap; 111 va_start (ap, fmt); 112 event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, fmt, ap); 113 va_end (ap); 114 return event; 115 } 116 117 struct hw_event * 118 hw_event_queue_schedule_vtracef (struct hw *me, 119 signed64 delta_time, 120 hw_event_callback *callback, 121 void *data, 122 const char *fmt, 123 va_list ap) 124 { 125 struct hw_event_data *entry = HW_ZALLOC (me, struct hw_event_data); 126 entry->next = me->events_of_hw; 127 me->events_of_hw = entry; 128 /* fill it in */ 129 entry->event.entry = entry; 130 entry->event.data = data; 131 entry->event.callback = callback; 132 entry->event.me = me; 133 entry->event.real = sim_events_schedule_vtracef (hw_system (me), 134 delta_time, 135 bounce_hw_event, 136 entry, 137 fmt, ap); 138 return &entry->event; 139 } 140 141 142 void 143 hw_event_queue_deschedule (struct hw *me, 144 struct hw_event *event_to_remove) 145 { 146 /* ZAP the event but only if it is still in the event queue. Note 147 that event_to_remove is only de-referenced after its validity has 148 been confirmed. */ 149 struct hw_event_data **prev; 150 for (prev = &me->events_of_hw; 151 (*prev) != NULL; 152 prev = &(*prev)->next) 153 { 154 struct hw_event_data *entry = (*prev); 155 if (&entry->event == event_to_remove) 156 { 157 sim_events_deschedule (hw_system (me), 158 entry->event.real); 159 (*prev) = entry->next; 160 hw_free (me, entry); 161 return; 162 } 163 } 164 } 165 166 167 signed64 168 hw_event_queue_time (struct hw *me) 169 { 170 return sim_events_time (hw_system (me)); 171 } 172 173 /* Returns the time that remains before the event is raised. */ 174 signed64 175 hw_event_remain_time (struct hw *me, struct hw_event *event) 176 { 177 signed64 t; 178 179 t = sim_events_remain_time (hw_system (me), event->real); 180 return t; 181 } 182 183 /* Only worry about this compling on ANSI systems. 184 Build with `make test-hw-events' in sim/<cpu> directory*/ 185 186 #if defined (MAIN) 187 #include "sim-main.h" 188 #include <string.h> 189 #include <stdio.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