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