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