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