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