1/* Hardware event manager. 2 Copyright (C) 1998, 2007, 2008, 2009, 2010, 2011 3 Free Software Foundation, Inc. 4 Contributed by Cygnus Support. 5 6This file is part of GDB, the GNU debugger. 7 8This program is free software; you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation; either version 3 of the License, or 11(at your option) any later version. 12 13This program is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21 22#include "hw-main.h" 23#include "hw-base.h" 24 25#include "sim-events.h" 26 27 28/* The hw-events object is implemented using sim-events */ 29 30struct hw_event 31{ 32 void *data; 33 struct hw *me; 34 hw_event_callback *callback; 35 sim_event *real; 36 struct hw_event_data *entry; 37}; 38 39struct hw_event_data 40{ 41 struct hw_event event; 42 struct hw_event_data *next; 43}; 44 45void 46create_hw_event_data (struct hw *me) 47{ 48 if (me->events_of_hw != NULL) 49 hw_abort (me, "stray events"); 50 /* NOP */ 51} 52 53void 54delete_hw_event_data (struct hw *me) 55{ 56 /* Remove the scheduled event. */ 57 while (me->events_of_hw) 58 hw_event_queue_deschedule (me, &me->events_of_hw->event); 59} 60 61 62/* Pass the H/W event onto the real callback */ 63 64static void 65bounce_hw_event (SIM_DESC sd, 66 void *data) 67{ 68 /* save the data */ 69 struct hw_event_data *entry = (struct hw_event_data *) data; 70 struct hw *me = entry->event.me; 71 void *event_data = entry->event.data; 72 hw_event_callback *callback = entry->event.callback; 73 struct hw_event_data **prev = &me->events_of_hw; 74 while ((*prev) != entry) 75 prev = &(*prev)->next; 76 (*prev) = entry->next; 77 hw_free (me, entry); 78 callback (me, event_data); /* may not return */ 79} 80 81 82 83/* Map onto the event functions */ 84 85struct hw_event * 86hw_event_queue_schedule (struct hw *me, 87 signed64 delta_time, 88 hw_event_callback *callback, 89 void *data) 90{ 91 struct hw_event *event; 92 va_list dummy; 93 memset (&dummy, 0, sizeof dummy); 94 event = hw_event_queue_schedule_vtracef (me, delta_time, callback, data, 95 NULL, dummy); 96 return event; 97} 98 99struct hw_event * 100hw_event_queue_schedule_tracef (struct hw *me, 101 signed64 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 115struct hw_event * 116hw_event_queue_schedule_vtracef (struct hw *me, 117 signed64 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 140void 141hw_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 165signed64 166hw_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. */ 172signed64 173hw_event_remain_time (struct hw *me, struct hw_event *event) 174{ 175 signed64 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 "sim-main.h" 186#include <string.h> 187#include <stdio.h> 188 189static void 190test_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 199int 200main (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