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