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