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