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