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