1#include <signal.h>
2
3#include "sim-main.h"
4#include "sim-options.h"
5#include "sim-hw.h"
6
7#include "sysdep.h"
8#include "bfd.h"
9#include "sim-assert.h"
10
11
12#ifdef HAVE_STDLIB_H
13#include <stdlib.h>
14#endif
15
16#ifdef HAVE_STRING_H
17#include <string.h>
18#else
19#ifdef HAVE_STRINGS_H
20#include <strings.h>
21#endif
22#endif
23
24#include "bfd.h"
25
26#ifndef INLINE
27#ifdef __GNUC__
28#define INLINE inline
29#else
30#define INLINE
31#endif
32#endif
33
34
35host_callback *mn10300_callback;
36int mn10300_debug;
37struct _state State;
38
39
40/* simulation target board.  NULL=default configuration */
41static char* board = NULL;
42
43static DECLARE_OPTION_HANDLER (mn10300_option_handler);
44
45enum {
46  OPTION_BOARD = OPTION_START,
47};
48
49static SIM_RC
50mn10300_option_handler (SIM_DESC sd,
51			sim_cpu *cpu,
52			int opt,
53			char *arg,
54			int is_command)
55{
56  int cpu_nr;
57  switch (opt)
58    {
59    case OPTION_BOARD:
60      {
61	if (arg)
62	  {
63	    board = zalloc(strlen(arg) + 1);
64	    strcpy(board, arg);
65	  }
66	return SIM_RC_OK;
67      }
68    }
69
70  return SIM_RC_OK;
71}
72
73static const OPTION mn10300_options[] =
74{
75#define BOARD_AM32 "stdeval1"
76  { {"board", required_argument, NULL, OPTION_BOARD},
77     '\0', "none" /* rely on compile-time string concatenation for other options */
78           "|" BOARD_AM32
79    , "Customize simulation for a particular board.", mn10300_option_handler },
80
81  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
82};
83
84/* For compatibility */
85SIM_DESC simulator;
86
87/* These default values correspond to expected usage for the chip.  */
88
89SIM_DESC
90sim_open (SIM_OPEN_KIND kind,
91	  host_callback *cb,
92	  struct bfd *abfd,
93	  char **argv)
94{
95  SIM_DESC sd = sim_state_alloc (kind, cb);
96  mn10300_callback = cb;
97
98  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
99
100  /* for compatibility */
101  simulator = sd;
102
103  /* FIXME: should be better way of setting up interrupts.  For
104     moment, only support watchpoints causing a breakpoint (gdb
105     halt). */
106  STATE_WATCHPOINTS (sd)->pc = &(PC);
107  STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
108  STATE_WATCHPOINTS (sd)->interrupt_handler = NULL;
109  STATE_WATCHPOINTS (sd)->interrupt_names = NULL;
110
111  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
112    return 0;
113  sim_add_option_table (sd, NULL, mn10300_options);
114
115  /* Allocate core managed memory */
116  sim_do_command (sd, "memory region 0,0x100000");
117  sim_do_command (sd, "memory region 0x40000000,0x200000");
118
119  /* getopt will print the error message so we just have to exit if this fails.
120     FIXME: Hmmm...  in the case of gdb we need getopt to call
121     print_filtered.  */
122  if (sim_parse_args (sd, argv) != SIM_RC_OK)
123    {
124      /* Uninstall the modules to avoid memory leaks,
125	 file descriptor leaks, etc.  */
126      sim_module_uninstall (sd);
127      return 0;
128    }
129
130  if ( NULL != board
131       && (strcmp(board, BOARD_AM32) == 0 ) )
132    {
133      /* environment */
134      STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
135
136      sim_do_command (sd, "memory region 0x44000000,0x40000");
137      sim_do_command (sd, "memory region 0x48000000,0x400000");
138
139      /* device support for mn1030002 */
140      /* interrupt controller */
141
142      sim_hw_parse (sd, "/mn103int@0x34000100/reg 0x34000100 0x7C 0x34000200 0x8 0x34000280 0x8");
143
144      /* DEBUG: NMI input's */
145      sim_hw_parse (sd, "/glue@0x30000000/reg 0x30000000 12");
146      sim_hw_parse (sd, "/glue@0x30000000 > int0 nmirq /mn103int");
147      sim_hw_parse (sd, "/glue@0x30000000 > int1 watchdog /mn103int");
148      sim_hw_parse (sd, "/glue@0x30000000 > int2 syserr /mn103int");
149
150      /* DEBUG: ACK input */
151      sim_hw_parse (sd, "/glue@0x30002000/reg 0x30002000 4");
152      sim_hw_parse (sd, "/glue@0x30002000 > int ack /mn103int");
153
154      /* DEBUG: LEVEL output */
155      sim_hw_parse (sd, "/glue@0x30004000/reg 0x30004000 8");
156      sim_hw_parse (sd, "/mn103int > nmi int0 /glue@0x30004000");
157      sim_hw_parse (sd, "/mn103int > level int1 /glue@0x30004000");
158
159      /* DEBUG: A bunch of interrupt inputs */
160      sim_hw_parse (sd, "/glue@0x30006000/reg 0x30006000 32");
161      sim_hw_parse (sd, "/glue@0x30006000 > int0 irq-0 /mn103int");
162      sim_hw_parse (sd, "/glue@0x30006000 > int1 irq-1 /mn103int");
163      sim_hw_parse (sd, "/glue@0x30006000 > int2 irq-2 /mn103int");
164      sim_hw_parse (sd, "/glue@0x30006000 > int3 irq-3 /mn103int");
165      sim_hw_parse (sd, "/glue@0x30006000 > int4 irq-4 /mn103int");
166      sim_hw_parse (sd, "/glue@0x30006000 > int5 irq-5 /mn103int");
167      sim_hw_parse (sd, "/glue@0x30006000 > int6 irq-6 /mn103int");
168      sim_hw_parse (sd, "/glue@0x30006000 > int7 irq-7 /mn103int");
169
170      /* processor interrupt device */
171
172      /* the device */
173      sim_hw_parse (sd, "/mn103cpu@0x20000000");
174      sim_hw_parse (sd, "/mn103cpu@0x20000000/reg 0x20000000 0x42");
175
176      /* DEBUG: ACK output wired upto a glue device */
177      sim_hw_parse (sd, "/glue@0x20002000");
178      sim_hw_parse (sd, "/glue@0x20002000/reg 0x20002000 4");
179      sim_hw_parse (sd, "/mn103cpu > ack int0 /glue@0x20002000");
180
181      /* DEBUG: RESET/NMI/LEVEL wired up to a glue device */
182      sim_hw_parse (sd, "/glue@0x20004000");
183      sim_hw_parse (sd, "/glue@0x20004000/reg 0x20004000 12");
184      sim_hw_parse (sd, "/glue@0x20004000 > int0 reset /mn103cpu");
185      sim_hw_parse (sd, "/glue@0x20004000 > int1 nmi /mn103cpu");
186      sim_hw_parse (sd, "/glue@0x20004000 > int2 level /mn103cpu");
187
188      /* REAL: The processor wired up to the real interrupt controller */
189      sim_hw_parse (sd, "/mn103cpu > ack ack /mn103int");
190      sim_hw_parse (sd, "/mn103int > level level /mn103cpu");
191      sim_hw_parse (sd, "/mn103int > nmi nmi /mn103cpu");
192
193
194      /* PAL */
195
196      /* the device */
197      sim_hw_parse (sd, "/pal@0x31000000");
198      sim_hw_parse (sd, "/pal@0x31000000/reg 0x31000000 64");
199      sim_hw_parse (sd, "/pal@0x31000000/poll? true");
200
201      /* DEBUG: PAL wired up to a glue device */
202      sim_hw_parse (sd, "/glue@0x31002000");
203      sim_hw_parse (sd, "/glue@0x31002000/reg 0x31002000 16");
204      sim_hw_parse (sd, "/pal@0x31000000 > countdown int0 /glue@0x31002000");
205      sim_hw_parse (sd, "/pal@0x31000000 > timer int1 /glue@0x31002000");
206      sim_hw_parse (sd, "/pal@0x31000000 > int int2 /glue@0x31002000");
207      sim_hw_parse (sd, "/glue@0x31002000 > int0 int3 /glue@0x31002000");
208      sim_hw_parse (sd, "/glue@0x31002000 > int1 int3 /glue@0x31002000");
209      sim_hw_parse (sd, "/glue@0x31002000 > int2 int3 /glue@0x31002000");
210
211      /* REAL: The PAL wired up to the real interrupt controller */
212      sim_hw_parse (sd, "/pal@0x31000000 > countdown irq-0 /mn103int");
213      sim_hw_parse (sd, "/pal@0x31000000 > timer irq-1 /mn103int");
214      sim_hw_parse (sd, "/pal@0x31000000 > int irq-2 /mn103int");
215
216      /* 8 and 16 bit timers */
217      sim_hw_parse (sd, "/mn103tim@0x34001000/reg 0x34001000 36 0x34001080 100 0x34004000 16");
218
219      /* Hook timer interrupts up to interrupt controller */
220      sim_hw_parse (sd, "/mn103tim > timer-0-underflow timer-0-underflow /mn103int");
221      sim_hw_parse (sd, "/mn103tim > timer-1-underflow timer-1-underflow /mn103int");
222      sim_hw_parse (sd, "/mn103tim > timer-2-underflow timer-2-underflow /mn103int");
223      sim_hw_parse (sd, "/mn103tim > timer-3-underflow timer-3-underflow /mn103int");
224      sim_hw_parse (sd, "/mn103tim > timer-4-underflow timer-4-underflow /mn103int");
225      sim_hw_parse (sd, "/mn103tim > timer-5-underflow timer-5-underflow /mn103int");
226      sim_hw_parse (sd, "/mn103tim > timer-6-underflow timer-6-underflow /mn103int");
227      sim_hw_parse (sd, "/mn103tim > timer-6-compare-a timer-6-compare-a /mn103int");
228      sim_hw_parse (sd, "/mn103tim > timer-6-compare-b timer-6-compare-b /mn103int");
229
230
231      /* Serial devices 0,1,2 */
232      sim_hw_parse (sd, "/mn103ser@0x34000800/reg 0x34000800 48");
233      sim_hw_parse (sd, "/mn103ser@0x34000800/poll? true");
234
235      /* Hook serial interrupts up to interrupt controller */
236      sim_hw_parse (sd, "/mn103ser > serial-0-receive serial-0-receive /mn103int");
237      sim_hw_parse (sd, "/mn103ser > serial-0-transmit serial-0-transmit /mn103int");
238      sim_hw_parse (sd, "/mn103ser > serial-1-receive serial-1-receive /mn103int");
239      sim_hw_parse (sd, "/mn103ser > serial-1-transmit serial-1-transmit /mn103int");
240      sim_hw_parse (sd, "/mn103ser > serial-2-receive serial-2-receive /mn103int");
241      sim_hw_parse (sd, "/mn103ser > serial-2-transmit serial-2-transmit /mn103int");
242
243      sim_hw_parse (sd, "/mn103iop@0x36008000/reg 0x36008000 8 0x36008020 8 0x36008040 0xc 0x36008060 8 0x36008080 8");
244
245      /* Memory control registers */
246      sim_do_command (sd, "memory region 0x32000020,0x30");
247      /* Cache control register */
248      sim_do_command (sd, "memory region 0x20000070,0x4");
249      /* Cache purge regions */
250      sim_do_command (sd, "memory region 0x28400000,0x800");
251      sim_do_command (sd, "memory region 0x28401000,0x800");
252      /* DMA registers */
253      sim_do_command (sd, "memory region 0x32000100,0xF");
254      sim_do_command (sd, "memory region 0x32000200,0xF");
255      sim_do_command (sd, "memory region 0x32000400,0xF");
256      sim_do_command (sd, "memory region 0x32000800,0xF");
257    }
258  else
259    {
260      if (board != NULL)
261        {
262	  sim_io_eprintf (sd, "Error: Board `%s' unknown.\n", board);
263          return 0;
264	}
265    }
266
267
268
269  /* check for/establish the a reference program image */
270  if (sim_analyze_program (sd,
271			   (STATE_PROG_ARGV (sd) != NULL
272			    ? *STATE_PROG_ARGV (sd)
273			    : NULL),
274			   abfd) != SIM_RC_OK)
275    {
276      sim_module_uninstall (sd);
277      return 0;
278    }
279
280  /* establish any remaining configuration options */
281  if (sim_config (sd) != SIM_RC_OK)
282    {
283      sim_module_uninstall (sd);
284      return 0;
285    }
286
287  if (sim_post_argv_init (sd) != SIM_RC_OK)
288    {
289      /* Uninstall the modules to avoid memory leaks,
290	 file descriptor leaks, etc.  */
291      sim_module_uninstall (sd);
292      return 0;
293    }
294
295
296  /* set machine specific configuration */
297/*   STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT */
298/* 			     | PSW_CY | PSW_OV | PSW_S | PSW_Z); */
299
300  return sd;
301}
302
303
304void
305sim_close (SIM_DESC sd, int quitting)
306{
307  sim_module_uninstall (sd);
308}
309
310
311SIM_RC
312sim_create_inferior (SIM_DESC sd,
313		     struct bfd *prog_bfd,
314		     char **argv,
315		     char **env)
316{
317  memset (&State, 0, sizeof (State));
318  if (prog_bfd != NULL) {
319    PC = bfd_get_start_address (prog_bfd);
320  } else {
321    PC = 0;
322  }
323  CIA_SET (STATE_CPU (sd, 0), (unsigned64) PC);
324
325  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_am33_2)
326    PSW |= PSW_FE;
327
328  return SIM_RC_OK;
329}
330
331void
332sim_do_command (SIM_DESC sd, char *cmd)
333{
334  char *mm_cmd = "memory-map";
335  char *int_cmd = "interrupt";
336
337  if (sim_args_command (sd, cmd) != SIM_RC_OK)
338    {
339      if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0))
340	sim_io_eprintf (sd, "`memory-map' command replaced by `sim memory'\n");
341      else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0)
342	sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n");
343      else
344	sim_io_eprintf (sd, "Unknown command `%s'\n", cmd);
345    }
346}
347
348/* FIXME These would more efficient to use than load_mem/store_mem,
349   but need to be changed to use the memory map.  */
350
351uint8
352get_byte (uint8 *x)
353{
354  return *x;
355}
356
357uint16
358get_half (uint8 *x)
359{
360  uint8 *a = x;
361  return (a[1] << 8) + (a[0]);
362}
363
364uint32
365get_word (uint8 *x)
366{
367  uint8 *a = x;
368  return (a[3]<<24) + (a[2]<<16) + (a[1]<<8) + (a[0]);
369}
370
371void
372put_byte (uint8 *addr, uint8 data)
373{
374  uint8 *a = addr;
375  a[0] = data;
376}
377
378void
379put_half (uint8 *addr, uint16 data)
380{
381  uint8 *a = addr;
382  a[0] = data & 0xff;
383  a[1] = (data >> 8) & 0xff;
384}
385
386void
387put_word (uint8 *addr, uint32 data)
388{
389  uint8 *a = addr;
390  a[0] = data & 0xff;
391  a[1] = (data >> 8) & 0xff;
392  a[2] = (data >> 16) & 0xff;
393  a[3] = (data >> 24) & 0xff;
394}
395
396int
397sim_fetch_register (SIM_DESC sd,
398		    int rn,
399		    unsigned char *memory,
400		    int length)
401{
402  put_word (memory, State.regs[rn]);
403  return -1;
404}
405
406int
407sim_store_register (SIM_DESC sd,
408		    int rn,
409		    unsigned char *memory,
410		    int length)
411{
412  State.regs[rn] = get_word (memory);
413  return -1;
414}
415
416
417void
418mn10300_core_signal (SIM_DESC sd,
419		     sim_cpu *cpu,
420		     sim_cia cia,
421		     unsigned map,
422		     int nr_bytes,
423		     address_word addr,
424		     transfer_type transfer,
425		     sim_core_signals sig)
426{
427  const char *copy = (transfer == read_transfer ? "read" : "write");
428  address_word ip = CIA_ADDR (cia);
429
430  switch (sig)
431    {
432    case sim_core_unmapped_signal:
433      sim_io_eprintf (sd, "mn10300-core: %d byte %s to unmapped address 0x%lx at 0x%lx\n",
434                      nr_bytes, copy,
435                      (unsigned long) addr, (unsigned long) ip);
436      program_interrupt(sd, cpu, cia, SIM_SIGSEGV);
437      break;
438
439    case sim_core_unaligned_signal:
440      sim_io_eprintf (sd, "mn10300-core: %d byte %s to unaligned address 0x%lx at 0x%lx\n",
441                      nr_bytes, copy,
442                      (unsigned long) addr, (unsigned long) ip);
443      program_interrupt(sd, cpu, cia, SIM_SIGBUS);
444      break;
445
446    default:
447      sim_engine_abort (sd, cpu, cia,
448                        "mn10300_core_signal - internal error - bad switch");
449    }
450}
451
452
453void
454program_interrupt (SIM_DESC sd,
455		   sim_cpu *cpu,
456		   sim_cia cia,
457		   SIM_SIGNAL sig)
458{
459  int status;
460  struct hw *device;
461  static int in_interrupt = 0;
462
463#ifdef SIM_CPU_EXCEPTION_TRIGGER
464  SIM_CPU_EXCEPTION_TRIGGER(sd,cpu,cia);
465#endif
466
467  /* avoid infinite recursion */
468  if (in_interrupt)
469    {
470      (*mn10300_callback->printf_filtered) (mn10300_callback,
471					    "ERROR: recursion in program_interrupt during software exception dispatch.");
472    }
473  else
474    {
475      in_interrupt = 1;
476      /* copy NMI handler code from dv-mn103cpu.c */
477      store_word (SP - 4, CIA_GET (cpu));
478      store_half (SP - 8, PSW);
479
480      /* Set the SYSEF flag in NMICR by backdoor method.  See
481	 dv-mn103int.c:write_icr().  This is necessary because
482         software exceptions are not modelled by actually talking to
483         the interrupt controller, so it cannot set its own SYSEF
484         flag. */
485     if ((NULL != board) && (strcmp(board, BOARD_AM32) == 0))
486       store_byte (0x34000103, 0x04);
487    }
488
489  PSW &= ~PSW_IE;
490  SP = SP - 8;
491  CIA_SET (cpu, 0x40000008);
492
493  in_interrupt = 0;
494  sim_engine_halt(sd, cpu, NULL, cia, sim_stopped, sig);
495}
496
497
498void
499mn10300_cpu_exception_trigger(SIM_DESC sd, sim_cpu* cpu, address_word cia)
500{
501  ASSERT(cpu != NULL);
502
503  if(State.exc_suspended > 0)
504    sim_io_eprintf(sd, "Warning, nested exception triggered (%d)\n", State.exc_suspended);
505
506  CIA_SET (cpu, cia);
507  memcpy(State.exc_trigger_regs, State.regs, sizeof(State.exc_trigger_regs));
508  State.exc_suspended = 0;
509}
510
511void
512mn10300_cpu_exception_suspend(SIM_DESC sd, sim_cpu* cpu, int exception)
513{
514  ASSERT(cpu != NULL);
515
516  if(State.exc_suspended > 0)
517    sim_io_eprintf(sd, "Warning, nested exception signal (%d then %d)\n",
518		   State.exc_suspended, exception);
519
520  memcpy(State.exc_suspend_regs, State.regs, sizeof(State.exc_suspend_regs));
521  memcpy(State.regs, State.exc_trigger_regs, sizeof(State.regs));
522  CIA_SET (cpu, PC); /* copy PC back from new State.regs */
523  State.exc_suspended = exception;
524}
525
526void
527mn10300_cpu_exception_resume(SIM_DESC sd, sim_cpu* cpu, int exception)
528{
529  ASSERT(cpu != NULL);
530
531  if(exception == 0 && State.exc_suspended > 0)
532    {
533      if(State.exc_suspended != SIGTRAP) /* warn not for breakpoints */
534         sim_io_eprintf(sd, "Warning, resuming but ignoring pending exception signal (%d)\n",
535  		       State.exc_suspended);
536    }
537  else if(exception != 0 && State.exc_suspended > 0)
538    {
539      if(exception != State.exc_suspended)
540	sim_io_eprintf(sd, "Warning, resuming with mismatched exception signal (%d vs %d)\n",
541		       State.exc_suspended, exception);
542
543      memcpy(State.regs, State.exc_suspend_regs, sizeof(State.regs));
544      CIA_SET (cpu, PC); /* copy PC back from new State.regs */
545    }
546  else if(exception != 0 && State.exc_suspended == 0)
547    {
548      sim_io_eprintf(sd, "Warning, ignoring spontanous exception signal (%d)\n", exception);
549    }
550  State.exc_suspended = 0;
551}
552
553/* This is called when an FP instruction is issued when the FP unit is
554   disabled, i.e., the FE bit of PSW is zero.  It raises interrupt
555   code 0x1c0.  */
556void
557fpu_disabled_exception (SIM_DESC sd, sim_cpu *cpu, sim_cia cia)
558{
559  sim_io_eprintf(sd, "FPU disabled exception\n");
560  program_interrupt (sd, cpu, cia, SIM_SIGFPE);
561}
562
563/* This is called when the FP unit is enabled but one of the
564   unimplemented insns is issued.  It raises interrupt code 0x1c8.  */
565void
566fpu_unimp_exception (SIM_DESC sd, sim_cpu *cpu, sim_cia cia)
567{
568  sim_io_eprintf(sd, "Unimplemented FPU instruction exception\n");
569  program_interrupt (sd, cpu, cia, SIM_SIGFPE);
570}
571
572/* This is called at the end of any FP insns that may have triggered
573   FP exceptions.  If no exception is enabled, it returns immediately.
574   Otherwise, it raises an exception code 0x1d0.  */
575void
576fpu_check_signal_exception (SIM_DESC sd, sim_cpu *cpu, sim_cia cia)
577{
578  if ((FPCR & EC_MASK) == 0)
579    return;
580
581  sim_io_eprintf(sd, "FPU %s%s%s%s%s exception\n",
582		 (FPCR & EC_V) ? "V" : "",
583		 (FPCR & EC_Z) ? "Z" : "",
584		 (FPCR & EC_O) ? "O" : "",
585		 (FPCR & EC_U) ? "U" : "",
586		 (FPCR & EC_I) ? "I" : "");
587  program_interrupt (sd, cpu, cia, SIM_SIGFPE);
588}
589
590/* Convert a 32-bit single-precision FP value in the target platform
591   format to a sim_fpu value.  */
592static void
593reg2val_32 (const void *reg, sim_fpu *val)
594{
595  FS2FPU (*(reg_t *)reg, *val);
596}
597
598/* Round the given sim_fpu value to single precision, following the
599   target platform rounding and denormalization conventions.  On
600   AM33/2.0, round_near is the only rounding mode.  */
601static int
602round_32 (sim_fpu *val)
603{
604  return sim_fpu_round_32 (val, sim_fpu_round_near, sim_fpu_denorm_zero);
605}
606
607/* Convert a sim_fpu value to the 32-bit single-precision target
608   representation.  */
609static void
610val2reg_32 (const sim_fpu *val, void *reg)
611{
612  FPU2FS (*val, *(reg_t *)reg);
613}
614
615/* Define the 32-bit single-precision conversion and rounding uniform
616   interface.  */
617const struct fp_prec_t
618fp_single_prec = {
619  reg2val_32, round_32, val2reg_32
620};
621
622/* Convert a 64-bit double-precision FP value in the target platform
623   format to a sim_fpu value.  */
624static void
625reg2val_64 (const void *reg, sim_fpu *val)
626{
627  FD2FPU (*(dword *)reg, *val);
628}
629
630/* Round the given sim_fpu value to double precision, following the
631   target platform rounding and denormalization conventions.  On
632   AM33/2.0, round_near is the only rounding mode.  */
633int
634round_64 (sim_fpu *val)
635{
636  return sim_fpu_round_64 (val, sim_fpu_round_near, sim_fpu_denorm_zero);
637}
638
639/* Convert a sim_fpu value to the 64-bit double-precision target
640   representation.  */
641static void
642val2reg_64 (const sim_fpu *val, void *reg)
643{
644  FPU2FD (*val, *(dword *)reg);
645}
646
647/* Define the 64-bit single-precision conversion and rounding uniform
648   interface.  */
649const struct fp_prec_t
650fp_double_prec = {
651  reg2val_64, round_64, val2reg_64
652};
653
654/* Define shortcuts to the uniform interface operations.  */
655#define REG2VAL(reg,val) (*ops->reg2val) (reg,val)
656#define ROUND(val) (*ops->round) (val)
657#define VAL2REG(val,reg) (*ops->val2reg) (val,reg)
658
659/* Check whether overflow, underflow or inexact exceptions should be
660   raised.  */
661int
662fpu_status_ok (sim_fpu_status stat)
663{
664  if ((stat & sim_fpu_status_overflow)
665      && (FPCR & EE_O))
666    FPCR |= EC_O;
667  else if ((stat & (sim_fpu_status_underflow | sim_fpu_status_denorm))
668	   && (FPCR & EE_U))
669    FPCR |= EC_U;
670  else if ((stat & (sim_fpu_status_inexact | sim_fpu_status_rounded))
671	   && (FPCR & EE_I))
672    FPCR |= EC_I;
673  else if (stat & ~ (sim_fpu_status_overflow
674		     | sim_fpu_status_underflow
675		     | sim_fpu_status_denorm
676		     | sim_fpu_status_inexact
677		     | sim_fpu_status_rounded))
678    abort ();
679  else
680    return 1;
681  return 0;
682}
683
684/* Implement a 32/64 bit reciprocal square root, signaling FP
685   exceptions when appropriate.  */
686void
687fpu_rsqrt (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
688	   const void *reg_in, void *reg_out, const struct fp_prec_t *ops)
689{
690  sim_fpu in, med, out;
691
692  REG2VAL (reg_in, &in);
693  ROUND (&in);
694  FPCR &= ~ EC_MASK;
695  switch (sim_fpu_is (&in))
696    {
697    case SIM_FPU_IS_SNAN:
698    case SIM_FPU_IS_NNUMBER:
699    case SIM_FPU_IS_NINF:
700      if (FPCR & EE_V)
701	FPCR |= EC_V;
702      else
703	VAL2REG (&sim_fpu_qnan, reg_out);
704      break;
705
706    case SIM_FPU_IS_QNAN:
707      VAL2REG (&sim_fpu_qnan, reg_out);
708      break;
709
710    case SIM_FPU_IS_PINF:
711      VAL2REG (&sim_fpu_zero, reg_out);
712      break;
713
714    case SIM_FPU_IS_PNUMBER:
715      {
716	/* Since we don't have a function to compute rsqrt directly,
717	   use sqrt and inv.  */
718	sim_fpu_status stat = 0;
719	stat |= sim_fpu_sqrt (&med, &in);
720	stat |= sim_fpu_inv (&out, &med);
721	stat |= ROUND (&out);
722	if (fpu_status_ok (stat))
723	  VAL2REG (&out, reg_out);
724      }
725      break;
726
727    case SIM_FPU_IS_NZERO:
728    case SIM_FPU_IS_PZERO:
729      if (FPCR & EE_Z)
730	FPCR |= EC_Z;
731      else
732	{
733	  /* Generate an INF with the same sign.  */
734	  sim_fpu_inv (&out, &in);
735	  VAL2REG (&out, reg_out);
736	}
737      break;
738
739    default:
740      abort ();
741    }
742
743  fpu_check_signal_exception (sd, cpu, cia);
744}
745
746static inline reg_t
747cmp2fcc (int res)
748{
749  switch (res)
750    {
751    case SIM_FPU_IS_SNAN:
752    case SIM_FPU_IS_QNAN:
753      return FCC_U;
754
755    case SIM_FPU_IS_NINF:
756    case SIM_FPU_IS_NNUMBER:
757    case SIM_FPU_IS_NDENORM:
758      return FCC_L;
759
760    case SIM_FPU_IS_PINF:
761    case SIM_FPU_IS_PNUMBER:
762    case SIM_FPU_IS_PDENORM:
763      return FCC_G;
764
765    case SIM_FPU_IS_NZERO:
766    case SIM_FPU_IS_PZERO:
767      return FCC_E;
768
769    default:
770      abort ();
771    }
772}
773
774/* Implement a 32/64 bit FP compare, setting the FPCR status and/or
775   exception bits as specified.  */
776void
777fpu_cmp (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
778	 const void *reg_in1, const void *reg_in2,
779	 const struct fp_prec_t *ops)
780{
781  sim_fpu m, n;
782
783  REG2VAL (reg_in1, &m);
784  REG2VAL (reg_in2, &n);
785  FPCR &= ~ EC_MASK;
786  FPCR &= ~ FCC_MASK;
787  ROUND (&m);
788  ROUND (&n);
789  if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n))
790    {
791      if (FPCR & EE_V)
792	FPCR |= EC_V;
793      else
794	FPCR |= FCC_U;
795    }
796  else
797    FPCR |= cmp2fcc (sim_fpu_cmp (&m, &n));
798
799  fpu_check_signal_exception (sd, cpu, cia);
800}
801
802/* Implement a 32/64 bit FP add, setting FP exception bits when
803   appropriate.  */
804void
805fpu_add (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
806	 const void *reg_in1, const void *reg_in2,
807	 void *reg_out, const struct fp_prec_t *ops)
808{
809  sim_fpu m, n, r;
810
811  REG2VAL (reg_in1, &m);
812  REG2VAL (reg_in2, &n);
813  ROUND (&m);
814  ROUND (&n);
815  FPCR &= ~ EC_MASK;
816  if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
817      || (sim_fpu_is (&m) == SIM_FPU_IS_PINF
818	  && sim_fpu_is (&n) == SIM_FPU_IS_NINF)
819      || (sim_fpu_is (&m) == SIM_FPU_IS_NINF
820	  && sim_fpu_is (&n) == SIM_FPU_IS_PINF))
821    {
822      if (FPCR & EE_V)
823	FPCR |= EC_V;
824      else
825	VAL2REG (&sim_fpu_qnan, reg_out);
826    }
827  else
828    {
829      sim_fpu_status stat = sim_fpu_add (&r, &m, &n);
830      stat |= ROUND (&r);
831      if (fpu_status_ok (stat))
832	VAL2REG (&r, reg_out);
833    }
834
835  fpu_check_signal_exception (sd, cpu, cia);
836}
837
838/* Implement a 32/64 bit FP sub, setting FP exception bits when
839   appropriate.  */
840void
841fpu_sub (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
842	 const void *reg_in1, const void *reg_in2,
843	 void *reg_out, const struct fp_prec_t *ops)
844{
845  sim_fpu m, n, r;
846
847  REG2VAL (reg_in1, &m);
848  REG2VAL (reg_in2, &n);
849  ROUND (&m);
850  ROUND (&n);
851  FPCR &= ~ EC_MASK;
852  if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
853      || (sim_fpu_is (&m) == SIM_FPU_IS_PINF
854	  && sim_fpu_is (&n) == SIM_FPU_IS_PINF)
855      || (sim_fpu_is (&m) == SIM_FPU_IS_NINF
856	  && sim_fpu_is (&n) == SIM_FPU_IS_NINF))
857    {
858      if (FPCR & EE_V)
859	FPCR |= EC_V;
860      else
861	VAL2REG (&sim_fpu_qnan, reg_out);
862    }
863  else
864    {
865      sim_fpu_status stat = sim_fpu_sub (&r, &m, &n);
866      stat |= ROUND (&r);
867      if (fpu_status_ok (stat))
868	VAL2REG (&r, reg_out);
869    }
870
871  fpu_check_signal_exception (sd, cpu, cia);
872}
873
874/* Implement a 32/64 bit FP mul, setting FP exception bits when
875   appropriate.  */
876void
877fpu_mul (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
878	 const void *reg_in1, const void *reg_in2,
879	 void *reg_out, const struct fp_prec_t *ops)
880{
881  sim_fpu m, n, r;
882
883  REG2VAL (reg_in1, &m);
884  REG2VAL (reg_in2, &n);
885  ROUND (&m);
886  ROUND (&n);
887  FPCR &= ~ EC_MASK;
888  if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
889      || (sim_fpu_is_infinity (&m) && sim_fpu_is_zero (&n))
890      || (sim_fpu_is_zero (&m) && sim_fpu_is_infinity (&n)))
891    {
892      if (FPCR & EE_V)
893	FPCR |= EC_V;
894      else
895	VAL2REG (&sim_fpu_qnan, reg_out);
896    }
897  else
898    {
899      sim_fpu_status stat = sim_fpu_mul (&r, &m, &n);
900      stat |= ROUND (&r);
901      if (fpu_status_ok (stat))
902	VAL2REG (&r, reg_out);
903    }
904
905  fpu_check_signal_exception (sd, cpu, cia);
906}
907
908/* Implement a 32/64 bit FP div, setting FP exception bits when
909   appropriate.  */
910void
911fpu_div (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
912	 const void *reg_in1, const void *reg_in2,
913	 void *reg_out, const struct fp_prec_t *ops)
914{
915  sim_fpu m, n, r;
916
917  REG2VAL (reg_in1, &m);
918  REG2VAL (reg_in2, &n);
919  ROUND (&m);
920  ROUND (&n);
921  FPCR &= ~ EC_MASK;
922  if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
923      || (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n))
924      || (sim_fpu_is_zero (&m) && sim_fpu_is_zero (&n)))
925    {
926      if (FPCR & EE_V)
927	FPCR |= EC_V;
928      else
929	VAL2REG (&sim_fpu_qnan, reg_out);
930    }
931  else if (sim_fpu_is_number (&m) && sim_fpu_is_zero (&n)
932	   && (FPCR & EE_Z))
933    FPCR |= EC_Z;
934  else
935    {
936      sim_fpu_status stat = sim_fpu_div (&r, &m, &n);
937      stat |= ROUND (&r);
938      if (fpu_status_ok (stat))
939	VAL2REG (&r, reg_out);
940    }
941
942  fpu_check_signal_exception (sd, cpu, cia);
943}
944
945/* Implement a 32/64 bit FP madd, setting FP exception bits when
946   appropriate.  */
947void
948fpu_fmadd (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
949	   const void *reg_in1, const void *reg_in2, const void *reg_in3,
950	   void *reg_out, const struct fp_prec_t *ops)
951{
952  sim_fpu m1, m2, m, n, r;
953
954  REG2VAL (reg_in1, &m1);
955  REG2VAL (reg_in2, &m2);
956  REG2VAL (reg_in3, &n);
957  ROUND (&m1);
958  ROUND (&m2);
959  ROUND (&n);
960  FPCR &= ~ EC_MASK;
961  if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
962      || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
963      || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
964    {
965    invalid_operands:
966      if (FPCR & EE_V)
967	FPCR |= EC_V;
968      else
969	VAL2REG (&sim_fpu_qnan, reg_out);
970    }
971  else
972    {
973      sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
974
975      if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
976	  && sim_fpu_sign (&m) != sim_fpu_sign (&n))
977	goto invalid_operands;
978
979      stat |= sim_fpu_add (&r, &m, &n);
980      stat |= ROUND (&r);
981      if (fpu_status_ok (stat))
982	VAL2REG (&r, reg_out);
983    }
984
985  fpu_check_signal_exception (sd, cpu, cia);
986}
987
988/* Implement a 32/64 bit FP msub, setting FP exception bits when
989   appropriate.  */
990void
991fpu_fmsub (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
992	   const void *reg_in1, const void *reg_in2, const void *reg_in3,
993	   void *reg_out, const struct fp_prec_t *ops)
994{
995  sim_fpu m1, m2, m, n, r;
996
997  REG2VAL (reg_in1, &m1);
998  REG2VAL (reg_in2, &m2);
999  REG2VAL (reg_in3, &n);
1000  ROUND (&m1);
1001  ROUND (&m2);
1002  ROUND (&n);
1003  FPCR &= ~ EC_MASK;
1004  if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
1005      || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
1006      || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
1007    {
1008    invalid_operands:
1009      if (FPCR & EE_V)
1010	FPCR |= EC_V;
1011      else
1012	VAL2REG (&sim_fpu_qnan, reg_out);
1013    }
1014  else
1015    {
1016      sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
1017
1018      if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
1019	  && sim_fpu_sign (&m) == sim_fpu_sign (&n))
1020	goto invalid_operands;
1021
1022      stat |= sim_fpu_sub (&r, &m, &n);
1023      stat |= ROUND (&r);
1024      if (fpu_status_ok (stat))
1025	VAL2REG (&r, reg_out);
1026    }
1027
1028  fpu_check_signal_exception (sd, cpu, cia);
1029}
1030
1031/* Implement a 32/64 bit FP nmadd, setting FP exception bits when
1032   appropriate.  */
1033void
1034fpu_fnmadd (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
1035	    const void *reg_in1, const void *reg_in2, const void *reg_in3,
1036	    void *reg_out, const struct fp_prec_t *ops)
1037{
1038  sim_fpu m1, m2, m, mm, n, r;
1039
1040  REG2VAL (reg_in1, &m1);
1041  REG2VAL (reg_in2, &m2);
1042  REG2VAL (reg_in3, &n);
1043  ROUND (&m1);
1044  ROUND (&m2);
1045  ROUND (&n);
1046  FPCR &= ~ EC_MASK;
1047  if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
1048      || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
1049      || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
1050    {
1051    invalid_operands:
1052      if (FPCR & EE_V)
1053	FPCR |= EC_V;
1054      else
1055	VAL2REG (&sim_fpu_qnan, reg_out);
1056    }
1057  else
1058    {
1059      sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
1060
1061      if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
1062	  && sim_fpu_sign (&m) == sim_fpu_sign (&n))
1063	goto invalid_operands;
1064
1065      stat |= sim_fpu_neg (&mm, &m);
1066      stat |= sim_fpu_add (&r, &mm, &n);
1067      stat |= ROUND (&r);
1068      if (fpu_status_ok (stat))
1069	VAL2REG (&r, reg_out);
1070    }
1071
1072  fpu_check_signal_exception (sd, cpu, cia);
1073}
1074
1075/* Implement a 32/64 bit FP nmsub, setting FP exception bits when
1076   appropriate.  */
1077void
1078fpu_fnmsub (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
1079	    const void *reg_in1, const void *reg_in2, const void *reg_in3,
1080	    void *reg_out, const struct fp_prec_t *ops)
1081{
1082  sim_fpu m1, m2, m, mm, n, r;
1083
1084  REG2VAL (reg_in1, &m1);
1085  REG2VAL (reg_in2, &m2);
1086  REG2VAL (reg_in3, &n);
1087  ROUND (&m1);
1088  ROUND (&m2);
1089  ROUND (&n);
1090  FPCR &= ~ EC_MASK;
1091  if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
1092      || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
1093      || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
1094    {
1095    invalid_operands:
1096      if (FPCR & EE_V)
1097	FPCR |= EC_V;
1098      else
1099	VAL2REG (&sim_fpu_qnan, reg_out);
1100    }
1101  else
1102    {
1103      sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
1104
1105      if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
1106	  && sim_fpu_sign (&m) != sim_fpu_sign (&n))
1107	goto invalid_operands;
1108
1109      stat |= sim_fpu_neg (&mm, &m);
1110      stat |= sim_fpu_sub (&r, &mm, &n);
1111      stat |= ROUND (&r);
1112      if (fpu_status_ok (stat))
1113	VAL2REG (&r, reg_out);
1114    }
1115
1116  fpu_check_signal_exception (sd, cpu, cia);
1117}
1118