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