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