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