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 **
next_event_queue(SIM_DESC sd,sim_event ** queue)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)
sim_events_poll(SIM_DESC sd,void * data)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
sim_events_install(SIM_DESC sd)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
sim_events_resume(SIM_DESC sd)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
sim_events_suspend(SIM_DESC sd)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
sim_events_uninstall(SIM_DESC sd)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 *
sim_events_zalloc(SIM_DESC sd)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)
sim_events_free(SIM_DESC sd,sim_event * dead)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
sim_events_init(SIM_DESC sd)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)
sim_events_time(SIM_DESC sd)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)
sim_events_elapsed_time(SIM_DESC sd)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)
sim_events_remain_time(SIM_DESC sd,sim_event * event)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)
update_time_from_event(SIM_DESC sd)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
insert_sim_event(SIM_DESC sd,sim_event * new_event,int64_t delta)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 *
sim_events_schedule(SIM_DESC sd,int64_t delta_time,sim_event_handler * handler,void * data)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 *
sim_events_schedule_tracef(SIM_DESC sd,int64_t delta_time,sim_event_handler * handler,void * data,const char * fmt,...)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 *
sim_events_schedule_vtracef(SIM_DESC sd,int64_t delta_time,sim_event_handler * handler,void * data,const char * fmt,va_list ap)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
sim_events_schedule_after_signal(SIM_DESC sd,int64_t delta_time,sim_event_handler * handler,void * data)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 *
sim_events_watch_clock(SIM_DESC sd,unsigned delta_ms_time,sim_event_handler * handler,void * data)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 *
sim_events_watch_pc(SIM_DESC sd,int is_within,uint64_t lb,uint64_t ub,sim_event_handler * handler,void * data)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 *
sim_events_watch_sim(SIM_DESC sd,void * host_addr,int nr_bytes,enum bfd_endian byte_order,int is_within,uint64_t lb,uint64_t ub,sim_event_handler * handler,void * data)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 *
sim_events_watch_core(SIM_DESC sd,address_word core_addr,unsigned core_map,int nr_bytes,enum bfd_endian byte_order,int is_within,uint64_t lb,uint64_t ub,sim_event_handler * handler,void * data)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
sim_events_deschedule(SIM_DESC sd,sim_event * event_to_remove)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)
sim_watch_valid(SIM_DESC sd,sim_event * to_do)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)
sim_events_tick(SIM_DESC sd)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)
sim_events_tickn(SIM_DESC sd,int n)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)
sim_events_slip(SIM_DESC sd,int slip)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)
sim_events_preprocess(SIM_DESC sd,int events_were_last,int events_were_next)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)
sim_events_process(SIM_DESC sd)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