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