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