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