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