2000-06-25 Stephane Carrez <Stephane.Carrez@worldnet.fr>
[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 /* Returns the time that remains before the event is raised. */
383 INLINE_SIM_EVENTS\
384 (signed64)
385 sim_events_remain_time (SIM_DESC sd, sim_event *event)
386 {
387   if (event == 0)
388     return 0;
389   
390   return (event->time_of_event - sim_events_time (sd));
391 }
392
393
394
395 STATIC_INLINE_SIM_EVENTS\
396 (void)
397 update_time_from_event (SIM_DESC sd)
398 {
399   sim_events *events = STATE_EVENTS (sd);
400   signed64 current_time = sim_events_time (sd);
401   if (events->queue != NULL)
402     {
403       events->time_of_event = events->queue->time_of_event;
404       events->time_from_event = (events->queue->time_of_event - current_time);
405     }
406   else
407     {
408       events->time_of_event = current_time - 1;
409       events->time_from_event = -1;
410     }
411   if (ETRACE_P)
412     {
413       sim_event *event;
414       int i;
415       for (event = events->queue, i = 0;
416            event != NULL;
417            event = event->next, i++)
418         {
419           ETRACE ((_ETRACE,
420                    "event time-from-event - time %ld, delta %ld - event %d, tag 0x%lx, time %ld, handler 0x%lx, data 0x%lx%s%s\n",
421                    (long)current_time,
422                    (long)events->time_from_event,
423                    i,
424                    (long)event,
425                    (long)event->time_of_event,
426                    (long)event->handler,
427                    (long)event->data,
428                    (event->trace != NULL) ? ", " : "",
429                    (event->trace != NULL) ? event->trace : ""));
430         }
431     }
432   SIM_ASSERT (current_time == sim_events_time (sd));
433 }
434
435
436 #if EXTERN_SIM_EVENTS_P
437 static void
438 insert_sim_event (SIM_DESC sd,
439                   sim_event *new_event,
440                   signed64 delta)
441 {
442   sim_events *events = STATE_EVENTS (sd);
443   sim_event *curr;
444   sim_event **prev;
445   signed64 time_of_event;
446
447   if (delta < 0)
448     sim_io_error (sd, "what is past is past!\n");
449   
450   /* compute when the event should occure */
451   time_of_event = sim_events_time (sd) + delta;
452   
453   /* find the queue insertion point - things are time ordered */
454   prev = &events->queue;
455   curr = events->queue;
456   while (curr != NULL && time_of_event >= curr->time_of_event)
457     {
458       SIM_ASSERT (curr->next == NULL
459                   || curr->time_of_event <= curr->next->time_of_event);
460       prev = &curr->next;
461       curr = curr->next;
462     }
463   SIM_ASSERT (curr == NULL || time_of_event < curr->time_of_event);
464   
465   /* insert it */
466   new_event->next = curr;
467   *prev = new_event;
468   new_event->time_of_event = time_of_event;
469   
470   /* adjust the time until the first event */
471   update_time_from_event (sd);
472 }
473 #endif
474
475
476 #if EXTERN_SIM_EVENTS_P
477 sim_event *
478 sim_events_schedule (SIM_DESC sd,
479                      signed64 delta_time,
480                      sim_event_handler *handler,
481                      void *data)
482 {
483   va_list dummy;
484   return sim_events_schedule_vtracef (sd, delta_time, handler, data,
485                                       NULL, dummy);
486 }
487 #endif
488
489
490 #if EXTERN_SIM_EVENTS_P
491 sim_event *
492 sim_events_schedule_tracef (SIM_DESC sd,
493                             signed64 delta_time,
494                             sim_event_handler *handler,
495                             void *data,
496                             const char *fmt,
497                             ...)
498 {
499   sim_event *new_event;
500   va_list ap;
501   va_start (ap, fmt);
502   new_event = sim_events_schedule_vtracef (sd, delta_time, handler, data, fmt, ap);
503   va_end (ap);
504   return new_event;
505 }
506 #endif
507
508
509 #if EXTERN_SIM_EVENTS_P
510 sim_event *
511 sim_events_schedule_vtracef (SIM_DESC sd,
512                              signed64 delta_time,
513                              sim_event_handler *handler,
514                              void *data,
515                              const char *fmt,
516                              va_list ap)
517 {
518   sim_event *new_event = sim_events_zalloc (sd);
519   new_event->data = data;
520   new_event->handler = handler;
521   new_event->watching = watch_timer;
522   if (fmt == NULL || !ETRACE_P || vasprintf (&new_event->trace, fmt, ap) < 0)
523     new_event->trace = NULL;
524   insert_sim_event(sd, new_event, delta_time);
525   ETRACE((_ETRACE,
526           "event scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx%s%s\n",
527           (long)sim_events_time(sd),
528           (long)new_event,
529           (long)new_event->time_of_event,
530           (long)new_event->handler,
531           (long)new_event->data,
532           (new_event->trace != NULL) ? ", " : "",
533           (new_event->trace != NULL) ? new_event->trace : ""));
534   return new_event;
535 }
536 #endif
537
538
539 #if EXTERN_SIM_EVENTS_P
540 void
541 sim_events_schedule_after_signal (SIM_DESC sd,
542                                   signed64 delta_time,
543                                   sim_event_handler *handler,
544                                   void *data)
545 {
546   sim_events *events = STATE_EVENTS (sd);
547   sim_event *new_event;
548 #if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK)
549   /*-LOCK-*/
550   sigset_t old_mask;
551   sigset_t new_mask;
552   sigfillset(&new_mask);
553   sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
554 #endif
555   
556   /* allocate an event entry from the signal buffer */
557   new_event = &events->held [events->nr_held];
558   events->nr_held ++;
559   if (events->nr_held > MAX_NR_SIGNAL_SIM_EVENTS)
560     {
561       sim_engine_abort (NULL, NULL, NULL_CIA,
562                         "sim_events_schedule_after_signal - buffer oveflow");
563     }
564   
565   new_event->data = data;
566   new_event->handler = handler;
567   new_event->time_of_event = delta_time; /* work it out later */
568   new_event->next = NULL;
569
570   events->work_pending = 1; /* notify main process */
571
572 #if defined (HAVE_SIGPROCMASK) && defined (SIG_SETMASK)
573   /*-UNLOCK-*/
574   sigprocmask (SIG_SETMASK, &old_mask, NULL);
575 #endif
576   
577   ETRACE ((_ETRACE,
578            "signal scheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx\n",
579            (long)sim_events_time(sd),
580            (long)new_event,
581            (long)new_event->time_of_event,
582            (long)new_event->handler,
583            (long)new_event->data));
584 }
585 #endif
586
587
588 #if EXTERN_SIM_EVENTS_P
589 sim_event *
590 sim_events_watch_clock (SIM_DESC sd,
591                         unsigned delta_ms_time,
592                         sim_event_handler *handler,
593                         void *data)
594 {
595   sim_events *events = STATE_EVENTS (sd);
596   sim_event *new_event = sim_events_zalloc (sd);
597   /* type */
598   new_event->watching = watch_clock;
599   /* handler */
600   new_event->data = data;
601   new_event->handler = handler;
602   /* data */
603   if (events->resume_wallclock == 0)
604     new_event->wallclock = (events->elapsed_wallclock + delta_ms_time);
605   else
606     new_event->wallclock = (events->elapsed_wallclock
607                             + sim_elapsed_time_since (events->resume_wallclock)
608                             + delta_ms_time);
609   /* insert */
610   new_event->next = events->watchpoints;
611   events->watchpoints = new_event;
612   events->work_pending = 1;
613   ETRACE ((_ETRACE,
614           "event watching clock at %ld - tag 0x%lx - wallclock %ld, handler 0x%lx, data 0x%lx\n",
615            (long)sim_events_time (sd),
616            (long)new_event,
617            (long)new_event->wallclock,
618            (long)new_event->handler,
619            (long)new_event->data));
620   return new_event;
621 }
622 #endif
623
624
625 #if EXTERN_SIM_EVENTS_P
626 sim_event *
627 sim_events_watch_sim (SIM_DESC sd,
628                       void *host_addr,
629                       int nr_bytes,
630                       int byte_order,
631                       int is_within,
632                       unsigned64 lb,
633                       unsigned64 ub,
634                       sim_event_handler *handler,
635                       void *data)
636 {
637   sim_events *events = STATE_EVENTS (sd);
638   sim_event *new_event = sim_events_zalloc (sd);
639   /* type */
640   switch (byte_order)
641     {
642     case 0:
643       switch (nr_bytes)
644         {
645         case 1: new_event->watching = watch_sim_host_1; break;
646         case 2: new_event->watching = watch_sim_host_2; break;
647         case 4: new_event->watching = watch_sim_host_4; break;
648         case 8: new_event->watching = watch_sim_host_8; break;
649         default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes");
650         }
651       break;
652     case BIG_ENDIAN:
653       switch (nr_bytes)
654         {
655         case 1: new_event->watching = watch_sim_be_1; break;
656         case 2: new_event->watching = watch_sim_be_2; break;
657         case 4: new_event->watching = watch_sim_be_4; break;
658         case 8: new_event->watching = watch_sim_be_8; break;
659         default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes");
660         }
661       break;
662     case LITTLE_ENDIAN:
663       switch (nr_bytes)
664         {
665         case 1: new_event->watching = watch_sim_le_1; break;
666         case 2: new_event->watching = watch_sim_le_2; break;
667         case 4: new_event->watching = watch_sim_le_4; break;
668         case 8: new_event->watching = watch_sim_le_8; break;
669         default: sim_io_error (sd, "sim_events_watch_sim - invalid nr bytes");
670         }
671       break;
672     default:
673       sim_io_error (sd, "sim_events_watch_sim - invalid byte order");
674     }
675   /* handler */
676   new_event->data = data;
677   new_event->handler = handler;
678   /* data */
679   new_event->host_addr = host_addr;
680   new_event->lb = lb;
681   new_event->lb64 = lb;
682   new_event->ub = ub;
683   new_event->ub64 = ub;
684   new_event->is_within = (is_within != 0);
685   /* insert */
686   new_event->next = events->watchpoints;
687   events->watchpoints = new_event;
688   events->work_pending = 1;
689   ETRACE ((_ETRACE,
690            "event watching host at %ld - tag 0x%lx - host-addr 0x%lx, 0x%lx..0x%lx, handler 0x%lx, data 0x%lx\n",
691            (long)sim_events_time (sd),
692            (long)new_event,
693            (long)new_event->host_addr,
694            (long)new_event->lb,
695            (long)new_event->ub,
696            (long)new_event->handler,
697            (long)new_event->data));
698   return new_event;
699 }
700 #endif
701
702
703 #if EXTERN_SIM_EVENTS_P
704 sim_event *
705 sim_events_watch_core (SIM_DESC sd,
706                        address_word core_addr,
707                        unsigned core_map,
708                        int nr_bytes,
709                        int byte_order,
710                        int is_within,
711                        unsigned64 lb,
712                        unsigned64 ub,
713                        sim_event_handler *handler,
714                        void *data)
715 {
716   sim_events *events = STATE_EVENTS (sd);
717   sim_event *new_event = sim_events_zalloc (sd);
718   /* type */
719   switch (byte_order)
720     {
721     case 0:
722       switch (nr_bytes)
723         {
724         case 1: new_event->watching = watch_core_targ_1; break;
725         case 2: new_event->watching = watch_core_targ_2; break;
726         case 4: new_event->watching = watch_core_targ_4; break;
727         case 8: new_event->watching = watch_core_targ_8; break;
728         default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes");
729         }
730       break;
731     case BIG_ENDIAN:
732       switch (nr_bytes)
733         {
734         case 1: new_event->watching = watch_core_be_1; break;
735         case 2: new_event->watching = watch_core_be_2; break;
736         case 4: new_event->watching = watch_core_be_4; break;
737         case 8: new_event->watching = watch_core_be_8; break;
738         default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes");
739         }
740       break;
741     case LITTLE_ENDIAN:
742       switch (nr_bytes)
743         {
744         case 1: new_event->watching = watch_core_le_1; break;
745         case 2: new_event->watching = watch_core_le_2; break;
746         case 4: new_event->watching = watch_core_le_4; break;
747         case 8: new_event->watching = watch_core_le_8; break;
748         default: sim_io_error (sd, "sim_events_watch_core - invalid nr bytes");
749         }
750       break;
751     default:
752       sim_io_error (sd, "sim_events_watch_core - invalid byte order");
753     }
754   /* handler */
755   new_event->data = data;
756   new_event->handler = handler;
757   /* data */
758   new_event->core_addr = core_addr;
759   new_event->core_map = core_map;
760   new_event->lb = lb;
761   new_event->lb64 = lb;
762   new_event->ub = ub;
763   new_event->ub64 = ub;
764   new_event->is_within = (is_within != 0);
765   /* insert */
766   new_event->next = events->watchpoints;
767   events->watchpoints = new_event;
768   events->work_pending = 1;
769   ETRACE ((_ETRACE,
770            "event watching host at %ld - tag 0x%lx - host-addr 0x%lx, 0x%lx..0x%lx, handler 0x%lx, data 0x%lx\n",
771            (long)sim_events_time (sd),
772            (long)new_event,
773            (long)new_event->host_addr,
774            (long)new_event->lb,
775            (long)new_event->ub,
776            (long)new_event->handler,
777            (long)new_event->data));
778   return new_event;
779 }
780 #endif
781
782
783 #if EXTERN_SIM_EVENTS_P
784 void
785 sim_events_deschedule (SIM_DESC sd,
786                        sim_event *event_to_remove)
787 {
788   sim_events *events = STATE_EVENTS (sd);
789   sim_event *to_remove = (sim_event*)event_to_remove;
790   if (event_to_remove != NULL)
791     {
792       sim_event **queue = NULL;
793       while ((queue = next_event_queue (sd, queue)) != NULL)
794         {
795           sim_event **ptr_to_current;
796           for (ptr_to_current = queue;
797                *ptr_to_current != NULL && *ptr_to_current != to_remove;
798                ptr_to_current = &(*ptr_to_current)->next);
799           if (*ptr_to_current == to_remove)
800             {
801               sim_event *dead = *ptr_to_current;
802               *ptr_to_current = dead->next;
803               ETRACE ((_ETRACE,
804                        "event/watch descheduled at %ld - tag 0x%lx - time %ld, handler 0x%lx, data 0x%lx%s%s\n",
805                        (long) sim_events_time (sd),
806                        (long) event_to_remove,
807                        (long) dead->time_of_event,
808                        (long) dead->handler,
809                        (long) dead->data,
810                        (dead->trace != NULL) ? ", " : "",
811                        (dead->trace != NULL) ? dead->trace : ""));
812               sim_events_free (sd, dead);
813               update_time_from_event (sd);
814               SIM_ASSERT ((events->time_from_event >= 0) == (events->queue != NULL));
815               return;
816             }
817         }
818     }
819   ETRACE ((_ETRACE,
820            "event/watch descheduled at %ld - tag 0x%lx - not found\n",
821            (long) sim_events_time (sd),
822            (long) event_to_remove));
823 }
824 #endif
825
826
827 STATIC_INLINE_SIM_EVENTS\
828 (int)
829 sim_watch_valid (SIM_DESC sd,
830                  sim_event *to_do)
831 {
832   switch (to_do->watching)
833     {
834
835 #define WATCH_CORE(N,OP,EXT) \
836       int ok; \
837       unsigned_##N word = 0; \
838       int nr_read = sim_core_read_buffer (sd, NULL, to_do->core_map, &word, \
839                                           to_do->core_addr, sizeof (word)); \
840       OP (word); \
841       ok = (nr_read == sizeof (unsigned_##N) \
842             && (to_do->is_within \
843                 == (word >= to_do->lb##EXT \
844                     && word <= to_do->ub##EXT)));
845
846     case watch_core_targ_1:
847       {
848         WATCH_CORE (1, T2H,);
849         return ok;
850       }
851     case watch_core_targ_2:
852       {
853         WATCH_CORE (2, T2H,);
854         return ok;
855       }
856     case watch_core_targ_4:
857       {
858         WATCH_CORE (4, T2H,);
859         return ok;
860       }
861     case watch_core_targ_8:
862       {
863         WATCH_CORE (8, T2H,64);
864         return ok;
865       }
866
867     case watch_core_be_1:
868       {
869         WATCH_CORE (1, BE2H,);
870         return ok;
871       }
872     case watch_core_be_2:
873       {
874         WATCH_CORE (2, BE2H,);
875         return ok;
876       }
877     case watch_core_be_4:
878       {
879         WATCH_CORE (4, BE2H,);
880         return ok;
881       }
882     case watch_core_be_8:
883       {
884         WATCH_CORE (8, BE2H,64);
885         return ok;
886       }
887
888     case watch_core_le_1:
889       {
890         WATCH_CORE (1, LE2H,);
891         return ok;
892       }
893     case watch_core_le_2:
894       {
895         WATCH_CORE (2, LE2H,);
896         return ok;
897       }
898     case watch_core_le_4:
899       {
900         WATCH_CORE (4, LE2H,);
901         return ok;
902       }
903     case watch_core_le_8:
904       {
905         WATCH_CORE (8, LE2H,64);
906         return ok;
907       }
908 #undef WATCH_CORE
909
910 #define WATCH_SIM(N,OP,EXT) \
911       int ok; \
912       unsigned_##N word = *(unsigned_##N*)to_do->host_addr; \
913       OP (word); \
914       ok = (to_do->is_within \
915             == (word >= to_do->lb##EXT \
916                 && word <= to_do->ub##EXT));
917
918     case watch_sim_host_1:
919       {
920         WATCH_SIM (1, word = ,);
921         return ok;
922       }
923     case watch_sim_host_2:
924       {
925         WATCH_SIM (2, word = ,);
926         return ok;
927       }
928     case watch_sim_host_4:
929       {
930         WATCH_SIM (4, word = ,);
931         return ok;
932       }
933     case watch_sim_host_8:
934       {
935         WATCH_SIM (8, word = ,64);
936         return ok;
937       }
938
939     case watch_sim_be_1:
940       {
941         WATCH_SIM (1, BE2H,);
942         return ok;
943       }
944     case watch_sim_be_2:
945       {
946         WATCH_SIM (2, BE2H,);
947         return ok;
948       }
949     case watch_sim_be_4:
950       {
951         WATCH_SIM (4, BE2H,);
952         return ok;
953       }
954     case watch_sim_be_8:
955       {
956         WATCH_SIM (8, BE2H,64);
957         return ok;
958       }
959
960     case watch_sim_le_1:
961       {
962         WATCH_SIM (1, LE2H,);
963         return ok;
964       }
965     case watch_sim_le_2:
966       {
967         WATCH_SIM (1, LE2H,);
968         return ok;
969       }
970     case watch_sim_le_4:
971       {
972         WATCH_SIM (1, LE2H,);
973         return ok;
974       }
975     case watch_sim_le_8:
976       {
977         WATCH_SIM (1, LE2H,64);
978         return ok;
979       }
980 #undef WATCH_SIM
981
982     case watch_clock: /* wallclock */
983       {
984         unsigned long elapsed_time = sim_events_elapsed_time (sd);
985         return (elapsed_time >= to_do->wallclock);
986       }
987
988     default:
989       sim_io_error (sd, "sim_watch_valid - bad switch");
990       break;
991
992     }
993   return 1;
994 }
995
996
997 INLINE_SIM_EVENTS\
998 (int)
999 sim_events_tick (SIM_DESC sd)
1000 {
1001   sim_events *events = STATE_EVENTS (sd);
1002
1003   /* this should only be called after the previous ticks have been
1004      fully processed */
1005
1006   /* Advance the time but *only* if there is nothing to process */
1007   if (events->work_pending
1008       || events->time_from_event == 0)
1009     {
1010       events->nr_ticks_to_process += 1;
1011       return 1;
1012     }
1013   else
1014     {
1015       events->time_from_event -= 1;
1016       return 0;
1017     }
1018 }
1019
1020
1021 INLINE_SIM_EVENTS\
1022 (int)
1023 sim_events_tickn (SIM_DESC sd,
1024                   int n)
1025 {
1026   sim_events *events = STATE_EVENTS (sd);
1027   SIM_ASSERT (n > 0);
1028
1029   /* this should only be called after the previous ticks have been
1030      fully processed */
1031
1032   /* Advance the time but *only* if there is nothing to process */
1033   if (events->work_pending || events->time_from_event < n)
1034     {
1035       events->nr_ticks_to_process += n;
1036       return 1;
1037     }
1038   else
1039     {
1040       events->time_from_event -= n;
1041       return 0;
1042     }
1043 }
1044
1045
1046 INLINE_SIM_EVENTS\
1047 (void)
1048 sim_events_slip (SIM_DESC sd,
1049                  int slip)
1050 {
1051   sim_events *events = STATE_EVENTS (sd);
1052   SIM_ASSERT (slip > 0);
1053
1054   /* Flag a ready event with work_pending instead of number of ticks
1055      to process so that the time continues to be correct */
1056   if (events->time_from_event < slip)
1057     {
1058       events->work_pending = 1;
1059     }
1060   events->time_from_event -= slip;
1061 }
1062
1063
1064 INLINE_SIM_EVENTS\
1065 (void)
1066 sim_events_preprocess (SIM_DESC sd,
1067                        int events_were_last,
1068                        int events_were_next)
1069 {
1070   sim_events *events = STATE_EVENTS(sd);
1071   if (events_were_last)
1072     {
1073       /* Halted part way through event processing */
1074       ASSERT (events->nr_ticks_to_process != 0);
1075       /* The external world can't tell if the event that stopped the
1076          simulator was the last event to process. */
1077       ASSERT (events_were_next);
1078       sim_events_process (sd);
1079     }
1080   else if (events_were_next)
1081     {
1082       /* Halted by the last processor */
1083       if (sim_events_tick (sd))
1084         sim_events_process (sd);
1085     }
1086 }
1087
1088
1089 INLINE_SIM_EVENTS\
1090 (void)
1091 sim_events_process (SIM_DESC sd)
1092 {
1093   sim_events *events = STATE_EVENTS(sd);
1094   signed64 event_time = sim_events_time(sd);
1095
1096   /* Clear work_pending before checking nr_held.  Clearing
1097      work_pending after nr_held (with out a lock could loose an
1098      event). */
1099   events->work_pending = 0;
1100
1101   /* move any events that were asynchronously queued by any signal
1102      handlers onto the real event queue.  */
1103   if (events->nr_held > 0)
1104     {
1105       int i;
1106       
1107 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
1108       /*-LOCK-*/
1109       sigset_t old_mask;
1110       sigset_t new_mask;
1111       sigfillset(&new_mask);
1112       sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
1113 #endif
1114
1115       for (i = 0; i < events->nr_held; i++)
1116         {
1117           sim_event *entry = &events->held [i];
1118           sim_events_schedule (sd,
1119                                entry->time_of_event,
1120                                entry->handler,
1121                                entry->data);
1122         }
1123       events->nr_held = 0;
1124       
1125 #if defined(HAVE_SIGPROCMASK) && defined(SIG_SETMASK)
1126       /*-UNLOCK-*/
1127       sigprocmask(SIG_SETMASK, &old_mask, NULL);
1128 #endif
1129       
1130     }
1131   
1132   /* Process any watchpoints. Be careful to allow a watchpoint to
1133      appear/disappear under our feet.
1134      To ensure that watchpoints are processed only once per cycle,
1135      they are moved onto a watched queue, this returned to the
1136      watchpoint queue when all queue processing has been
1137      completed. */
1138   while (events->watchpoints != NULL)
1139     {
1140       sim_event *to_do = events->watchpoints;
1141       events->watchpoints = to_do->next;
1142       if (sim_watch_valid (sd, to_do))
1143         {
1144           sim_event_handler *handler = to_do->handler;
1145           void *data = to_do->data;
1146           ETRACE((_ETRACE,
1147                   "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx%s%s\n",
1148                   (long) event_time,
1149                   (long) to_do,
1150                   (long) handler,
1151                   (long) data,
1152                   (to_do->trace != NULL) ? ", " : "",
1153                   (to_do->trace != NULL) ? to_do->trace : ""));
1154           sim_events_free (sd, to_do);
1155           handler (sd, data);
1156         }
1157       else
1158         {
1159           to_do->next = events->watchedpoints;
1160           events->watchedpoints = to_do;
1161         }
1162     }
1163   
1164   /* consume all events for this or earlier times.  Be careful to
1165      allow an event to appear/disappear under our feet */
1166   while (events->queue->time_of_event <
1167          (event_time + events->nr_ticks_to_process))
1168     {
1169       sim_event *to_do = events->queue;
1170       sim_event_handler *handler = to_do->handler;
1171       void *data = to_do->data;
1172       events->queue = to_do->next;
1173       update_time_from_event (sd);
1174       ETRACE((_ETRACE,
1175               "event issued at %ld - tag 0x%lx - handler 0x%lx, data 0x%lx%s%s\n",
1176               (long) event_time,
1177               (long) to_do,
1178               (long) handler,
1179               (long) data,
1180               (to_do->trace != NULL) ? ", " : "",
1181               (to_do->trace != NULL) ? to_do->trace : ""));
1182       sim_events_free (sd, to_do);
1183       handler (sd, data);
1184     }
1185   
1186   /* put things back where they belong ready for the next iteration */
1187   events->watchpoints = events->watchedpoints;
1188   events->watchedpoints = NULL;
1189   if (events->watchpoints != NULL)
1190     events->work_pending = 1;
1191   
1192   /* advance the time */
1193   SIM_ASSERT (events->time_from_event >= events->nr_ticks_to_process);
1194   SIM_ASSERT (events->queue != NULL); /* always poll event */
1195   events->time_from_event -= events->nr_ticks_to_process;
1196
1197   /* this round of processing complete */
1198   events->nr_ticks_to_process = 0;
1199 }
1200
1201 #endif