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