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