1#include <signal.h> 2 3#include "sim-main.h" 4#include "sim-options.h" 5#include "sim-hw.h" 6 7#include "sysdep.h" 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 26#ifndef INLINE 27#ifdef __GNUC__ 28#define INLINE inline 29#else 30#define INLINE 31#endif 32#endif 33 34 35host_callback *mn10300_callback; 36int mn10300_debug; 37struct _state State; 38 39 40/* simulation target board. NULL=default configuration */ 41static char* board = NULL; 42 43static DECLARE_OPTION_HANDLER (mn10300_option_handler); 44 45enum { 46 OPTION_BOARD = OPTION_START, 47}; 48 49static SIM_RC 50mn10300_option_handler (SIM_DESC sd, 51 sim_cpu *cpu, 52 int opt, 53 char *arg, 54 int is_command) 55{ 56 int cpu_nr; 57 switch (opt) 58 { 59 case OPTION_BOARD: 60 { 61 if (arg) 62 { 63 board = zalloc(strlen(arg) + 1); 64 strcpy(board, arg); 65 } 66 return SIM_RC_OK; 67 } 68 } 69 70 return SIM_RC_OK; 71} 72 73static const OPTION mn10300_options[] = 74{ 75#define BOARD_AM32 "stdeval1" 76 { {"board", required_argument, NULL, OPTION_BOARD}, 77 '\0', "none" /* rely on compile-time string concatenation for other options */ 78 "|" BOARD_AM32 79 , "Customize simulation for a particular board.", mn10300_option_handler }, 80 81 { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } 82}; 83 84/* For compatibility */ 85SIM_DESC simulator; 86 87/* These default values correspond to expected usage for the chip. */ 88 89SIM_DESC 90sim_open (SIM_OPEN_KIND kind, 91 host_callback *cb, 92 struct bfd *abfd, 93 char **argv) 94{ 95 SIM_DESC sd = sim_state_alloc (kind, cb); 96 mn10300_callback = cb; 97 98 SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 99 100 /* for compatibility */ 101 simulator = sd; 102 103 /* FIXME: should be better way of setting up interrupts. For 104 moment, only support watchpoints causing a breakpoint (gdb 105 halt). */ 106 STATE_WATCHPOINTS (sd)->pc = &(PC); 107 STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC); 108 STATE_WATCHPOINTS (sd)->interrupt_handler = NULL; 109 STATE_WATCHPOINTS (sd)->interrupt_names = NULL; 110 111 if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK) 112 return 0; 113 sim_add_option_table (sd, NULL, mn10300_options); 114 115 /* Allocate core managed memory */ 116 sim_do_command (sd, "memory region 0,0x100000"); 117 sim_do_command (sd, "memory region 0x40000000,0x200000"); 118 119 /* getopt will print the error message so we just have to exit if this fails. 120 FIXME: Hmmm... in the case of gdb we need getopt to call 121 print_filtered. */ 122 if (sim_parse_args (sd, argv) != SIM_RC_OK) 123 { 124 /* Uninstall the modules to avoid memory leaks, 125 file descriptor leaks, etc. */ 126 sim_module_uninstall (sd); 127 return 0; 128 } 129 130 if ( NULL != board 131 && (strcmp(board, BOARD_AM32) == 0 ) ) 132 { 133 /* environment */ 134 STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT; 135 136 sim_do_command (sd, "memory region 0x44000000,0x40000"); 137 sim_do_command (sd, "memory region 0x48000000,0x400000"); 138 139 /* device support for mn1030002 */ 140 /* interrupt controller */ 141 142 sim_hw_parse (sd, "/mn103int@0x34000100/reg 0x34000100 0x7C 0x34000200 0x8 0x34000280 0x8"); 143 144 /* DEBUG: NMI input's */ 145 sim_hw_parse (sd, "/glue@0x30000000/reg 0x30000000 12"); 146 sim_hw_parse (sd, "/glue@0x30000000 > int0 nmirq /mn103int"); 147 sim_hw_parse (sd, "/glue@0x30000000 > int1 watchdog /mn103int"); 148 sim_hw_parse (sd, "/glue@0x30000000 > int2 syserr /mn103int"); 149 150 /* DEBUG: ACK input */ 151 sim_hw_parse (sd, "/glue@0x30002000/reg 0x30002000 4"); 152 sim_hw_parse (sd, "/glue@0x30002000 > int ack /mn103int"); 153 154 /* DEBUG: LEVEL output */ 155 sim_hw_parse (sd, "/glue@0x30004000/reg 0x30004000 8"); 156 sim_hw_parse (sd, "/mn103int > nmi int0 /glue@0x30004000"); 157 sim_hw_parse (sd, "/mn103int > level int1 /glue@0x30004000"); 158 159 /* DEBUG: A bunch of interrupt inputs */ 160 sim_hw_parse (sd, "/glue@0x30006000/reg 0x30006000 32"); 161 sim_hw_parse (sd, "/glue@0x30006000 > int0 irq-0 /mn103int"); 162 sim_hw_parse (sd, "/glue@0x30006000 > int1 irq-1 /mn103int"); 163 sim_hw_parse (sd, "/glue@0x30006000 > int2 irq-2 /mn103int"); 164 sim_hw_parse (sd, "/glue@0x30006000 > int3 irq-3 /mn103int"); 165 sim_hw_parse (sd, "/glue@0x30006000 > int4 irq-4 /mn103int"); 166 sim_hw_parse (sd, "/glue@0x30006000 > int5 irq-5 /mn103int"); 167 sim_hw_parse (sd, "/glue@0x30006000 > int6 irq-6 /mn103int"); 168 sim_hw_parse (sd, "/glue@0x30006000 > int7 irq-7 /mn103int"); 169 170 /* processor interrupt device */ 171 172 /* the device */ 173 sim_hw_parse (sd, "/mn103cpu@0x20000000"); 174 sim_hw_parse (sd, "/mn103cpu@0x20000000/reg 0x20000000 0x42"); 175 176 /* DEBUG: ACK output wired upto a glue device */ 177 sim_hw_parse (sd, "/glue@0x20002000"); 178 sim_hw_parse (sd, "/glue@0x20002000/reg 0x20002000 4"); 179 sim_hw_parse (sd, "/mn103cpu > ack int0 /glue@0x20002000"); 180 181 /* DEBUG: RESET/NMI/LEVEL wired up to a glue device */ 182 sim_hw_parse (sd, "/glue@0x20004000"); 183 sim_hw_parse (sd, "/glue@0x20004000/reg 0x20004000 12"); 184 sim_hw_parse (sd, "/glue@0x20004000 > int0 reset /mn103cpu"); 185 sim_hw_parse (sd, "/glue@0x20004000 > int1 nmi /mn103cpu"); 186 sim_hw_parse (sd, "/glue@0x20004000 > int2 level /mn103cpu"); 187 188 /* REAL: The processor wired up to the real interrupt controller */ 189 sim_hw_parse (sd, "/mn103cpu > ack ack /mn103int"); 190 sim_hw_parse (sd, "/mn103int > level level /mn103cpu"); 191 sim_hw_parse (sd, "/mn103int > nmi nmi /mn103cpu"); 192 193 194 /* PAL */ 195 196 /* the device */ 197 sim_hw_parse (sd, "/pal@0x31000000"); 198 sim_hw_parse (sd, "/pal@0x31000000/reg 0x31000000 64"); 199 sim_hw_parse (sd, "/pal@0x31000000/poll? true"); 200 201 /* DEBUG: PAL wired up to a glue device */ 202 sim_hw_parse (sd, "/glue@0x31002000"); 203 sim_hw_parse (sd, "/glue@0x31002000/reg 0x31002000 16"); 204 sim_hw_parse (sd, "/pal@0x31000000 > countdown int0 /glue@0x31002000"); 205 sim_hw_parse (sd, "/pal@0x31000000 > timer int1 /glue@0x31002000"); 206 sim_hw_parse (sd, "/pal@0x31000000 > int int2 /glue@0x31002000"); 207 sim_hw_parse (sd, "/glue@0x31002000 > int0 int3 /glue@0x31002000"); 208 sim_hw_parse (sd, "/glue@0x31002000 > int1 int3 /glue@0x31002000"); 209 sim_hw_parse (sd, "/glue@0x31002000 > int2 int3 /glue@0x31002000"); 210 211 /* REAL: The PAL wired up to the real interrupt controller */ 212 sim_hw_parse (sd, "/pal@0x31000000 > countdown irq-0 /mn103int"); 213 sim_hw_parse (sd, "/pal@0x31000000 > timer irq-1 /mn103int"); 214 sim_hw_parse (sd, "/pal@0x31000000 > int irq-2 /mn103int"); 215 216 /* 8 and 16 bit timers */ 217 sim_hw_parse (sd, "/mn103tim@0x34001000/reg 0x34001000 36 0x34001080 100 0x34004000 16"); 218 219 /* Hook timer interrupts up to interrupt controller */ 220 sim_hw_parse (sd, "/mn103tim > timer-0-underflow timer-0-underflow /mn103int"); 221 sim_hw_parse (sd, "/mn103tim > timer-1-underflow timer-1-underflow /mn103int"); 222 sim_hw_parse (sd, "/mn103tim > timer-2-underflow timer-2-underflow /mn103int"); 223 sim_hw_parse (sd, "/mn103tim > timer-3-underflow timer-3-underflow /mn103int"); 224 sim_hw_parse (sd, "/mn103tim > timer-4-underflow timer-4-underflow /mn103int"); 225 sim_hw_parse (sd, "/mn103tim > timer-5-underflow timer-5-underflow /mn103int"); 226 sim_hw_parse (sd, "/mn103tim > timer-6-underflow timer-6-underflow /mn103int"); 227 sim_hw_parse (sd, "/mn103tim > timer-6-compare-a timer-6-compare-a /mn103int"); 228 sim_hw_parse (sd, "/mn103tim > timer-6-compare-b timer-6-compare-b /mn103int"); 229 230 231 /* Serial devices 0,1,2 */ 232 sim_hw_parse (sd, "/mn103ser@0x34000800/reg 0x34000800 48"); 233 sim_hw_parse (sd, "/mn103ser@0x34000800/poll? true"); 234 235 /* Hook serial interrupts up to interrupt controller */ 236 sim_hw_parse (sd, "/mn103ser > serial-0-receive serial-0-receive /mn103int"); 237 sim_hw_parse (sd, "/mn103ser > serial-0-transmit serial-0-transmit /mn103int"); 238 sim_hw_parse (sd, "/mn103ser > serial-1-receive serial-1-receive /mn103int"); 239 sim_hw_parse (sd, "/mn103ser > serial-1-transmit serial-1-transmit /mn103int"); 240 sim_hw_parse (sd, "/mn103ser > serial-2-receive serial-2-receive /mn103int"); 241 sim_hw_parse (sd, "/mn103ser > serial-2-transmit serial-2-transmit /mn103int"); 242 243 sim_hw_parse (sd, "/mn103iop@0x36008000/reg 0x36008000 8 0x36008020 8 0x36008040 0xc 0x36008060 8 0x36008080 8"); 244 245 /* Memory control registers */ 246 sim_do_command (sd, "memory region 0x32000020,0x30"); 247 /* Cache control register */ 248 sim_do_command (sd, "memory region 0x20000070,0x4"); 249 /* Cache purge regions */ 250 sim_do_command (sd, "memory region 0x28400000,0x800"); 251 sim_do_command (sd, "memory region 0x28401000,0x800"); 252 /* DMA registers */ 253 sim_do_command (sd, "memory region 0x32000100,0xF"); 254 sim_do_command (sd, "memory region 0x32000200,0xF"); 255 sim_do_command (sd, "memory region 0x32000400,0xF"); 256 sim_do_command (sd, "memory region 0x32000800,0xF"); 257 } 258 else 259 { 260 if (board != NULL) 261 { 262 sim_io_eprintf (sd, "Error: Board `%s' unknown.\n", board); 263 return 0; 264 } 265 } 266 267 268 269 /* check for/establish the a reference program image */ 270 if (sim_analyze_program (sd, 271 (STATE_PROG_ARGV (sd) != NULL 272 ? *STATE_PROG_ARGV (sd) 273 : NULL), 274 abfd) != SIM_RC_OK) 275 { 276 sim_module_uninstall (sd); 277 return 0; 278 } 279 280 /* establish any remaining configuration options */ 281 if (sim_config (sd) != SIM_RC_OK) 282 { 283 sim_module_uninstall (sd); 284 return 0; 285 } 286 287 if (sim_post_argv_init (sd) != SIM_RC_OK) 288 { 289 /* Uninstall the modules to avoid memory leaks, 290 file descriptor leaks, etc. */ 291 sim_module_uninstall (sd); 292 return 0; 293 } 294 295 296 /* set machine specific configuration */ 297/* STATE_CPU (sd, 0)->psw_mask = (PSW_NP | PSW_EP | PSW_ID | PSW_SAT */ 298/* | PSW_CY | PSW_OV | PSW_S | PSW_Z); */ 299 300 return sd; 301} 302 303 304void 305sim_close (SIM_DESC sd, int quitting) 306{ 307 sim_module_uninstall (sd); 308} 309 310 311SIM_RC 312sim_create_inferior (SIM_DESC sd, 313 struct bfd *prog_bfd, 314 char **argv, 315 char **env) 316{ 317 memset (&State, 0, sizeof (State)); 318 if (prog_bfd != NULL) { 319 PC = bfd_get_start_address (prog_bfd); 320 } else { 321 PC = 0; 322 } 323 CIA_SET (STATE_CPU (sd, 0), (unsigned64) PC); 324 325 if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_am33_2) 326 PSW |= PSW_FE; 327 328 return SIM_RC_OK; 329} 330 331void 332sim_do_command (SIM_DESC sd, char *cmd) 333{ 334 char *mm_cmd = "memory-map"; 335 char *int_cmd = "interrupt"; 336 337 if (sim_args_command (sd, cmd) != SIM_RC_OK) 338 { 339 if (strncmp (cmd, mm_cmd, strlen (mm_cmd) == 0)) 340 sim_io_eprintf (sd, "`memory-map' command replaced by `sim memory'\n"); 341 else if (strncmp (cmd, int_cmd, strlen (int_cmd)) == 0) 342 sim_io_eprintf (sd, "`interrupt' command replaced by `sim watch'\n"); 343 else 344 sim_io_eprintf (sd, "Unknown command `%s'\n", cmd); 345 } 346} 347 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 352get_byte (uint8 *x) 353{ 354 return *x; 355} 356 357uint16 358get_half (uint8 *x) 359{ 360 uint8 *a = x; 361 return (a[1] << 8) + (a[0]); 362} 363 364uint32 365get_word (uint8 *x) 366{ 367 uint8 *a = x; 368 return (a[3]<<24) + (a[2]<<16) + (a[1]<<8) + (a[0]); 369} 370 371void 372put_byte (uint8 *addr, uint8 data) 373{ 374 uint8 *a = addr; 375 a[0] = data; 376} 377 378void 379put_half (uint8 *addr, uint16 data) 380{ 381 uint8 *a = addr; 382 a[0] = data & 0xff; 383 a[1] = (data >> 8) & 0xff; 384} 385 386void 387put_word (uint8 *addr, uint32 data) 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 397sim_fetch_register (SIM_DESC sd, 398 int rn, 399 unsigned char *memory, 400 int length) 401{ 402 put_word (memory, State.regs[rn]); 403 return -1; 404} 405 406int 407sim_store_register (SIM_DESC sd, 408 int rn, 409 unsigned char *memory, 410 int length) 411{ 412 State.regs[rn] = get_word (memory); 413 return -1; 414} 415 416 417void 418mn10300_core_signal (SIM_DESC sd, 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) 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; 461 static int in_interrupt = 0; 462 463#ifdef SIM_CPU_EXCEPTION_TRIGGER 464 SIM_CPU_EXCEPTION_TRIGGER(sd,cpu,cia); 465#endif 466 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 */ 477 store_word (SP - 4, CIA_GET (cpu)); 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 489 PSW &= ~PSW_IE; 490 SP = SP - 8; 491 CIA_SET (cpu, 0x40000008); 492 493 in_interrupt = 0; 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 506 CIA_SET (cpu, cia); 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)); 522 CIA_SET (cpu, PC); /* copy PC back from new State.regs */ 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)); 544 CIA_SET (cpu, PC); /* copy PC back from new State.regs */ 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} 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} 1118