1/*- 2 * Copyright (c) 2010 by Peter Jeremy <peterjeremy@acm.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD$"); 28 29#include <sys/param.h> 30 31#include <math.h> 32#include <stdio.h> 33#include <stdlib.h> 34 35#include "__sparc_utrap_private.h" 36#include "fpu_extern.h" 37#include "fpu_reg.h" 38 39static u_long ireg[32]; 40 41void 42__utrap_panic(const char *msg) 43{ 44 45 fprintf(stderr, "panic: %s\n", msg); 46 exit(1); 47} 48 49void __utrap_write(const char *msg) 50{ 51 52 fprintf(stderr, "%s", msg); 53} 54 55u_long 56__emul_fetch_reg(struct utrapframe *uf, int reg) 57{ 58 59 return (ireg[reg]); 60} 61 62typedef unsigned char int8; 63typedef unsigned int int32; 64typedef unsigned long int64; 65typedef unsigned int float32; 66typedef unsigned long float64; 67typedef struct { 68 unsigned long high, low; 69} float128; 70typedef unsigned long flag; 71 72struct utrapframe utf; 73 74u_int32_t __fpreg[64]; 75 76static __inline float128 77__fpu_getreg128(int r) 78{ 79 float128 v; 80 81 v.high = ((u_int64_t)__fpreg[r] << 32 | (u_int64_t)__fpreg[r + 1]); 82 v.low = ((u_int64_t)__fpreg[r + 2] << 32 | (u_int64_t)__fpreg[r + 3]); 83 return (v); 84} 85 86static __inline void 87__fpu_setreg128(int r, float128 v) 88{ 89 90 __fpreg[r] = (u_int32_t)(v.high >> 32); 91 __fpreg[r + 1] = (u_int32_t)v.high; 92 __fpreg[r + 2] = (u_int32_t)(v.low >> 32); 93 __fpreg[r + 3] = (u_int32_t)v.low; 94} 95 96/* 97------------------------------------------------------------------------------- 98Clears the system's IEC/IEEE floating-point exception flags. Returns the 99previous value of the flags. 100------------------------------------------------------------------------------- 101*/ 102#include <fenv.h> 103#include <ieeefp.h> 104 105int8 syst_float_flags_clear(void) 106{ 107 int32 flags; 108 109 flags = (utf.uf_fsr & FE_ALL_EXCEPT) >> 5; 110 utf.uf_fsr &= ~(u_long)FE_ALL_EXCEPT; 111 return (flags); 112} 113 114static void 115emul_trap(const u_int *insn, u_long mask) 116{ 117 u_int32_t savreg[64]; 118 int i; 119 120 for (i = 0; i < 64; i++) 121 savreg[i] = __fpreg[i]; 122 123 utf.uf_fsr = (utf.uf_fsr & ~FSR_FTT_MASK) | 124 (FSR_FTT_UNFIN << FSR_FTT_SHIFT); 125 utf.uf_pc = (u_long)insn; 126 if (__fpu_exception(&utf) == 0) 127 __asm("stx %%fsr,%0" : "=m" (utf.uf_fsr)); 128 129 for (i = 0; i < 64; i++) { 130 if (!(mask & (1UL << i)) && savreg[i] != __fpreg[i]) { 131 fprintf(stderr, "### %2d %08x != %08x\n", 132 i, savreg[i], __fpreg[i]); 133 } 134 } 135} 136 137extern u_int insn_int32_to_float32; 138extern u_int insn_int32_to_float64; 139extern u_int insn_int32_to_float128; 140extern u_int insn_int64_to_float32; 141extern u_int insn_int64_to_float64; 142extern u_int insn_int64_to_float128; 143extern u_int insn_float32_to_int32_round_to_zero; 144extern u_int insn_float32_to_int64_round_to_zero; 145extern u_int insn_float32_to_float64; 146extern u_int insn_float32_to_float128; 147extern u_int insn_float32_add; 148extern u_int insn_float32_sub; 149extern u_int insn_float32_mul; 150extern u_int insn_float32_div; 151extern u_int insn_float32_sqrt; 152extern u_int insn_float32_cmp; 153extern u_int insn_float32_cmpe; 154extern u_int insn_float64_to_int32_round_to_zero; 155extern u_int insn_float64_to_int64_round_to_zero; 156extern u_int insn_float64_to_float32; 157extern u_int insn_float64_to_float128; 158extern u_int insn_float64_add; 159extern u_int insn_float64_sub; 160extern u_int insn_float64_mul; 161extern u_int insn_float64_div; 162extern u_int insn_float64_sqrt; 163extern u_int insn_float64_cmp; 164extern u_int insn_float64_cmpe; 165extern u_int insn_float128_to_int32_round_to_zero; 166extern u_int insn_float128_to_int64_round_to_zero; 167extern u_int insn_float128_to_float32; 168extern u_int insn_float128_to_float64; 169extern u_int insn_float128_add; 170extern u_int insn_float128_sub; 171extern u_int insn_float128_mul; 172extern u_int insn_float128_div; 173extern u_int insn_float128_sqrt; 174extern u_int insn_float128_cmp; 175extern u_int insn_float128_cmpe; 176 177float32 178syst_int32_to_float32(int32 a) 179{ 180 181 __fpu_setreg(0, a); 182 emul_trap(&insn_int32_to_float32, 0x1UL); 183 return (__fpu_getreg(0)); 184} 185 186float64 187syst_int32_to_float64(int32 a) 188{ 189 190 __fpu_setreg(0, a); 191 emul_trap(&insn_int32_to_float64, 0x3UL); 192 return (__fpu_getreg64(0)); 193} 194 195float128 196syst_int32_to_float128(int32 a) 197{ 198 199 __fpu_setreg(0, a); 200 emul_trap(&insn_int32_to_float128, 0xfUL); 201 return (__fpu_getreg128(0)); 202} 203 204float32 205syst_int64_to_float32(int64 a) 206{ 207 208 __fpu_setreg64(0, a); 209 emul_trap(&insn_int64_to_float32, 0x1UL); 210 return (__fpu_getreg(0)); 211} 212 213float64 214syst_int64_to_float64(int64 a) 215{ 216 217 __fpu_setreg64(0, a); 218 emul_trap(&insn_int64_to_float64, 0x3UL); 219 return (__fpu_getreg64(0)); 220} 221 222 223float128 224syst_int64_to_float128(int64 a) 225{ 226 227 __fpu_setreg64(0, a); 228 emul_trap(&insn_int64_to_float128, 0xfUL); 229 return (__fpu_getreg128(0)); 230} 231 232int32 233syst_float32_to_int32_round_to_zero(float32 a) 234{ 235 236 __fpu_setreg(0, a); 237 emul_trap(&insn_float32_to_int32_round_to_zero, 0x1UL); 238 return (__fpu_getreg(0)); 239} 240 241int64 242syst_float32_to_int64_round_to_zero(float32 a) 243{ 244 245 __fpu_setreg(0, a); 246 emul_trap(&insn_float32_to_int64_round_to_zero, 0x3UL); 247 return (__fpu_getreg64(0)); 248} 249 250float64 251syst_float32_to_float64(float32 a) 252{ 253 254 __fpu_setreg(0, a); 255 emul_trap(&insn_float32_to_float64, 0x3UL); 256 return (__fpu_getreg64(0)); 257} 258 259float128 260syst_float32_to_float128(float32 a) 261{ 262 263 __fpu_setreg(0, a); 264 emul_trap(&insn_float32_to_float128, 0xfUL); 265 return (__fpu_getreg128(0)); 266} 267 268float32 269syst_float32_add(float32 a, float32 b) 270{ 271 272 __fpu_setreg(0, a); 273 __fpu_setreg(1, b); 274 emul_trap(&insn_float32_add, 0x1UL); 275 return (__fpu_getreg(0)); 276} 277 278float32 279syst_float32_sub(float32 a, float32 b) 280{ 281 282 __fpu_setreg(0, a); 283 __fpu_setreg(1, b); 284 emul_trap(&insn_float32_sub, 0x1UL); 285 return (__fpu_getreg(0)); 286} 287 288float32 289syst_float32_mul(float32 a, float32 b) 290{ 291 292 __fpu_setreg(0, a); 293 __fpu_setreg(1, b); 294 emul_trap(&insn_float32_mul, 0x1UL); 295 return (__fpu_getreg(0)); 296} 297 298float32 299syst_float32_div(float32 a, float32 b) 300{ 301 302 __fpu_setreg(0, a); 303 __fpu_setreg(1, b); 304 emul_trap(&insn_float32_div, 0x1UL); 305 return (__fpu_getreg(0)); 306} 307 308float32 309syst_float32_sqrt(float32 a) 310{ 311 312 __fpu_setreg(0, a); 313 emul_trap(&insn_float32_sqrt, 0x1UL); 314 return (__fpu_getreg(0)); 315} 316 317flag syst_float32_eq(float32 a, float32 b) 318{ 319 u_long r; 320 321 __fpu_setreg(0, a); 322 __fpu_setreg(1, b); 323 emul_trap(&insn_float32_cmp, 0x0UL); 324 __asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r)); 325 return (r); 326} 327 328flag syst_float32_le(float32 a, float32 b) 329{ 330 u_long r; 331 332 __fpu_setreg(0, a); 333 __fpu_setreg(1, b); 334 emul_trap(&insn_float32_cmpe, 0x0UL); 335 __asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r)); 336 return (r); 337} 338 339flag syst_float32_lt(float32 a, float32 b) 340{ 341 u_long r; 342 343 __fpu_setreg(0, a); 344 __fpu_setreg(1, b); 345 emul_trap(&insn_float32_cmpe, 0x0UL); 346 __asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r)); 347 return (r); 348} 349 350flag syst_float32_eq_signaling(float32 a, float32 b) 351{ 352 u_long r; 353 354 __fpu_setreg(0, a); 355 __fpu_setreg(1, b); 356 emul_trap(&insn_float32_cmpe, 0x0UL); 357 __asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r)); 358 return (r); 359} 360 361flag syst_float32_le_quiet(float32 a, float32 b) 362{ 363 u_long r; 364 365 __fpu_setreg(0, a); 366 __fpu_setreg(1, b); 367 emul_trap(&insn_float32_cmp, 0x0UL); 368 __asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r)); 369 return (r); 370} 371 372flag syst_float32_lt_quiet(float32 a, float32 b) 373{ 374 u_long r; 375 376 __fpu_setreg(0, a); 377 __fpu_setreg(1, b); 378 emul_trap(&insn_float32_cmp, 0x0UL); 379 __asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r)); 380 return (r); 381} 382 383int32 384syst_float64_to_int32_round_to_zero(float64 a) 385{ 386 387 __fpu_setreg64(0, a); 388 emul_trap(&insn_float64_to_int32_round_to_zero, 0x1UL); 389 return (__fpu_getreg(0)); 390} 391 392int64 393syst_float64_to_int64_round_to_zero(float64 a) 394{ 395 396 __fpu_setreg64(0, a); 397 emul_trap(&insn_float64_to_int64_round_to_zero, 0x3UL); 398 return (__fpu_getreg64(0)); 399} 400 401float32 402syst_float64_to_float32(float64 a) 403{ 404 405 __fpu_setreg64(0, a); 406 emul_trap(&insn_float64_to_float32, 0x1UL); 407 return (__fpu_getreg(0)); 408} 409 410float128 411syst_float64_to_float128(float64 a) 412{ 413 414 __fpu_setreg64(0, a); 415 emul_trap(&insn_float64_to_float128, 0xfUL); 416 return (__fpu_getreg128(0)); 417} 418 419float64 420syst_float64_add(float64 a, float64 b) 421{ 422 423 __fpu_setreg64(0, a); 424 __fpu_setreg64(2, b); 425 emul_trap(&insn_float64_add, 0x3UL); 426 return (__fpu_getreg64(0)); 427} 428 429float64 430syst_float64_sub(float64 a, float64 b) 431{ 432 433 __fpu_setreg64(0, a); 434 __fpu_setreg64(2, b); 435 emul_trap(&insn_float64_sub, 0x3UL); 436 return (__fpu_getreg64(0)); 437} 438 439float64 440syst_float64_mul(float64 a, float64 b) 441{ 442 443 __fpu_setreg64(0, a); 444 __fpu_setreg64(2, b); 445 emul_trap(&insn_float64_mul, 0x3UL); 446 return (__fpu_getreg64(0)); 447} 448 449float64 450syst_float64_div(float64 a, float64 b) 451{ 452 453 __fpu_setreg64(0, a); 454 __fpu_setreg64(2, b); 455 emul_trap(&insn_float64_div, 0x3UL); 456 return (__fpu_getreg64(0)); 457} 458 459float64 460syst_float64_sqrt(float64 a) 461{ 462 463 __fpu_setreg64(0, a); 464 emul_trap(&insn_float64_sqrt, 0x3UL); 465 return (__fpu_getreg64(0)); 466} 467 468flag syst_float64_eq(float64 a, float64 b) 469{ 470 u_long r; 471 472 __fpu_setreg64(0, a); 473 __fpu_setreg64(2, b); 474 emul_trap(&insn_float64_cmp, 0x0UL); 475 __asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r)); 476 return (r); 477} 478 479flag syst_float64_le(float64 a, float64 b) 480{ 481 u_long r; 482 483 __fpu_setreg64(0, a); 484 __fpu_setreg64(2, b); 485 emul_trap(&insn_float64_cmpe, 0x0UL); 486 __asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r)); 487 return (r); 488} 489 490flag syst_float64_lt(float64 a, float64 b) 491{ 492 u_long r; 493 494 __fpu_setreg64(0, a); 495 __fpu_setreg64(2, b); 496 emul_trap(&insn_float64_cmpe, 0x0UL); 497 __asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r)); 498 return (r); 499} 500 501flag syst_float64_eq_signaling(float64 a, float64 b) 502{ 503 u_long r; 504 505 __fpu_setreg64(0, a); 506 __fpu_setreg64(2, b); 507 emul_trap(&insn_float64_cmpe, 0x0UL); 508 __asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r)); 509 return (r); 510} 511 512flag syst_float64_le_quiet(float64 a, float64 b) 513{ 514 u_long r; 515 516 __fpu_setreg64(0, a); 517 __fpu_setreg64(2, b); 518 emul_trap(&insn_float64_cmp, 0x0UL); 519 __asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r)); 520 return (r); 521} 522 523flag syst_float64_lt_quiet(float64 a, float64 b) 524{ 525 u_long r; 526 527 __fpu_setreg64(0, a); 528 __fpu_setreg64(2, b); 529 emul_trap(&insn_float64_cmp, 0x0UL); 530 __asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r)); 531 return (r); 532} 533 534int32 535syst_float128_to_int32_round_to_zero(float128 a) 536{ 537 538 __fpu_setreg128(0, a); 539 emul_trap(&insn_float128_to_int32_round_to_zero, 0x1UL); 540 return (__fpu_getreg(0)); 541} 542 543int64 544syst_float128_to_int64_round_to_zero(float128 a) 545{ 546 547 __fpu_setreg128(0, a); 548 emul_trap(&insn_float128_to_int64_round_to_zero, 0x3UL); 549 return (__fpu_getreg64(0)); 550} 551 552float32 553syst_float128_to_float32(float128 a) 554{ 555 556 __fpu_setreg128(0, a); 557 emul_trap(&insn_float128_to_float32, 0x1UL); 558 return (__fpu_getreg(0)); 559} 560 561float64 562syst_float128_to_float64(float128 a) 563{ 564 565 __fpu_setreg128(0, a); 566 emul_trap(&insn_float128_to_float64, 0x3UL); 567 return (__fpu_getreg64(0)); 568} 569 570float128 571syst_float128_add(float128 a, float128 b) 572{ 573 574 __fpu_setreg128(0, a); 575 __fpu_setreg128(4, b); 576 emul_trap(&insn_float128_add, 0xfUL); 577 return (__fpu_getreg128(0)); 578} 579 580float128 581syst_float128_sub(float128 a, float128 b) 582{ 583 584 __fpu_setreg128(0, a); 585 __fpu_setreg128(4, b); 586 emul_trap(&insn_float128_sub, 0xfUL); 587 return (__fpu_getreg128(0)); 588} 589 590float128 591syst_float128_mul(float128 a, float128 b) 592{ 593 594 __fpu_setreg128(0, a); 595 __fpu_setreg128(4, b); 596 emul_trap(&insn_float128_mul, 0xfUL); 597 return (__fpu_getreg128(0)); 598} 599 600float128 601syst_float128_div(float128 a, float128 b) 602{ 603 604 __fpu_setreg128(0, a); 605 __fpu_setreg128(4, b); 606 emul_trap(&insn_float128_div, 0xfUL); 607 return (__fpu_getreg128(0)); 608} 609 610float128 611syst_float128_sqrt(float128 a) 612{ 613 614 __fpu_setreg128(0, a); 615 emul_trap(&insn_float128_sqrt, 0xfUL); 616 return (__fpu_getreg128(0)); 617} 618 619flag syst_float128_eq(float128 a, float128 b) 620{ 621 u_long r; 622 623 __fpu_setreg128(0, a); 624 __fpu_setreg128(4, b); 625 emul_trap(&insn_float128_cmp, 0x0UL); 626 __asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r)); 627 return (r); 628} 629 630flag syst_float128_le(float128 a, float128 b) 631{ 632 u_long r; 633 634 __fpu_setreg128(0, a); 635 __fpu_setreg128(4, b); 636 emul_trap(&insn_float128_cmpe, 0x0UL); 637 __asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r)); 638 return (r); 639} 640 641flag syst_float128_lt(float128 a, float128 b) 642{ 643 u_long r; 644 645 __fpu_setreg128(0, a); 646 __fpu_setreg128(4, b); 647 emul_trap(&insn_float128_cmpe, 0x0UL); 648 __asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r)); 649 return (r); 650} 651 652flag syst_float128_eq_signaling(float128 a, float128 b) 653{ 654 u_long r; 655 656 __fpu_setreg128(0, a); 657 __fpu_setreg128(4, b); 658 emul_trap(&insn_float128_cmpe, 0x0UL); 659 __asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r)); 660 return (r); 661} 662 663flag syst_float128_le_quiet(float128 a, float128 b) 664{ 665 u_long r; 666 667 __fpu_setreg128(0, a); 668 __fpu_setreg128(4, b); 669 emul_trap(&insn_float128_cmp, 0x0UL); 670 __asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r)); 671 return (r); 672} 673 674flag syst_float128_lt_quiet(float128 a, float128 b) 675{ 676 u_long r; 677 678 __fpu_setreg128(0, a); 679 __fpu_setreg128(4, b); 680 emul_trap(&insn_float128_cmp, 0x0UL); 681 __asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r)); 682 return (r); 683} 684 685 686/* 687------------------------------------------------------------------------------- 688Sets the system's IEC/IEEE floating-point rounding mode. 689------------------------------------------------------------------------------- 690*/ 691void syst_float_set_rounding_mode(int8 roundingMode) 692{ 693 694 utf.uf_fsr &= ~FSR_RD_MASK; 695 utf.uf_fsr |= FSR_RD((unsigned int)roundingMode & 0x03); 696} 697 698/* 699------------------------------------------------------------------------------- 700Does nothing. 701------------------------------------------------------------------------------- 702*/ 703void syst_float_set_rounding_precision(int8 precision) 704{ 705 706} 707