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