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