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