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