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