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