sim: sim-close: unify sim_close logic
[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 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 SIM_RC
321 sim_create_inferior (SIM_DESC sd,
322                      struct bfd *prog_bfd,
323                      char **argv,
324                      char **env)
325 {
326   memset (&State, 0, sizeof (State));
327   if (prog_bfd != NULL) {
328     PC = bfd_get_start_address (prog_bfd);
329   } else {
330     PC = 0;
331   }
332   CPU_PC_SET (STATE_CPU (sd, 0), (unsigned64) PC);
333
334   if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_am33_2)
335     PSW |= PSW_FE;
336
337   return SIM_RC_OK;
338 }
339
340 /* FIXME These would more efficient to use than load_mem/store_mem,
341    but need to be changed to use the memory map.  */
342
343 int
344 sim_fetch_register (SIM_DESC sd,
345                     int rn,
346                     unsigned char *memory,
347                     int length)
348 {
349   reg_t reg = State.regs[rn];
350   uint8 *a = memory;
351   a[0] = reg;
352   a[1] = reg >> 8;
353   a[2] = reg >> 16;
354   a[3] = reg >> 24;
355   return length;
356 }
357  
358 int
359 sim_store_register (SIM_DESC sd,
360                     int rn,
361                     unsigned char *memory,
362                     int length)
363 {
364   uint8 *a = memory;
365   State.regs[rn] = (a[3] << 24) + (a[2] << 16) + (a[1] << 8) + a[0];
366   return length;
367 }
368
369 void
370 mn10300_core_signal (SIM_DESC sd,
371                      sim_cpu *cpu,
372                      sim_cia cia,
373                      unsigned map,
374                      int nr_bytes,
375                      address_word addr,
376                      transfer_type transfer,
377                      sim_core_signals sig)
378 {
379   const char *copy = (transfer == read_transfer ? "read" : "write");
380   address_word ip = CIA_ADDR (cia);
381
382   switch (sig)
383     {
384     case sim_core_unmapped_signal:
385       sim_io_eprintf (sd, "mn10300-core: %d byte %s to unmapped address 0x%lx at 0x%lx\n",
386                       nr_bytes, copy, 
387                       (unsigned long) addr, (unsigned long) ip);
388       program_interrupt(sd, cpu, cia, SIM_SIGSEGV);
389       break;
390
391     case sim_core_unaligned_signal:
392       sim_io_eprintf (sd, "mn10300-core: %d byte %s to unaligned address 0x%lx at 0x%lx\n",
393                       nr_bytes, copy, 
394                       (unsigned long) addr, (unsigned long) ip);
395       program_interrupt(sd, cpu, cia, SIM_SIGBUS);
396       break;
397
398     default:
399       sim_engine_abort (sd, cpu, cia,
400                         "mn10300_core_signal - internal error - bad switch");
401     }
402 }
403
404
405 void
406 program_interrupt (SIM_DESC sd,
407                    sim_cpu *cpu,
408                    sim_cia cia,
409                    SIM_SIGNAL sig)
410 {
411   int status;
412   struct hw *device;
413   static int in_interrupt = 0;
414
415 #ifdef SIM_CPU_EXCEPTION_TRIGGER
416   SIM_CPU_EXCEPTION_TRIGGER(sd,cpu,cia);
417 #endif
418
419   /* avoid infinite recursion */
420   if (in_interrupt)
421     {
422       (*mn10300_callback->printf_filtered) (mn10300_callback, 
423                                             "ERROR: recursion in program_interrupt during software exception dispatch.");
424     }
425   else
426     {
427       in_interrupt = 1;
428       /* copy NMI handler code from dv-mn103cpu.c */
429       store_word (SP - 4, CPU_PC_GET (cpu));
430       store_half (SP - 8, PSW);
431
432       /* Set the SYSEF flag in NMICR by backdoor method.  See
433          dv-mn103int.c:write_icr().  This is necessary because
434          software exceptions are not modelled by actually talking to
435          the interrupt controller, so it cannot set its own SYSEF
436          flag. */
437      if ((NULL != board) && (strcmp(board, BOARD_AM32) == 0))
438        store_byte (0x34000103, 0x04);
439     }
440
441   PSW &= ~PSW_IE;
442   SP = SP - 8;
443   CPU_PC_SET (cpu, 0x40000008);
444
445   in_interrupt = 0;
446   sim_engine_halt(sd, cpu, NULL, cia, sim_stopped, sig);
447 }
448
449
450 void
451 mn10300_cpu_exception_trigger(SIM_DESC sd, sim_cpu* cpu, address_word cia)
452 {
453   ASSERT(cpu != NULL);
454
455   if(State.exc_suspended > 0)
456     sim_io_eprintf(sd, "Warning, nested exception triggered (%d)\n", State.exc_suspended); 
457
458   CPU_PC_SET (cpu, cia);
459   memcpy(State.exc_trigger_regs, State.regs, sizeof(State.exc_trigger_regs));
460   State.exc_suspended = 0;
461 }
462
463 void
464 mn10300_cpu_exception_suspend(SIM_DESC sd, sim_cpu* cpu, int exception)
465 {
466   ASSERT(cpu != NULL);
467
468   if(State.exc_suspended > 0)
469     sim_io_eprintf(sd, "Warning, nested exception signal (%d then %d)\n", 
470                    State.exc_suspended, exception); 
471
472   memcpy(State.exc_suspend_regs, State.regs, sizeof(State.exc_suspend_regs));
473   memcpy(State.regs, State.exc_trigger_regs, sizeof(State.regs));
474   CPU_PC_SET (cpu, PC); /* copy PC back from new State.regs */
475   State.exc_suspended = exception;
476 }
477
478 void
479 mn10300_cpu_exception_resume(SIM_DESC sd, sim_cpu* cpu, int exception)
480 {
481   ASSERT(cpu != NULL);
482
483   if(exception == 0 && State.exc_suspended > 0)
484     {
485       if(State.exc_suspended != SIGTRAP) /* warn not for breakpoints */
486          sim_io_eprintf(sd, "Warning, resuming but ignoring pending exception signal (%d)\n",
487                        State.exc_suspended); 
488     }
489   else if(exception != 0 && State.exc_suspended > 0)
490     {
491       if(exception != State.exc_suspended) 
492         sim_io_eprintf(sd, "Warning, resuming with mismatched exception signal (%d vs %d)\n",
493                        State.exc_suspended, exception); 
494       
495       memcpy(State.regs, State.exc_suspend_regs, sizeof(State.regs)); 
496       CPU_PC_SET (cpu, PC); /* copy PC back from new State.regs */
497     }
498   else if(exception != 0 && State.exc_suspended == 0)
499     {
500       sim_io_eprintf(sd, "Warning, ignoring spontanous exception signal (%d)\n", exception); 
501     }
502   State.exc_suspended = 0; 
503 }
504
505 /* This is called when an FP instruction is issued when the FP unit is
506    disabled, i.e., the FE bit of PSW is zero.  It raises interrupt
507    code 0x1c0.  */
508 void
509 fpu_disabled_exception (SIM_DESC sd, sim_cpu *cpu, sim_cia cia)
510 {
511   sim_io_eprintf(sd, "FPU disabled exception\n");
512   program_interrupt (sd, cpu, cia, SIM_SIGFPE);
513 }
514
515 /* This is called when the FP unit is enabled but one of the
516    unimplemented insns is issued.  It raises interrupt code 0x1c8.  */
517 void
518 fpu_unimp_exception (SIM_DESC sd, sim_cpu *cpu, sim_cia cia)
519 {
520   sim_io_eprintf(sd, "Unimplemented FPU instruction exception\n");
521   program_interrupt (sd, cpu, cia, SIM_SIGFPE);
522 }
523
524 /* This is called at the end of any FP insns that may have triggered
525    FP exceptions.  If no exception is enabled, it returns immediately.
526    Otherwise, it raises an exception code 0x1d0.  */
527 void
528 fpu_check_signal_exception (SIM_DESC sd, sim_cpu *cpu, sim_cia cia)
529 {
530   if ((FPCR & EC_MASK) == 0)
531     return;
532
533   sim_io_eprintf(sd, "FPU %s%s%s%s%s exception\n",
534                  (FPCR & EC_V) ? "V" : "",
535                  (FPCR & EC_Z) ? "Z" : "",
536                  (FPCR & EC_O) ? "O" : "",
537                  (FPCR & EC_U) ? "U" : "",
538                  (FPCR & EC_I) ? "I" : "");
539   program_interrupt (sd, cpu, cia, SIM_SIGFPE);
540 }
541
542 /* Convert a 32-bit single-precision FP value in the target platform
543    format to a sim_fpu value.  */
544 static void
545 reg2val_32 (const void *reg, sim_fpu *val)
546 {
547   FS2FPU (*(reg_t *)reg, *val);
548 }
549
550 /* Round the given sim_fpu value to single precision, following the
551    target platform rounding and denormalization conventions.  On
552    AM33/2.0, round_near is the only rounding mode.  */
553 static int
554 round_32 (sim_fpu *val)
555 {
556   return sim_fpu_round_32 (val, sim_fpu_round_near, sim_fpu_denorm_zero);
557 }
558
559 /* Convert a sim_fpu value to the 32-bit single-precision target
560    representation.  */
561 static void
562 val2reg_32 (const sim_fpu *val, void *reg)
563 {
564   FPU2FS (*val, *(reg_t *)reg);
565 }
566
567 /* Define the 32-bit single-precision conversion and rounding uniform
568    interface.  */
569 const struct fp_prec_t
570 fp_single_prec = {
571   reg2val_32, round_32, val2reg_32
572 };
573
574 /* Convert a 64-bit double-precision FP value in the target platform
575    format to a sim_fpu value.  */
576 static void
577 reg2val_64 (const void *reg, sim_fpu *val)
578 {
579   FD2FPU (*(dword *)reg, *val);
580 }
581
582 /* Round the given sim_fpu value to double precision, following the
583    target platform rounding and denormalization conventions.  On
584    AM33/2.0, round_near is the only rounding mode.  */
585 static int
586 round_64 (sim_fpu *val)
587 {
588   return sim_fpu_round_64 (val, sim_fpu_round_near, sim_fpu_denorm_zero);
589 }
590
591 /* Convert a sim_fpu value to the 64-bit double-precision target
592    representation.  */
593 static void
594 val2reg_64 (const sim_fpu *val, void *reg)
595 {
596   FPU2FD (*val, *(dword *)reg);
597 }
598
599 /* Define the 64-bit single-precision conversion and rounding uniform
600    interface.  */
601 const struct fp_prec_t
602 fp_double_prec = {
603   reg2val_64, round_64, val2reg_64
604 };
605
606 /* Define shortcuts to the uniform interface operations.  */
607 #define REG2VAL(reg,val) (*ops->reg2val) (reg,val)
608 #define ROUND(val) (*ops->round) (val)
609 #define VAL2REG(val,reg) (*ops->val2reg) (val,reg)
610
611 /* Check whether overflow, underflow or inexact exceptions should be
612    raised.  */
613 static int
614 fpu_status_ok (sim_fpu_status stat)
615 {
616   if ((stat & sim_fpu_status_overflow)
617       && (FPCR & EE_O))
618     FPCR |= EC_O;
619   else if ((stat & (sim_fpu_status_underflow | sim_fpu_status_denorm))
620            && (FPCR & EE_U))
621     FPCR |= EC_U;
622   else if ((stat & (sim_fpu_status_inexact | sim_fpu_status_rounded))
623            && (FPCR & EE_I))
624     FPCR |= EC_I;
625   else if (stat & ~ (sim_fpu_status_overflow
626                      | sim_fpu_status_underflow
627                      | sim_fpu_status_denorm
628                      | sim_fpu_status_inexact
629                      | sim_fpu_status_rounded))
630     abort ();
631   else
632     return 1;
633   return 0;
634 }
635
636 /* Implement a 32/64 bit reciprocal square root, signaling FP
637    exceptions when appropriate.  */
638 void
639 fpu_rsqrt (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
640            const void *reg_in, void *reg_out, const struct fp_prec_t *ops)
641 {
642   sim_fpu in, med, out;
643
644   REG2VAL (reg_in, &in);
645   ROUND (&in);
646   FPCR &= ~ EC_MASK;
647   switch (sim_fpu_is (&in))
648     {
649     case SIM_FPU_IS_SNAN:
650     case SIM_FPU_IS_NNUMBER:
651     case SIM_FPU_IS_NINF:
652       if (FPCR & EE_V)
653         FPCR |= EC_V;
654       else
655         VAL2REG (&sim_fpu_qnan, reg_out);
656       break;
657             
658     case SIM_FPU_IS_QNAN:
659       VAL2REG (&sim_fpu_qnan, reg_out);
660       break;
661
662     case SIM_FPU_IS_PINF:
663       VAL2REG (&sim_fpu_zero, reg_out);
664       break;
665
666     case SIM_FPU_IS_PNUMBER:
667       {
668         /* Since we don't have a function to compute rsqrt directly,
669            use sqrt and inv.  */
670         sim_fpu_status stat = 0;
671         stat |= sim_fpu_sqrt (&med, &in);
672         stat |= sim_fpu_inv (&out, &med);
673         stat |= ROUND (&out);
674         if (fpu_status_ok (stat))
675           VAL2REG (&out, reg_out);
676       }
677       break;
678
679     case SIM_FPU_IS_NZERO:
680     case SIM_FPU_IS_PZERO:
681       if (FPCR & EE_Z)
682         FPCR |= EC_Z;
683       else
684         {
685           /* Generate an INF with the same sign.  */
686           sim_fpu_inv (&out, &in);
687           VAL2REG (&out, reg_out);
688         }
689       break;
690
691     default:
692       abort ();
693     }
694
695   fpu_check_signal_exception (sd, cpu, cia);
696 }
697
698 static inline reg_t
699 cmp2fcc (int res)
700 {
701   switch (res)
702     {
703     case SIM_FPU_IS_SNAN:
704     case SIM_FPU_IS_QNAN:
705       return FCC_U;
706       
707     case SIM_FPU_IS_NINF:
708     case SIM_FPU_IS_NNUMBER:
709     case SIM_FPU_IS_NDENORM:
710       return FCC_L;
711       
712     case SIM_FPU_IS_PINF:
713     case SIM_FPU_IS_PNUMBER:
714     case SIM_FPU_IS_PDENORM:
715       return FCC_G;
716       
717     case SIM_FPU_IS_NZERO:
718     case SIM_FPU_IS_PZERO:
719       return FCC_E;
720       
721     default:
722       abort ();
723     }
724 }
725
726 /* Implement a 32/64 bit FP compare, setting the FPCR status and/or
727    exception bits as specified.  */
728 void
729 fpu_cmp (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
730          const void *reg_in1, const void *reg_in2,
731          const struct fp_prec_t *ops)
732 {
733   sim_fpu m, n;
734
735   REG2VAL (reg_in1, &m);
736   REG2VAL (reg_in2, &n);
737   FPCR &= ~ EC_MASK;
738   FPCR &= ~ FCC_MASK;
739   ROUND (&m);
740   ROUND (&n);
741   if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n))
742     {
743       if (FPCR & EE_V)
744         FPCR |= EC_V;
745       else
746         FPCR |= FCC_U;
747     }
748   else
749     FPCR |= cmp2fcc (sim_fpu_cmp (&m, &n));
750
751   fpu_check_signal_exception (sd, cpu, cia);
752 }
753
754 /* Implement a 32/64 bit FP add, setting FP exception bits when
755    appropriate.  */
756 void
757 fpu_add (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
758          const void *reg_in1, const void *reg_in2,
759          void *reg_out, const struct fp_prec_t *ops)
760 {
761   sim_fpu m, n, r;
762
763   REG2VAL (reg_in1, &m);
764   REG2VAL (reg_in2, &n);
765   ROUND (&m);
766   ROUND (&n);
767   FPCR &= ~ EC_MASK;
768   if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
769       || (sim_fpu_is (&m) == SIM_FPU_IS_PINF
770           && sim_fpu_is (&n) == SIM_FPU_IS_NINF)
771       || (sim_fpu_is (&m) == SIM_FPU_IS_NINF
772           && sim_fpu_is (&n) == SIM_FPU_IS_PINF))
773     {
774       if (FPCR & EE_V)
775         FPCR |= EC_V;
776       else
777         VAL2REG (&sim_fpu_qnan, reg_out);
778     }
779   else
780     {
781       sim_fpu_status stat = sim_fpu_add (&r, &m, &n);
782       stat |= ROUND (&r);
783       if (fpu_status_ok (stat))
784         VAL2REG (&r, reg_out);
785     }
786   
787   fpu_check_signal_exception (sd, cpu, cia);
788 }
789
790 /* Implement a 32/64 bit FP sub, setting FP exception bits when
791    appropriate.  */
792 void
793 fpu_sub (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
794          const void *reg_in1, const void *reg_in2,
795          void *reg_out, const struct fp_prec_t *ops)
796 {
797   sim_fpu m, n, r;
798
799   REG2VAL (reg_in1, &m);
800   REG2VAL (reg_in2, &n);
801   ROUND (&m);
802   ROUND (&n);
803   FPCR &= ~ EC_MASK;
804   if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
805       || (sim_fpu_is (&m) == SIM_FPU_IS_PINF
806           && sim_fpu_is (&n) == SIM_FPU_IS_PINF)
807       || (sim_fpu_is (&m) == SIM_FPU_IS_NINF
808           && sim_fpu_is (&n) == SIM_FPU_IS_NINF))
809     {
810       if (FPCR & EE_V)
811         FPCR |= EC_V;
812       else
813         VAL2REG (&sim_fpu_qnan, reg_out);
814     }
815   else
816     {
817       sim_fpu_status stat = sim_fpu_sub (&r, &m, &n);
818       stat |= ROUND (&r);
819       if (fpu_status_ok (stat))
820         VAL2REG (&r, reg_out);
821     }
822   
823   fpu_check_signal_exception (sd, cpu, cia);
824 }
825
826 /* Implement a 32/64 bit FP mul, setting FP exception bits when
827    appropriate.  */
828 void
829 fpu_mul (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
830          const void *reg_in1, const void *reg_in2,
831          void *reg_out, const struct fp_prec_t *ops)
832 {
833   sim_fpu m, n, r;
834
835   REG2VAL (reg_in1, &m);
836   REG2VAL (reg_in2, &n);
837   ROUND (&m);
838   ROUND (&n);
839   FPCR &= ~ EC_MASK;
840   if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
841       || (sim_fpu_is_infinity (&m) && sim_fpu_is_zero (&n))
842       || (sim_fpu_is_zero (&m) && sim_fpu_is_infinity (&n)))
843     {
844       if (FPCR & EE_V)
845         FPCR |= EC_V;
846       else
847         VAL2REG (&sim_fpu_qnan, reg_out);
848     }
849   else
850     {
851       sim_fpu_status stat = sim_fpu_mul (&r, &m, &n);
852       stat |= ROUND (&r);
853       if (fpu_status_ok (stat))
854         VAL2REG (&r, reg_out);
855     }
856   
857   fpu_check_signal_exception (sd, cpu, cia);
858 }
859
860 /* Implement a 32/64 bit FP div, setting FP exception bits when
861    appropriate.  */
862 void
863 fpu_div (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
864          const void *reg_in1, const void *reg_in2,
865          void *reg_out, const struct fp_prec_t *ops)
866 {
867   sim_fpu m, n, r;
868
869   REG2VAL (reg_in1, &m);
870   REG2VAL (reg_in2, &n);
871   ROUND (&m);
872   ROUND (&n);
873   FPCR &= ~ EC_MASK;
874   if (sim_fpu_is_snan (&m) || sim_fpu_is_snan (&n)
875       || (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n))
876       || (sim_fpu_is_zero (&m) && sim_fpu_is_zero (&n)))
877     {
878       if (FPCR & EE_V)
879         FPCR |= EC_V;
880       else
881         VAL2REG (&sim_fpu_qnan, reg_out);
882     }
883   else if (sim_fpu_is_number (&m) && sim_fpu_is_zero (&n)
884            && (FPCR & EE_Z))
885     FPCR |= EC_Z;
886   else
887     {
888       sim_fpu_status stat = sim_fpu_div (&r, &m, &n);
889       stat |= ROUND (&r);
890       if (fpu_status_ok (stat))
891         VAL2REG (&r, reg_out);
892     }
893   
894   fpu_check_signal_exception (sd, cpu, cia);
895 }
896
897 /* Implement a 32/64 bit FP madd, setting FP exception bits when
898    appropriate.  */
899 void
900 fpu_fmadd (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
901            const void *reg_in1, const void *reg_in2, const void *reg_in3,
902            void *reg_out, const struct fp_prec_t *ops)
903 {
904   sim_fpu m1, m2, m, n, r;
905
906   REG2VAL (reg_in1, &m1);
907   REG2VAL (reg_in2, &m2);
908   REG2VAL (reg_in3, &n);
909   ROUND (&m1);
910   ROUND (&m2);
911   ROUND (&n);
912   FPCR &= ~ EC_MASK;
913   if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
914       || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
915       || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
916     {
917     invalid_operands:
918       if (FPCR & EE_V)
919         FPCR |= EC_V;
920       else
921         VAL2REG (&sim_fpu_qnan, reg_out);
922     }
923   else
924     {
925       sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
926
927       if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
928           && sim_fpu_sign (&m) != sim_fpu_sign (&n))
929         goto invalid_operands;
930
931       stat |= sim_fpu_add (&r, &m, &n);
932       stat |= ROUND (&r);
933       if (fpu_status_ok (stat))
934         VAL2REG (&r, reg_out);
935     }
936   
937   fpu_check_signal_exception (sd, cpu, cia);
938 }
939
940 /* Implement a 32/64 bit FP msub, setting FP exception bits when
941    appropriate.  */
942 void
943 fpu_fmsub (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
944            const void *reg_in1, const void *reg_in2, const void *reg_in3,
945            void *reg_out, const struct fp_prec_t *ops)
946 {
947   sim_fpu m1, m2, m, n, r;
948
949   REG2VAL (reg_in1, &m1);
950   REG2VAL (reg_in2, &m2);
951   REG2VAL (reg_in3, &n);
952   ROUND (&m1);
953   ROUND (&m2);
954   ROUND (&n);
955   FPCR &= ~ EC_MASK;
956   if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
957       || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
958       || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
959     {
960     invalid_operands:
961       if (FPCR & EE_V)
962         FPCR |= EC_V;
963       else
964         VAL2REG (&sim_fpu_qnan, reg_out);
965     }
966   else
967     {
968       sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
969
970       if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
971           && sim_fpu_sign (&m) == sim_fpu_sign (&n))
972         goto invalid_operands;
973
974       stat |= sim_fpu_sub (&r, &m, &n);
975       stat |= ROUND (&r);
976       if (fpu_status_ok (stat))
977         VAL2REG (&r, reg_out);
978     }
979   
980   fpu_check_signal_exception (sd, cpu, cia);
981 }
982
983 /* Implement a 32/64 bit FP nmadd, setting FP exception bits when
984    appropriate.  */
985 void
986 fpu_fnmadd (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
987             const void *reg_in1, const void *reg_in2, const void *reg_in3,
988             void *reg_out, const struct fp_prec_t *ops)
989 {
990   sim_fpu m1, m2, m, mm, n, r;
991
992   REG2VAL (reg_in1, &m1);
993   REG2VAL (reg_in2, &m2);
994   REG2VAL (reg_in3, &n);
995   ROUND (&m1);
996   ROUND (&m2);
997   ROUND (&n);
998   FPCR &= ~ EC_MASK;
999   if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
1000       || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
1001       || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
1002     {
1003     invalid_operands:
1004       if (FPCR & EE_V)
1005         FPCR |= EC_V;
1006       else
1007         VAL2REG (&sim_fpu_qnan, reg_out);
1008     }
1009   else
1010     {
1011       sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
1012
1013       if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
1014           && sim_fpu_sign (&m) == sim_fpu_sign (&n))
1015         goto invalid_operands;
1016
1017       stat |= sim_fpu_neg (&mm, &m);
1018       stat |= sim_fpu_add (&r, &mm, &n);
1019       stat |= ROUND (&r);
1020       if (fpu_status_ok (stat))
1021         VAL2REG (&r, reg_out);
1022     }
1023   
1024   fpu_check_signal_exception (sd, cpu, cia);
1025 }
1026
1027 /* Implement a 32/64 bit FP nmsub, setting FP exception bits when
1028    appropriate.  */
1029 void
1030 fpu_fnmsub (SIM_DESC sd, sim_cpu *cpu, sim_cia cia,
1031             const void *reg_in1, const void *reg_in2, const void *reg_in3,
1032             void *reg_out, const struct fp_prec_t *ops)
1033 {
1034   sim_fpu m1, m2, m, mm, n, r;
1035
1036   REG2VAL (reg_in1, &m1);
1037   REG2VAL (reg_in2, &m2);
1038   REG2VAL (reg_in3, &n);
1039   ROUND (&m1);
1040   ROUND (&m2);
1041   ROUND (&n);
1042   FPCR &= ~ EC_MASK;
1043   if (sim_fpu_is_snan (&m1) || sim_fpu_is_snan (&m2) || sim_fpu_is_snan (&n)
1044       || (sim_fpu_is_infinity (&m1) && sim_fpu_is_zero (&m2))
1045       || (sim_fpu_is_zero (&m1) && sim_fpu_is_infinity (&m2)))
1046     {
1047     invalid_operands:
1048       if (FPCR & EE_V)
1049         FPCR |= EC_V;
1050       else
1051         VAL2REG (&sim_fpu_qnan, reg_out);
1052     }
1053   else
1054     {
1055       sim_fpu_status stat = sim_fpu_mul (&m, &m1, &m2);
1056
1057       if (sim_fpu_is_infinity (&m) && sim_fpu_is_infinity (&n)
1058           && sim_fpu_sign (&m) != sim_fpu_sign (&n))
1059         goto invalid_operands;
1060
1061       stat |= sim_fpu_neg (&mm, &m);
1062       stat |= sim_fpu_sub (&r, &mm, &n);
1063       stat |= ROUND (&r);
1064       if (fpu_status_ok (stat))
1065         VAL2REG (&r, reg_out);
1066     }
1067   
1068   fpu_check_signal_exception (sd, cpu, cia);
1069 }