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