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