1 /* This file is part of the program psim.
3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #ifndef _SIM_EVENTS_C_
23 #define _SIM_EVENTS_C_
26 #include "sim-assert.h"
31 /* The event queue maintains a single absolute time using two
34 TIME_OF_EVENT: this holds the time at which the next event is ment
35 to occure. If no next event it will hold the time of the last
38 TIME_FROM_EVENT: The current distance from TIME_OF_EVENT. If an
39 event is pending, this will be positive. If no future event is
40 pending this will be negative. This variable is decremented once
41 for each iteration of a clock cycle.
43 Initially, the clock is started at time one (0) with TIME_OF_EVENT
44 == 0 and TIME_FROM_EVENT == 0.
46 Clearly there is a bug in that this code assumes that the absolute
47 time counter will never become greater than 2^62.
49 To avoid the need to use 64bit arithmetic, the event queue always
50 contains at least one event scheduled every 16 000 ticks. This
51 limits the time from event counter to values less than
55 #if !defined (SIM_EVENTS_POLL_RATE)
56 #define SIM_EVENTS_POLL_RATE 0x4000
63 #define ETRACE(ARGS) \
68 if (sd->events.trace) \
71 SIM_FILTER_PATH(file, __FILE__); \
72 sim_io_printf (sd, "%s:%d: ", file, __LINE__); \
80 STATIC_INLINE_SIM_EVENTS\
82 sim_events_poll (void *data
)
84 /* just re-schedule in 1000 million ticks time */
86 sim_events_schedule(sd
, SIM_EVENTS_POLL_RATE
, sim_events_poll
, sd
);
87 sim_io_poll_quit (sd
);
93 sim_events_init(SIM_DESC sd
)
95 sim_events
*events
= &sd
->events
;
98 /* drain the interrupt queue */
100 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
103 sigfillset(&new_mask
);
104 /*-LOCK-*/ sigprocmask(SIG_SETMASK
, &new_mask
, &old_mask
);
106 event
= events
->held
;
107 while (event
!= NULL
) {
108 sim_event
*dead
= event
;
113 events
->held_end
= &events
->held
;
114 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
115 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
119 /* drain the normal queue */
120 event
= events
->queue
;
121 while (event
!= NULL
) {
122 sim_event
*dead
= event
;
126 events
->queue
= NULL
;
128 /* wind time back to zero */
129 events
->processing
= 0;
130 events
->time_of_event
= 0;
131 events
->time_from_event
= 0;
133 /* schedule our initial counter event */
134 sim_events_schedule(sd
, 0, sim_events_poll
, sd
);
136 /* from now on, except when the large-int event is being processed
137 the event queue is non empty */
138 SIM_ASSERT(events
->queue
!= NULL
);
143 sim_events_time(SIM_DESC sd
)
145 sim_events
*events
= &sd
->events
;
146 return events
->time_of_event
- events
->time_from_event
;
149 STATIC_INLINE_SIM_EVENTS\
151 update_time_from_event(SIM_DESC sd
)
153 sim_events
*events
= &sd
->events
;
154 signed64 current_time
= sim_events_time(sd
);
155 if (events
->queue
!= NULL
) {
156 events
->time_from_event
= (events
->queue
->time_of_event
- current_time
);
157 events
->time_of_event
= events
->queue
->time_of_event
;
160 events
->time_of_event
= current_time
- 1;
161 events
->time_from_event
= -1;
163 SIM_ASSERT(current_time
== sim_events_time (sd
));
164 SIM_ASSERT((events
->time_from_event
>= 0) == (events
->queue
!= NULL
));
167 STATIC_INLINE_SIM_EVENTS\
169 insert_sim_event(SIM_DESC sd
,
170 sim_event
*new_event
,
173 sim_events
*events
= &sd
->events
;
176 signed64 time_of_event
;
179 engine_error (sd
, "what is past is past!\n");
181 /* compute when the event should occure */
182 time_of_event
= sim_events_time(sd
) + delta
;
184 /* find the queue insertion point - things are time ordered */
185 prev
= &events
->queue
;
186 curr
= events
->queue
;
187 while (curr
!= NULL
&& time_of_event
>= curr
->time_of_event
) {
188 SIM_ASSERT(curr
->next
== NULL
189 || curr
->time_of_event
<= curr
->next
->time_of_event
);
193 SIM_ASSERT(curr
== NULL
|| time_of_event
< curr
->time_of_event
);
196 new_event
->next
= curr
;
198 new_event
->time_of_event
= time_of_event
;
200 /* adjust the time until the first event */
201 update_time_from_event(sd
);
206 sim_events_schedule(SIM_DESC sd
,
208 sim_event_handler
*handler
,
211 sim_event
*new_event
= ZALLOC(sim_event
);
212 new_event
->data
= data
;
213 new_event
->handler
= handler
;
214 insert_sim_event(sd
, new_event
, delta_time
);
216 "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
217 (long)sim_events_time(sd
),
219 (long)new_event
->time_of_event
,
220 (long)new_event
->handler
,
221 (long)new_event
->data
));
228 sim_events_schedule_after_signal(SIM_DESC sd
,
230 sim_event_handler
*handler
,
233 sim_events
*events
= &sd
->events
;
234 sim_event
*new_event
= ZALLOC(sim_event
);
236 new_event
->data
= data
;
237 new_event
->handler
= handler
;
238 new_event
->time_of_event
= delta_time
; /* work it out later */
239 new_event
->next
= NULL
;
242 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
245 sigfillset(&new_mask
);
246 /*-LOCK-*/ sigprocmask(SIG_SETMASK
, &new_mask
, &old_mask
);
248 if (events
->held
== NULL
) {
249 events
->held
= new_event
;
252 *events
->held_end
= new_event
;
254 events
->held_end
= &new_event
->next
;
255 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
256 /*-UNLOCK-*/ sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
261 "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
262 (long)sim_events_time(sd
),
264 (long)new_event
->time_of_event
,
265 (long)new_event
->handler
,
266 (long)new_event
->data
));
274 sim_events_deschedule(SIM_DESC sd
,
275 sim_event
*event_to_remove
)
277 sim_events
*events
= &sd
->events
;
278 sim_event
*to_remove
= (sim_event
*)event_to_remove
;
279 SIM_ASSERT((events
->time_from_event
>= 0) == (events
->queue
!= NULL
));
280 if (event_to_remove
!= NULL
) {
282 sim_event
**ptr_to_current
;
283 for (ptr_to_current
= &events
->queue
, current
= *ptr_to_current
;
284 current
!= NULL
&& current
!= to_remove
;
285 ptr_to_current
= ¤t
->next
, current
= *ptr_to_current
);
286 if (current
== to_remove
) {
287 *ptr_to_current
= current
->next
;
289 "event descheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
290 (long)sim_events_time(sd
),
291 (long)event_to_remove
,
292 (long)current
->time_of_event
,
293 (long)current
->handler
,
294 (long)current
->data
));
296 update_time_from_event(sd
);
300 "event descheduled at %ld - tag 0x%lx - not found\n",
301 (long)sim_events_time(sd
),
302 (long)event_to_remove
));
305 SIM_ASSERT((events
->time_from_event
>= 0) == (events
->queue
!= NULL
));
313 sim_events_tick(SIM_DESC sd
)
315 sim_events
*events
= &sd
->events
;
317 /* we should only be here when the previous tick has been fully
319 SIM_ASSERT(!events
->processing
&& events
->queue
!= NULL
);
321 /* Advance the time but *only* if there is nothing to process */
322 if (events
->time_from_event
== 0)
324 else if (events
->held
!= NULL
)
327 events
->time_from_event
-= 1;
336 sim_events_process(SIM_DESC sd
)
338 sim_events
*events
= &sd
->events
;
339 signed64 event_time
= sim_events_time(sd
);
341 /* something to do */
342 SIM_ASSERT(events
->time_from_event
== 0 || events
->held
!= NULL
);
343 SIM_ASSERT(events
->queue
!= NULL
);
345 /* move any events that were queued by any signal handlers onto the
347 if (events
->held
!= NULL
) {
348 sim_event
*held_events
;
349 sim_event
*curr_event
;
351 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
355 sigfillset(&new_mask
);
356 sigprocmask(SIG_SETMASK
, &new_mask
, &old_mask
);
359 held_events
= events
->held
;
361 events
->held_end
= &events
->held
;
363 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
365 sigprocmask(SIG_SETMASK
, &old_mask
, NULL
);
369 curr_event
= held_events
;
370 held_events
= curr_event
->next
;
371 insert_sim_event(sd
, curr_event
, curr_event
->time_of_event
);
372 } while (held_events
!= NULL
);
375 /* consume all events for this or earlier times. Be careful to
376 allow a new event to appear under our feet */
377 events
->processing
= 1;
378 while (events
->queue
->time_of_event
<= event_time
) {
379 sim_event
*to_do
= events
->queue
;
380 sim_event_handler
*handler
= to_do
->handler
;
381 void *data
= to_do
->data
;
382 events
->queue
= to_do
->next
;
384 "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx\n",
392 events
->processing
= 0;
394 /* re-caculate time for new events - advance the time */
395 update_time_from_event(sd
);
396 SIM_ASSERT(events
->time_from_event
> 0 && events
->queue
!= NULL
);
397 events
->time_from_event
-= 1;