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