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