Provide more detailed traces of the event queue.
[external/binutils.git] / sim / common / sim-events.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4
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.
9
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.
14  
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.
18  
19     */
20
21
22 #ifndef _SIM_EVENTS_C_
23 #define _SIM_EVENTS_C_
24
25 #include "sim-main.h"
26 #include "sim-assert.h"
27
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #else
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 #endif
35
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39
40 #include <signal.h> /* For SIGPROCMASK et.al. */
41
42 typedef enum {
43   watch_invalid,
44
45   /* core - target byte order */
46   watch_core_targ_1,
47   watch_core_targ_2,
48   watch_core_targ_4,
49   watch_core_targ_8,
50   /* core - big-endian */
51   watch_core_be_1,
52   watch_core_be_2,
53   watch_core_be_4,
54   watch_core_be_8,
55   /* core - little-endian */
56   watch_core_le_1,
57   watch_core_le_2,
58   watch_core_le_4,
59   watch_core_le_8,
60
61   /* sim - host byte order */
62   watch_sim_host_1,
63   watch_sim_host_2,
64   watch_sim_host_4,
65   watch_sim_host_8,
66   /* sim - big-endian */
67   watch_sim_be_1,
68   watch_sim_be_2,
69   watch_sim_be_4,
70   watch_sim_be_8,
71   /* sim - little-endian */
72   watch_sim_le_1,
73   watch_sim_le_2,
74   watch_sim_le_4,
75   watch_sim_le_8,
76   
77   /* wallclock */
78   watch_clock,
79
80   /* timer */
81   watch_timer,
82 } sim_event_watchpoints;
83
84
85 struct _sim_event {
86   sim_event_watchpoints watching;
87   void *data;
88   sim_event_handler *handler;
89   /* timer event */
90   signed64 time_of_event;
91   /* watch wallclock event */
92   unsigned wallclock;
93   /* watch core address */
94   address_word core_addr;
95   unsigned core_map;
96   /* watch sim addr */
97   void *host_addr;
98   /* watch core/sim range */
99   int is_within; /* 0/1 */
100   unsigned ub;
101   unsigned lb;
102   unsigned64 ub64;
103   unsigned64 lb64;
104   /* trace info (if any) */
105   char *trace;
106   /* list */
107   sim_event *next;
108 };
109
110
111 /* The event queue maintains a single absolute time using two
112    variables.
113    
114    TIME_OF_EVENT: this holds the time at which the next event is ment
115    to occure.  If no next event it will hold the time of the last
116    event.
117
118    TIME_FROM_EVENT: The current distance from TIME_OF_EVENT.  A value
119    <= 0 (except when poll-event is being processed) indicates that
120    event processing is due.  This variable is decremented once for
121    each iteration of a clock cycle.
122
123    Initially, the clock is started at time one (0) with TIME_OF_EVENT
124    == 0 and TIME_FROM_EVENT == 0 and with NR_TICKS_TO_PROCESS == 1.
125
126    Clearly there is a bug in that this code assumes that the absolute
127    time counter will never become greater than 2^62.
128
129    To avoid the need to use 64bit arithmetic, the event queue always
130    contains at least one event scheduled every 16 000 ticks.  This
131    limits the time from event counter to values less than
132    16 000. */
133
134
135 #if !defined (SIM_EVENTS_POLL_RATE)
136 #define SIM_EVENTS_POLL_RATE 0x1000
137 #endif
138
139
140 #define _ETRACE sd, NULL
141
142 #undef ETRACE_P
143 #define ETRACE_P (WITH_TRACE && STATE_EVENTS (sd)->trace)
144
145 #undef ETRACE
146 #define ETRACE(ARGS) \
147 do \
148   { \
149     if (ETRACE_P) \
150       { \
151         if (STRACE_DEBUG_P (sd)) \
152           { \
153             const char *file; \
154             SIM_FILTER_PATH (file, __FILE__); \
155             trace_printf (sd, NULL, "%s:%d: ", file, __LINE__); \
156           } \
157         trace_printf  ARGS; \
158       } \
159   } \
160 while (0)
161
162
163 /* event queue iterator - don't iterate over the held queue. */
164
165 #if EXTERN_SIM_EVENTS_P
166 static sim_event **
167 next_event_queue (SIM_DESC sd,
168                   sim_event **queue)
169 {
170   if (queue == NULL)
171     return &STATE_EVENTS (sd)->queue;
172   else if (queue == &STATE_EVENTS (sd)->queue)
173     return &STATE_EVENTS (sd)->watchpoints;
174   else if (queue == &STATE_EVENTS (sd)->watchpoints)
175     return &STATE_EVENTS (sd)->watchedpoints;
176   else if (queue == &STATE_EVENTS (sd)->watchedpoints)
177     return NULL;
178   else
179     sim_io_error (sd, "next_event_queue - bad queue");
180   return NULL;
181 }
182 #endif
183
184
185 STATIC_INLINE_SIM_EVENTS\
186 (void)
187 sim_events_poll (SIM_DESC sd,
188                  void *data)
189 {
190   /* just re-schedule in 1000 million ticks time */
191   sim_events_schedule (sd, SIM_EVENTS_POLL_RATE, sim_events_poll, sd);
192   sim_io_poll_quit (sd);
193 }
194
195
196 /* "events" module install handler.
197    This is called via sim_module_install to install the "events" subsystem
198    into the simulator.  */
199
200 #if EXTERN_SIM_EVENTS_P
201 STATIC_SIM_EVENTS (MODULE_UNINSTALL_FN) sim_events_uninstall;
202 STATIC_SIM_EVENTS (MODULE_INIT_FN) sim_events_init;
203 STATIC_SIM_EVENTS (MODULE_RESUME_FN) sim_events_resume;
204 STATIC_SIM_EVENTS (MODULE_SUSPEND_FN) sim_events_suspend;
205 #endif
206
207 #if EXTERN_SIM_EVENTS_P
208 SIM_RC
209 sim_events_install (SIM_DESC sd)
210 {
211   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
212   sim_module_add_uninstall_fn (sd, sim_events_uninstall);
213   sim_module_add_init_fn (sd, sim_events_init);
214   sim_module_add_resume_fn (sd, sim_events_resume);
215   sim_module_add_suspend_fn (sd, sim_events_suspend);
216   return SIM_RC_OK;
217 }
218 #endif
219
220
221 /* Suspend/resume the event queue manager when the simulator is not
222    running */
223
224 #if EXTERN_SIM_EVENTS_P
225 static SIM_RC
226 sim_events_resume (SIM_DESC sd)
227 {
228   sim_events *events = STATE_EVENTS (sd);
229   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
230   SIM_ASSERT (events->resume_wallclock == 0);
231   events->resume_wallclock = sim_elapsed_time_get ();
232   return SIM_RC_OK;
233 }
234 #endif
235
236 #if EXTERN_SIM_EVENTS_P
237 static SIM_RC
238 sim_events_suspend (SIM_DESC sd)
239 {
240   sim_events *events = STATE_EVENTS (sd);
241   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
242   SIM_ASSERT (events->resume_wallclock != 0);
243   events->elapsed_wallclock += sim_elapsed_time_since (events->resume_wallclock);
244   events->resume_wallclock = 0;
245   return SIM_RC_OK;
246 }
247 #endif
248
249
250 /* Uninstall the "events" subsystem from the simulator.  */
251
252 #if EXTERN_SIM_EVENTS_P
253 static void
254 sim_events_uninstall (SIM_DESC sd)
255 {
256   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
257   /* FIXME: free buffers, etc. */
258 }
259 #endif
260
261
262 /* malloc/free */
263
264 #if EXTERN_SIM_EVENTS_P
265 static sim_event *
266 sim_events_zalloc (SIM_DESC sd)
267 {
268   sim_events *events = STATE_EVENTS (sd);
269   sim_event *new = events->free_list;
270   if (new != NULL)
271     {
272       events->free_list = new->next;
273       memset (new, 0, sizeof (*new));
274     }
275   else
276     {
277 #if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK)
278       /*-LOCK-*/
279       sigset_t old_mask;
280       sigset_t new_mask;
281       sigfillset(&new_mask);
282       sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
283 #endif
284       new = ZALLOC (sim_event);
285 #if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK)
286       /*-UNLOCK-*/
287       sigprocmask (SIG_SETMASK, &old_mask, NULL);
288 #endif
289     }
290   return new;
291 }
292 #endif
293
294 STATIC_INLINE_SIM_EVENTS\
295 (void)
296 sim_events_free (SIM_DESC sd,
297                  sim_event *dead)
298 {
299   sim_events *events = STATE_EVENTS (sd);
300   dead->next = events->free_list;
301   events->free_list = dead;
302   if (dead->trace != NULL)
303     {
304       free (dead->trace); /* NB: asprintf returns a `free' buf */
305       dead->trace = NULL;
306     }
307 }
308
309
310 /* Initialize the simulator event manager */
311
312 #if EXTERN_SIM_EVENTS_P
313 SIM_RC
314 sim_events_init (SIM_DESC sd)
315 {
316   sim_events *events = STATE_EVENTS (sd);
317
318   /* drain the interrupt queue */
319   events->nr_held = 0;
320   if (events->held == NULL)
321     events->held = NZALLOC (sim_event, MAX_NR_SIGNAL_SIM_EVENTS);
322
323   /* drain the normal queues */
324   {
325     sim_event **queue = NULL;
326     while ((queue = next_event_queue (sd, queue)) != NULL)
327       {
328         if (queue == NULL) break;
329         while (*queue != NULL)
330           {
331             sim_event *dead = *queue;
332             *queue = dead->next;
333             sim_events_free (sd, dead);
334           }
335         *queue = NULL;
336       }
337   }
338
339   /* wind time back to zero */
340   events->nr_ticks_to_process = 1; /* start by doing queue */
341   events->time_of_event = 0;
342   events->time_from_event = 0;
343   events->elapsed_wallclock = 0;
344   events->resume_wallclock = 0;
345
346   /* schedule our initial counter event */
347   sim_events_schedule (sd, 0, sim_events_poll, sd);
348
349   /* from now on, except when the large-int event is being processed
350      the event queue is non empty */
351   SIM_ASSERT (events->queue != NULL);
352
353   return SIM_RC_OK;
354 }
355 #endif
356
357
358 INLINE_SIM_EVENTS\
359 (signed64)
360 sim_events_time (SIM_DESC sd)
361 {
362   sim_events *events = STATE_EVENTS (sd);
363   return (events->time_of_event - events->time_from_event);
364 }
365
366
367 INLINE_SIM_EVENTS\
368 (unsigned long)
369 sim_events_elapsed_time (SIM_DESC sd)
370 {
371   unsigned long elapsed = STATE_EVENTS (sd)->elapsed_wallclock;
372
373   /* Are we being called inside sim_resume?
374      (Is there a simulation in progress?)  */
375   if (STATE_EVENTS (sd)->resume_wallclock != 0)
376      elapsed += sim_elapsed_time_since (STATE_EVENTS (sd)->resume_wallclock);
377
378   return elapsed;
379 }
380
381
382 STATIC_INLINE_SIM_EVENTS\
383 (void)
384 update_time_from_event (SIM_DESC sd)
385 {
386   sim_events *events = STATE_EVENTS (sd);
387   signed64 current_time = sim_events_time (sd);
388   if (events->queue != NULL)
389     {
390       events->time_of_event = events->queue->time_of_event;
391       events->time_from_event = (events->queue->time_of_event - current_time);
392     }
393   else
394     {
395       events->time_of_event = current_time - 1;
396       events->time_from_event = -1;
397     }
398   if (ETRACE_P)
399     {
400       sim_event *event;
401       int i;
402       for (event = events->queue, i = 0;
403            event != NULL;
404            event = event->next, i++)
405         {
406           ETRACE ((_ETRACE,
407                    "event time-from-event - time %ld, delta %ld - event %d, tag 0x%lx, time %ld, handler 0x%lx, data 0x%lx%s%s\n",
408                    (long)current_time,
409                    (long)events->time_from_event,
410                    i,
411                    (long)event,
412                    (long)event->time_of_event,
413                    (long)event->handler,
414                    (long)event->data,
415                    (event->trace != NULL) ? ", " : "",
416                    (event->trace != NULL) ? event->trace : ""));
417         }
418     }
419   SIM_ASSERT (current_time == sim_events_time (sd));
420 }
421
422
423 #if EXTERN_SIM_EVENTS_P
424 static void
425 insert_sim_event (SIM_DESC sd,
426                   sim_event *new_event,
427                   signed64 delta)
428 {
429   sim_events *events = STATE_EVENTS (sd);
430   sim_event *curr;
431   sim_event **prev;
432   signed64 time_of_event;
433
434   if (delta < 0)
435     sim_io_error (sd, "what is past is past!\n");
436   
437   /* compute when the event should occure */
438   time_of_event = sim_events_time (sd) + delta;
439   
440   /* find the queue insertion point - things are time ordered */
441   prev = &events->queue;
442   curr = events->queue;
443   while (curr != NULL && time_of_event >= curr->time_of_event)
444     {
445       SIM_ASSERT (curr->next == NULL
446                   || curr->time_of_event <= curr->next->time_of_event);
447       prev = &curr->next;
448       curr = curr->next;
449     }
450   SIM_ASSERT (curr == NULL || time_of_event < curr->time_of_event);
451   
452   /* insert it */
453   new_event->next = curr;
454   *prev = new_event;
455   new_event->time_of_event = time_of_event;
456   
457   /* adjust the time until the first event */
458   update_time_from_event (sd);
459 }
460 #endif
461
462
463 #if EXTERN_SIM_EVENTS_P
464 sim_event *
465 sim_events_schedule (SIM_DESC sd,
466                      signed64 delta_time,
467                      sim_event_handler *handler,
468                      void *data)
469 {
470   va_list dummy;
471   return sim_events_schedule_vtracef (sd, delta_time, handler, data,
472                                       NULL, dummy);
473 }
474 #endif
475
476
477 #if EXTERN_SIM_EVENTS_P
478 sim_event *
479 sim_events_schedule_tracef (SIM_DESC sd,
480                             signed64 delta_time,
481                             sim_event_handler *handler,
482                             void *data,
483                             const char *fmt,
484                             ...)
485 {
486   sim_event *new_event;
487   va_list ap;
488   va_start (ap, fmt);
489   new_event = sim_events_schedule_vtracef (sd, delta_time, handler, data, fmt, ap);
490   va_end (ap);
491   return new_event;
492 }
493 #endif
494
495
496 #if EXTERN_SIM_EVENTS_P
497 sim_event *
498 sim_events_schedule_vtracef (SIM_DESC sd,
499                              signed64 delta_time,
500                              sim_event_handler *handler,
501                              void *data,
502                              const char *fmt,
503                              va_list ap)
504 {
505   sim_event *new_event = sim_events_zalloc (sd);
506   new_event->data = data;
507   new_event->handler = handler;
508   new_event->watching = watch_timer;
509   if (fmt == NULL || !ETRACE_P || vasprintf (&new_event->trace, fmt, ap) < 0)
510     new_event->trace = NULL;
511   insert_sim_event(sd, new_event, delta_time);
512   ETRACE((_ETRACE,
513           "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx%s%s\n",
514           (long)sim_events_time(sd),
515           (long)new_event,
516           (long)new_event->time_of_event,
517           (long)new_event->handler,
518           (long)new_event->data,
519           (new_event->trace != NULL) ? ", " : "",
520           (new_event->trace != NULL) ? new_event->trace : ""));
521   return new_event;
522 }
523 #endif
524
525
526 #if EXTERN_SIM_EVENTS_P
527 void
528 sim_events_schedule_after_signal (SIM_DESC sd,
529                                   signed64 delta_time,
530                                   sim_event_handler *handler,
531                                   void *data)
532 {
533   sim_events *events = STATE_EVENTS (sd);
534   sim_event *new_event;
535 #if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK)
536   /*-LOCK-*/
537   sigset_t old_mask;
538   sigset_t new_mask;
539   sigfillset(&new_mask);
540   sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
541 #endif
542   
543   /* allocate an event entry from the signal buffer */
544   new_event = &events->held [events->nr_held];
545   events->nr_held ++;
546   if (events->nr_held > MAX_NR_SIGNAL_SIM_EVENTS)
547     {
548       sim_engine_abort (NULL, NULL, NULL_CIA,
549                         "sim_events_schedule_after_signal - buffer oveflow");
550     }
551   
552   new_event->data = data;
553   new_event->handler = handler;
554   new_event->time_of_event = delta_time; /* work it out later */
555   new_event->next = NULL;
556
557   events->work_pending = 1; /* notify main process */
558
559 #if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK)
560   /*-UNLOCK-*/
561   sigprocmask (SIG_SETMASK, &old_mask, NULL);
562 #endif
563   
564   ETRACE ((_ETRACE,
565            "signal scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
566            (long)sim_events_time(sd),
567            (long)new_event,
568            (long)new_event->time_of_event,
569            (long)new_event->handler,
570            (long)new_event->data));
571 }
572 #endif
573
574
575 #if EXTERN_SIM_EVENTS_P
576 sim_event *
577 sim_events_watch_clock (SIM_DESC sd,
578                         unsigned delta_ms_time,
579                         sim_event_handler *handler,
580                         void *data)
581 {
582   sim_events *events = STATE_EVENTS (sd);
583   sim_event *new_event = sim_events_zalloc (sd);
584   /* type */
585   new_event->watching = watch_clock;
586   /* handler */
587   new_event->data = data;
588   new_event->handler = handler;
589   /* data */
590   if (events->resume_wallclock == 0)
591     new_event->wallclock = (events->elapsed_wallclock + delta_ms_time);
592   else
593     new_event->wallclock = (events->elapsed_wallclock
594                             + sim_elapsed_time_since (events->resume_wallclock)
595                             + delta_ms_time);
596   /* insert */
597   new_event->next = events->watchpoints;
598   events->watchpoints = new_event;
599   events->work_pending = 1;
600   ETRACE ((_ETRACE,
601           "event watching clock at %ld - tag 0x%lx - wallclock %ld, handler 0x%lx, data 0x%lx\n",
602            (long)sim_events_time (sd),
603            (long)new_event,
604            (long)new_event->wallclock,
605            (long)new_event->handler,
606            (long)new_event->data));
607   return new_event;
608 }
609 #endif
610
611
612 #if EXTERN_SIM_EVENTS_P
613 sim_event *
614 sim_events_watch_sim (SIM_DESC sd,
615                       void *host_addr,
616                       int nr_bytes,
617                       int byte_order,
618                       int is_within,
619                       unsigned64 lb,
620                       unsigned64 ub,
621                       sim_event_handler *handler,
622                       void *data)
623 {
624   sim_events *events = STATE_EVENTS (sd);
625   sim_event *new_event = sim_events_zalloc (sd);
626   /* type */
627   switch (byte_order)
628     {
629     case 0:
630       switch (nr_bytes)
631         {
632         case 1: new_event->watching = watch_sim_host_1; break;
633         case 2: new_event->watching = watch_sim_host_2; break;
634         case 4: new_event->watching = watch_sim_host_4; break;
635         case 8: new_event->watching = watch_sim_host_8; break;
636         default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes");
637         }
638       break;
639     case BIG_ENDIAN:
640       switch (nr_bytes)
641         {
642         case 1: new_event->watching = watch_sim_be_1; break;
643         case 2: new_event->watching = watch_sim_be_2; break;
644         case 4: new_event->watching = watch_sim_be_4; break;
645         case 8: new_event->watching = watch_sim_be_8; break;
646         default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes");
647         }
648       break;
649     case LITTLE_ENDIAN:
650       switch (nr_bytes)
651         {
652         case 1: new_event->watching = watch_sim_le_1; break;
653         case 2: new_event->watching = watch_sim_le_2; break;
654         case 4: new_event->watching = watch_sim_le_4; break;
655         case 8: new_event->watching = watch_sim_le_8; break;
656         default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes");
657         }
658       break;
659     default:
660       sim_io_error (sd, "sim_events_watch_sim - invalid byte order");
661     }
662   /* handler */
663   new_event->data = data;
664   new_event->handler = handler;
665   /* data */
666   new_event->host_addr = host_addr;
667   new_event->lb = lb;
668   new_event->lb64 = lb;
669   new_event->ub = ub;
670   new_event->ub64 = ub;
671   new_event->is_within = (is_within != 0);
672   /* insert */
673   new_event->next = events->watchpoints;
674   events->watchpoints = new_event;
675   events->work_pending = 1;
676   ETRACE ((_ETRACE,
677            "event watching host at %ld - tag 0x%lx - host-addr 0x%lx, 0x%lx..0x%lx, handler 0x%lx, data 0x%lx\n",
678            (long)sim_events_time (sd),
679            (long)new_event,
680            (long)new_event->host_addr,
681            (long)new_event->lb,
682            (long)new_event->ub,
683            (long)new_event->handler,
684            (long)new_event->data));
685   return new_event;
686 }
687 #endif
688
689
690 #if EXTERN_SIM_EVENTS_P
691 sim_event *
692 sim_events_watch_core (SIM_DESC sd,
693                        address_word core_addr,
694                        unsigned core_map,
695                        int nr_bytes,
696                        int byte_order,
697                        int is_within,
698                        unsigned64 lb,
699                        unsigned64 ub,
700                        sim_event_handler *handler,
701                        void *data)
702 {
703   sim_events *events = STATE_EVENTS (sd);
704   sim_event *new_event = sim_events_zalloc (sd);
705   /* type */
706   switch (byte_order)
707     {
708     case 0:
709       switch (nr_bytes)
710         {
711         case 1: new_event->watching = watch_core_targ_1; break;
712         case 2: new_event->watching = watch_core_targ_2; break;
713         case 4: new_event->watching = watch_core_targ_4; break;
714         case 8: new_event->watching = watch_core_targ_8; break;
715         default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes");
716         }
717       break;
718     case BIG_ENDIAN:
719       switch (nr_bytes)
720         {
721         case 1: new_event->watching = watch_core_be_1; break;
722         case 2: new_event->watching = watch_core_be_2; break;
723         case 4: new_event->watching = watch_core_be_4; break;
724         case 8: new_event->watching = watch_core_be_8; break;
725         default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes");
726         }
727       break;
728     case LITTLE_ENDIAN:
729       switch (nr_bytes)
730         {
731         case 1: new_event->watching = watch_core_le_1; break;
732         case 2: new_event->watching = watch_core_le_2; break;
733         case 4: new_event->watching = watch_core_le_4; break;
734         case 8: new_event->watching = watch_core_le_8; break;
735         default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes");
736         }
737       break;
738     default:
739       sim_io_error (sd, "sim_events_watch_core - invalid byte order");
740     }
741   /* handler */
742   new_event->data = data;
743   new_event->handler = handler;
744   /* data */
745   new_event->core_addr = core_addr;
746   new_event->core_map = core_map;
747   new_event->lb = lb;
748   new_event->lb64 = lb;
749   new_event->ub = ub;
750   new_event->ub64 = ub;
751   new_event->is_within = (is_within != 0);
752   /* insert */
753   new_event->next = events->watchpoints;
754   events->watchpoints = new_event;
755   events->work_pending = 1;
756   ETRACE ((_ETRACE,
757            "event watching host at %ld - tag 0x%lx - host-addr 0x%lx, 0x%lx..0x%lx, handler 0x%lx, data 0x%lx\n",
758            (long)sim_events_time (sd),
759            (long)new_event,
760            (long)new_event->host_addr,
761            (long)new_event->lb,
762            (long)new_event->ub,
763            (long)new_event->handler,
764            (long)new_event->data));
765   return new_event;
766 }
767 #endif
768
769
770 #if EXTERN_SIM_EVENTS_P
771 void
772 sim_events_deschedule (SIM_DESC sd,
773                        sim_event *event_to_remove)
774 {
775   sim_events *events = STATE_EVENTS (sd);
776   sim_event *to_remove = (sim_event*)event_to_remove;
777   if (event_to_remove != NULL)
778     {
779       sim_event **queue = NULL;
780       while ((queue = next_event_queue (sd, queue)) != NULL)
781         {
782           sim_event **ptr_to_current;
783           for (ptr_to_current = queue;
784                *ptr_to_current != NULL && *ptr_to_current != to_remove;
785                ptr_to_current = &(*ptr_to_current)->next);
786           if (*ptr_to_current == to_remove)
787             {
788               sim_event *dead = *ptr_to_current;
789               *ptr_to_current = dead->next;
790               ETRACE ((_ETRACE,
791                        "event/watch descheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx%s%s\n",
792                        (long) sim_events_time (sd),
793                        (long) event_to_remove,
794                        (long) dead->time_of_event,
795                        (long) dead->handler,
796                        (long) dead->data,
797                        (dead->trace != NULL) ? ", " : "",
798                        (dead->trace != NULL) ? dead->trace : ""));
799               sim_events_free (sd, dead);
800               update_time_from_event (sd);
801               SIM_ASSERT ((events->time_from_event >= 0) == (events->queue != NULL));
802               return;
803             }
804         }
805     }
806   ETRACE ((_ETRACE,
807            "event/watch descheduled at %ld - tag 0x%lx - not found\n",
808            (long) sim_events_time (sd),
809            (long) event_to_remove));
810 }
811 #endif
812
813
814 STATIC_INLINE_SIM_EVENTS\
815 (int)
816 sim_watch_valid (SIM_DESC sd,
817                  sim_event *to_do)
818 {
819   switch (to_do->watching)
820     {
821
822 #define WATCH_CORE(N,OP,EXT) \
823       int ok; \
824       unsigned_##N word = 0; \
825       int nr_read = sim_core_read_buffer (sd, NULL, to_do->core_map, &word, \
826                                           to_do->core_addr, sizeof (word)); \
827       OP (word); \
828       ok = (nr_read == sizeof (unsigned_##N) \
829             && (to_do->is_within \
830                 == (word >= to_do->lb##EXT \
831                     && word <= to_do->ub##EXT)));
832
833     case watch_core_targ_1:
834       {
835         WATCH_CORE (1, T2H,);
836         return ok;
837       }
838     case watch_core_targ_2:
839       {
840         WATCH_CORE (2, T2H,);
841         return ok;
842       }
843     case watch_core_targ_4:
844       {
845         WATCH_CORE (4, T2H,);
846         return ok;
847       }
848     case watch_core_targ_8:
849       {
850         WATCH_CORE (8, T2H,64);
851         return ok;
852       }
853
854     case watch_core_be_1:
855       {
856         WATCH_CORE (1, BE2H,);
857         return ok;
858       }
859     case watch_core_be_2:
860       {
861         WATCH_CORE (2, BE2H,);
862         return ok;
863       }
864     case watch_core_be_4:
865       {
866         WATCH_CORE (4, BE2H,);
867         return ok;
868       }
869     case watch_core_be_8:
870       {
871         WATCH_CORE (8, BE2H,64);
872         return ok;
873       }
874
875     case watch_core_le_1:
876       {
877         WATCH_CORE (1, LE2H,);
878         return ok;
879       }
880     case watch_core_le_2:
881       {
882         WATCH_CORE (2, LE2H,);
883         return ok;
884       }
885     case watch_core_le_4:
886       {
887         WATCH_CORE (4, LE2H,);
888         return ok;
889       }
890     case watch_core_le_8:
891       {
892         WATCH_CORE (8, LE2H,64);
893         return ok;
894       }
895 #undef WATCH_CORE
896
897 #define WATCH_SIM(N,OP,EXT) \
898       int ok; \
899       unsigned_##N word = *(unsigned_##N*)to_do->host_addr; \
900       OP (word); \
901       ok = (to_do->is_within \
902             == (word >= to_do->lb##EXT \
903                 && word <= to_do->ub##EXT));
904
905     case watch_sim_host_1:
906       {
907         WATCH_SIM (1, word = ,);
908         return ok;
909       }
910     case watch_sim_host_2:
911       {
912         WATCH_SIM (2, word = ,);
913         return ok;
914       }
915     case watch_sim_host_4:
916       {
917         WATCH_SIM (4, word = ,);
918         return ok;
919       }
920     case watch_sim_host_8:
921       {
922         WATCH_SIM (8, word = ,64);
923         return ok;
924       }
925
926     case watch_sim_be_1:
927       {
928         WATCH_SIM (1, BE2H,);
929         return ok;
930       }
931     case watch_sim_be_2:
932       {
933         WATCH_SIM (2, BE2H,);
934         return ok;
935       }
936     case watch_sim_be_4:
937       {
938         WATCH_SIM (4, BE2H,);
939         return ok;
940       }
941     case watch_sim_be_8:
942       {
943         WATCH_SIM (8, BE2H,64);
944         return ok;
945       }
946
947     case watch_sim_le_1:
948       {
949         WATCH_SIM (1, LE2H,);
950         return ok;
951       }
952     case watch_sim_le_2:
953       {
954         WATCH_SIM (1, LE2H,);
955         return ok;
956       }
957     case watch_sim_le_4:
958       {
959         WATCH_SIM (1, LE2H,);
960         return ok;
961       }
962     case watch_sim_le_8:
963       {
964         WATCH_SIM (1, LE2H,64);
965         return ok;
966       }
967 #undef WATCH_SIM
968
969     case watch_clock: /* wallclock */
970       {
971         unsigned long elapsed_time = sim_events_elapsed_time (sd);
972         return (elapsed_time >= to_do->wallclock);
973       }
974
975     default:
976       sim_io_error (sd, "sim_watch_valid - bad switch");
977       break;
978
979     }
980   return 1;
981 }
982
983
984 INLINE_SIM_EVENTS\
985 (int)
986 sim_events_tick (SIM_DESC sd)
987 {
988   sim_events *events = STATE_EVENTS (sd);
989
990   /* this should only be called after the previous ticks have been
991      fully processed */
992
993   /* Advance the time but *only* if there is nothing to process */
994   if (events->work_pending
995       || events->time_from_event == 0)
996     {
997       events->nr_ticks_to_process += 1;
998       return 1;
999     }
1000   else
1001     {
1002       events->time_from_event -= 1;
1003       return 0;
1004     }
1005 }
1006
1007
1008 INLINE_SIM_EVENTS\
1009 (int)
1010 sim_events_tickn (SIM_DESC sd,
1011                   int n)
1012 {
1013   sim_events *events = STATE_EVENTS (sd);
1014   SIM_ASSERT (n > 0);
1015
1016   /* this should only be called after the previous ticks have been
1017      fully processed */
1018
1019   /* Advance the time but *only* if there is nothing to process */
1020   if (events->work_pending || events->time_from_event < n)
1021     {
1022       events->nr_ticks_to_process += n;
1023       return 1;
1024     }
1025   else
1026     {
1027       events->time_from_event -= n;
1028       return 0;
1029     }
1030 }
1031
1032
1033 INLINE_SIM_EVENTS\
1034 (void)
1035 sim_events_slip (SIM_DESC sd,
1036                  int slip)
1037 {
1038   sim_events *events = STATE_EVENTS (sd);
1039   SIM_ASSERT (slip > 0);
1040
1041   /* Flag a ready event with work_pending instead of number of ticks
1042      to process so that the time continues to be correct */
1043   if (events->time_from_event < slip)
1044     {
1045       events->work_pending = 1;
1046     }
1047   events->time_from_event -= slip;
1048 }
1049
1050
1051 INLINE_SIM_EVENTS\
1052 (void)
1053 sim_events_preprocess (SIM_DESC sd,
1054                        int events_were_last,
1055                        int events_were_next)
1056 {
1057   sim_events *events = STATE_EVENTS(sd);
1058   if (events_were_last)
1059     {
1060       /* Halted part way through event processing */
1061       ASSERT (events->nr_ticks_to_process != 0);
1062       /* The external world can't tell if the event that stopped the
1063          simulator was the last event to process. */
1064       ASSERT (events_were_next);
1065       sim_events_process (sd);
1066     }
1067   else if (events_were_next)
1068     {
1069       /* Halted by the last processor */
1070       if (sim_events_tick (sd))
1071         sim_events_process (sd);
1072     }
1073 }
1074
1075
1076 INLINE_SIM_EVENTS\
1077 (void)
1078 sim_events_process (SIM_DESC sd)
1079 {
1080   sim_events *events = STATE_EVENTS(sd);
1081   signed64 event_time = sim_events_time(sd);
1082
1083   /* Clear work_pending before checking nr_held.  Clearing
1084      work_pending after nr_held (with out a lock could loose an
1085      event). */
1086   events->work_pending = 0;
1087
1088   /* move any events that were asynchronously queued by any signal
1089      handlers onto the real event queue.  */
1090   if (events->nr_held > 0)
1091     {
1092       int i;
1093       
1094 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
1095       /*-LOCK-*/
1096       sigset_t old_mask;
1097       sigset_t new_mask;
1098       sigfillset(&new_mask);
1099       sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
1100 #endif
1101
1102       for (i = 0; i < events->nr_held; i++)
1103         {
1104           sim_event *entry = &events->held [i];
1105           sim_events_schedule (sd,
1106                                entry->time_of_event,
1107                                entry->handler,
1108                                entry->data);
1109         }
1110       events->nr_held = 0;
1111       
1112 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
1113       /*-UNLOCK-*/
1114       sigprocmask(SIG_SETMASK, &old_mask, NULL);
1115 #endif
1116       
1117     }
1118   
1119   /* Process any watchpoints. Be careful to allow a watchpoint to
1120      appear/disappear under our feet.
1121      To ensure that watchpoints are processed only once per cycle,
1122      they are moved onto a watched queue, this returned to the
1123      watchpoint queue when all queue processing has been
1124      completed. */
1125   while (events->watchpoints != NULL)
1126     {
1127       sim_event *to_do = events->watchpoints;
1128       events->watchpoints = to_do->next;
1129       if (sim_watch_valid (sd, to_do))
1130         {
1131           sim_event_handler *handler = to_do->handler;
1132           void *data = to_do->data;
1133           ETRACE((_ETRACE,
1134                   "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx%s%s\n",
1135                   (long) event_time,
1136                   (long) to_do,
1137                   (long) handler,
1138                   (long) data,
1139                   (to_do->trace != NULL) ? ", " : "",
1140                   (to_do->trace != NULL) ? to_do->trace : ""));
1141           sim_events_free (sd, to_do);
1142           handler (sd, data);
1143         }
1144       else
1145         {
1146           to_do->next = events->watchedpoints;
1147           events->watchedpoints = to_do;
1148         }
1149     }
1150   
1151   /* consume all events for this or earlier times.  Be careful to
1152      allow an event to appear/disappear under our feet */
1153   while (events->queue->time_of_event <
1154          (event_time + events->nr_ticks_to_process))
1155     {
1156       sim_event *to_do = events->queue;
1157       sim_event_handler *handler = to_do->handler;
1158       void *data = to_do->data;
1159       events->queue = to_do->next;
1160       update_time_from_event (sd);
1161       ETRACE((_ETRACE,
1162               "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx%s%s\n",
1163               (long) event_time,
1164               (long) to_do,
1165               (long) handler,
1166               (long) data,
1167               (to_do->trace != NULL) ? ", " : "",
1168               (to_do->trace != NULL) ? to_do->trace : ""));
1169       sim_events_free (sd, to_do);
1170       handler (sd, data);
1171     }
1172   
1173   /* put things back where they belong ready for the next iteration */
1174   events->watchpoints = events->watchedpoints;
1175   events->watchedpoints = NULL;
1176   if (events->watchpoints != NULL)
1177     events->work_pending = 1;
1178   
1179   /* advance the time */
1180   SIM_ASSERT (events->time_from_event >= events->nr_ticks_to_process);
1181   SIM_ASSERT (events->queue != NULL); /* always poll event */
1182   events->time_from_event -= events->nr_ticks_to_process;
1183
1184   /* this round of processing complete */
1185   events->nr_ticks_to_process = 0;
1186 }
1187
1188 #endif