1/* $NetBSD: unimpl_emul.S,v 1.2 2002/02/24 01:04:27 matt Exp $ */ 2 3/* 4 * Copyright (c) 2001 Brandon Creighton. All rights reserved. 5 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed at Ludd, University of 18 * Lule}, Sweden and its contributors. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 35#include <machine/asm.h> 36#include "assym.h" 37 38# Only intended for debugging emulation code (security hole) 39#undef EMULATE_INKERNEL 40 41# Defines to fetch register operands 42#define S_R0 (%fp) 43#define S_R1 4(%fp) 44#define S_R2 8(%fp) 45#define S_R3 12(%fp) 46#define S_R4 16(%fp) 47#define S_R5 20(%fp) 48#define S_R6 24(%fp) 49#define S_R7 28(%fp) 50#define S_R8 32(%fp) 51#define S_R9 36(%fp) 52#define S_R10 40(%fp) 53#define S_R11 44(%fp) 54#define S_AP 48(%fp) 55#define S_FP 52(%fp) 56#define S_SP 56(%fp) 57#define S_PC 60(%fp) 58#define S_PSL 64(%fp) 59 60# The condition codes. 61 62#define PSL_C 1 63#define PSL_V 2 64#define PSL_Z 4 65#define PSL_N 8 66#define PSL_Q 15 # all four 67 68# 69# Emulation of instruction trapped via SCB vector 0x18. (reserved op) 70# 71ALTENTRY(unimemu) 72 pushl %r0 73 movl 8(%sp),%r0 # get trap address 74 movzbl (%r0),%r0 # fetch insn generating trap 75 caseb %r0,$0x74,$1 # case to jump to address 760: .word emodd-0b 77 .word polyd-0b 78 791: movl (%sp)+,%r0 # restore reg 80 rsb # continue fault 81 82# 83# switch the code back over to user mode. 84# puts the psl + pc (+ jsb return address) on top of user stack. 85# 86#ifdef EMULATE_INKERNEL 87touser: movl (%sp),-52(%sp) # save rsb address on top of new stack 88 movl 4(%sp),%r0 # restore saved reg 89 addl2 $12,%sp # pop junk from stack 90 pushr $0x7fff # save all regs 91 movl %sp,%fp # new frame pointer 92 tstl -(%sp) # remember old rsb address 93 incl S_PC # skip matching insn 94 rsb 95#else 96touser: mfpr $PR_USP,%r0 # get user stack pointer 97 movl 4(%sp),-68(%r0) # move already saved %r0 98 movl (%sp),-72(%r0) # move return address 99 movq 12(%sp),-8(%r0) # move pc + psl 100 addl2 $12,%sp # remove moved fields from stack 101 movl $1f,(%sp) # change return address 102 rei 1031: subl2 $8,%sp # trapaddr + psl already on stack 104 pushr $0x7ffe # %r0 already saved 105 subl2 $8,%sp # do not trash %r0 + retaddr 106 movab 4(%sp),%fp 107 incl S_PC # skip matching insn 108 rsb 109#endif 110 111# 112# Restore registers, cleanup and continue 113# 114goback: movl %fp,%sp # be sure 115 popr $0x7fff # restore all regs 116 rei 117 118/* 119 * getval: is used by the getval_* functions. Gets the value specified by the 120 * current operand specifier pointed to by S_PC. It also increments S_PC. 121 */ 122getval: 123 clrq %r0 124 pushr $(R2+R3+R4+R5+R6) 125 movl S_PC,%r3 # argument address 126 extzv $4,$4,(%r3),%r2 # get mode 127 caseb %r2,$0,$0xf 1280: .word getval_literal-0b # 0-3 literal 129 .word getval_literal-0b 130 .word getval_literal-0b 131 .word getval_literal-0b 132 .word 2f-0b # 4 indexed 133 .word getval_reg-0b # 5 register 134 .word getval_regdefer-0b # 6 register deferred 135 .word 2f-0b # 7 register deferred 136 .word getval_ai-0b # 8 autoincrement 137 .word 2f-0b # 9 autoincrement deferred 138 .word getval_bytedis-0b # A byte displacement 139 .word 2f-0b # B byte displacement deferred 140 .word 2f-0b # C word displacement 141 .word 2f-0b # D word displacement deferred 142 .word getval_longdis-0b # E longword displacement 143 .word 2f-0b # F longword displacement deferred 144#ifdef EMULATE_INKERNEL 1452: movab 0f,%r0 146 movl %r2,%r1 147 brw die 1480: .asciz "getval: missing address mode %d\n" 149#else 1502: .word 0xffff # reserved operand 151#endif 152 153 /* 154 * 0x00-0x03 155 * Literal mode. Note: getval_{d,f}float will *never* use this routine 156 * to get literal values, since they treat them differently (see those routines 157 * for details). 158 */ 159getval_literal: 160 movzbl (%r3)+,%r0 # correct operand 161 brw 4f 162 163 /* 164 * 0x05 165 * Register mode. Grab the register number, yank the value out. 166 */ 167getval_reg: 168 extzv $0,$4,(%r3),%r2 # Get reg number 169 incl %r3 170 ashl $2,%r2,%r2 171 addl3 %fp,%r2,%r5 172 bsbw emul_extract 173 brw 4f 174 175 /* 176 * 0x06 177 * Register deferred mode. Grab the register number, yank the value out, 178 * use that as the address to get the real value. 179 */ 180getval_regdefer: 181 extzv $0,$4,(%r3),%r2 # Get reg number 182 incl %r3 183 ashl $2,%r2,%r2 184 addl2 %fp,%r2 185 movl (%r2),%r5 186 bsbw emul_extract 187 brw 4f 188 189 /* 190 * 0x08 Autoincrement mode 191 * Get the value in the register, use that as the address of our target, 192 * then increment the register. 193 */ 194getval_ai: 195 extzv $0,$4,(%r3),%r2 # Get reg number 196 incl %r3 197 198 /* 199 * In the case of the register being PC (0xf), this is called immediate mode; 200 * we can treat it the same as any other register, as long as we keep %r3 201 * and S_PC in sync. We do that here. 202 */ 203 movl %r3,S_PC 204 205 ashl $2,%r2,%r2 206 addl2 %fp,%r2 207 movl (%r2),%r5 208 bsbw emul_extract 209 addl2 %r6,(%r2) 210 211 movl S_PC,%r3 /* if PC did change, S_PC was changed too */ 212 brw 4f 213 214 /* 215 * 0xA 216 * Byte displacement mode. 217 */ 218getval_bytedis: 219 extzv $0, $4, (%r3), %r2 # get register 220 incl %r3 221 ashl $2,%r2,%r2 222 addl2 %fp,%r2 223 movl (%r2),%r5 224 movzbl (%r3),%r4 225 incl %r3 226 addl2 %r4, %r5 227 bsbw emul_extract 228 brw 4f 229 230 /* 231 * 0xE 232 * Longword displacement mode. 233 */ 234getval_longdis: 235 extzv $0, $4, (%r3), %r2 # get register 236 incl %r3 237 ashl $2,%r2,%r2 238 addl2 %fp,%r2 239 movl (%r2),%r5 240 movl (%r3)+,%r4 241 addl2 %r4, %r5 242 bsbw emul_extract 243 2444: movl %r3,S_PC 245 popr $(R2+R3+R4+R5+R6) 246 rsb 247 248/* 249 * emul_extract: used by the getval functions. This extracts exactly %r6 bytes 250 * from the address in %r5 and places them in %r0 and %r1 (if necessary). 251 * 8 is the current maximum length. 252 */ 253emul_extract: 254 cmpl $0x8, %r6 255 bgeq 1f 256 .word 0xffff # reserved operand 2571: 258 caseb %r6, $0x1, $0x7 2590: .word 1f-0b # 1: byte 260 .word 2f-0b # 2: word 261 .word 9f-0b # unknown 262 .word 4f-0b # 4: longword 263 .word 9f-0b # unknown 264 .word 9f-0b # unknown 265 .word 9f-0b # unknown 266 .word 8f-0b # 8: quadword 267 2681: movzbl (%r5), %r0 269 rsb 270 2712: movzwl (%r5), %r0 272 rsb 273 2744: movl (%r5), %r0 275 rsb 276 2778: movq (%r5), %r0 278 rsb 279 2809: 281 .word 0xffff # reserved operand 282 rsb 283 284getval_dfloat: 285 clrq %r0 286 pushr $(R2+R3+R6) # use %r2+%r3 as scratch reg 287 movl S_PC,%r3 # argument address 288 extzv $4,$4,(%r3),%r2 # get mode 289 caseb %r2,$0,$0x3 2900: .word 1f-0b # 0-3 literal 291 .word 1f-0b 292 .word 1f-0b 293 .word 1f-0b 294 295 movl $0x8, %r6 296 bsbw getval 297 brw 4f 298 2991: insv (%r3),$0,$3,%r0 # insert fraction 300 extzv $3,$3,(%r3),%r2 # get exponent 301 addl2 $128,%r2 # bias the exponent 302 insv %r2,$7,$8,%r0 # insert exponent 303 tstb (%r3)+ 304 movl %r3,S_PC 3054: 306 popr $(R2+R3+R6) 307 rsb 308 309getval_long: 310 clrl %r0 311 pushr $(R6+R1) 312 movl $0x4, %r6 313 bsbw getval 314 popr $(R6+R1) 315 rsb 316 317getval_word: 318 clrl %r0 319 pushr $(R6+R1) 320 movl $0x2, %r6 321 bsbw getval 322 popr $(R6+R1) 323 rsb 324 325getval_byte: 326 clrl %r0 327 pushr $(R6+R1) # use %r2+%r3 as scratch reg 328 movl $0x1, %r6 329 bsbw getval 330 popr $(R6+R1) 331 rsb 332 333# 334# getaddr_byte get 4 bytes and stores them in %r0. Increases PC. 335# 336getaddr_byte: 337 clrl %r0 338 pushr $(R2+R3) # use %r2+%r3 as scratch reg 339 movl S_PC,%r3 # argument address 340 extzv $4,$4,(%r3),%r2 # get mode 341 caseb %r2,$0,$0xf 3420: .word 2f-0b # 0-3 literal 343 .word 2f-0b 344 .word 2f-0b 345 .word 2f-0b 346 .word 2f-0b # 4 347 .word 6f-0b # 5 register 348 .word 5f-0b # 6 deferred 349 .word 2f-0b # 7 autodecr (missing) 350 .word 2f-0b # 8 autoincr (missing) 351 .word 2f-0b # 9 autoincr deferred (missing) 352 .word 7f-0b # 10 byte disp 353 .word 2f-0b # 11 byte disp deferred (missing) 354 .word 2f-0b # 12 word disp (missing) 355 .word 2f-0b # 13 word disp deferred (missing) 356 .word 1f-0b # 14 long disp 357 .word 2f-0b # 15 long disp deferred (missing) 358#ifdef EMULATE_INKERNEL 3592: movab 3f,%r0 360 movl %r2,%r1 361 brw die # reserved operand 3623: .asciz "getaddr_byte: missing address mode %d\n" 363#else 3642: .word 0xffff # reserved operand 365#endif 366 3671: extzv $0,$4,(%r3),%r2 # Get reg number 368 incl %r3 369 movl (%fp)[%r2],%r0 # Register contents 370 addl2 (%r3),%r0 # add displacement 371 cmpl %r2,$15 # pc? 372 bneq 0f # no, skip 373 addl2 $5,%r0 # compensate for displacement size 3740: addl2 $4,%r3 # increase pc 375 brw 4f 376 3775: extzv $0,$4,(%r3),%r2 # Get reg number 378 incl %r3 379 movl (%fp)[%r2],%r0 380 brw 4f 381 3827: 383 extzv $0, $4, (%r3), %r2 # get register 384 incl %r3 385 movl %r3, S_PC 386 ashl $2,%r2,%r2 387 addl2 %fp,%r2 388 movl (%r2),%r5 389 movzbl (%r3),%r4 390 movl S_PC, %r3 391 incl %r3 392 addl3 %r4, %r5, %r0 393 brw 4f 394 3956: extzv $0,$4,(%r3),%r2 # Get reg number 396 incl %r3 397 moval (%fp)[%r2],%r0 398 3994: movl %r3,S_PC 400 popr $(R2+R3) 401 rsb 402 403# 404# Polynomial calculation, d-float 405# Uses d-float instructions, so hopefully d-float is available. 406# 407# polyd MISSING: 408# - check for bad arguments 409# - set PSL flags 410# - do not use d-float instructions (may be emulated) 411# 412polyd: bsbw touser # go back to user mode 413 bsbw getval_dfloat # fetches argument to %r0/%r1 414 movq %r0,%r6 415 bsbw getval_word 416 movl %r0,%r4 417 bsbw getaddr_byte 418 movl %r0,%r3 419 clrq %r0 420# Ok, do the real calculation (Horner's method) 4210: addd2 (%r3)+,%r0 # add constant 422 tstl %r4 # more? 423 beql 1f # no, exit 424 muld2 %r6,%r0 # multiply with arg 425 decl %r4 # lower degree 426 brb 0b 427 4281: movq %r0,(%fp) 429 clrl S_R2 430 movl %r3,S_R3 431 clrq S_R4 432 brw goback 433 434 435#ifdef EMULATE_INKERNEL 436# When we end up somewhere we don't want. 437die: pushl %r1 438 pushl %r0 439 calls $2,_printf 440 movl %fp,sp 441 brw goback # anything may happen 442#endif 443 444# these emodd-related 445#define TMPSIZE 0x20 /* temp bytes -- be careful with this! */ 446#define PRECIS 0x7 447#define TMPFRAC1 (%ap) 448#define TMPFRAC2 32(%ap) 449#define TMPFRACTGT 64(%ap) 450# 451# Extended multiply/modulus 452# XXX just EMODD for now 453emodd: bsbw touser 454 455 /* Clear the condition codes; we will set them as needed later. */ 456 bicl2 $(PSL_C|PSL_V|PSL_Z|PSL_N), S_PSL 457 458 /* 459 * We temporarily appropriate ap for the use of TMPFRAC*. 460 */ 461 pushl %ap 462 subl2 $(3*TMPSIZE), %sp 463 movl %sp, %ap 464 465 movc5 $0x0, TMPFRAC1, $0x0, $TMPSIZE, TMPFRAC1 466 movc5 $0x0, TMPFRAC2, $0x0, $TMPSIZE, TMPFRAC2 467 movc5 $0x0, TMPFRACTGT, $0x0, $TMPSIZE, TMPFRACTGT 468 469 clrl -(%sp) 470 movl %sp, %r3 /* %r3 = addr of exp space (1) */ 471 clrl -(%sp) 472 movl %sp, %r5 /* %r5 = addr of exp space (2) */ 473 subl2 $0x10, %sp 474 movl %sp, %r6 /* %r6 = addr of allocated target space */ 475 476 /* 477 * Now we package both numbers up and call fltext_De, which 478 * will remove the exponent and sign; this will make them 479 * easier to work with. They will be in TMPFRAC1 and 480 * TMPFRAC2 when done. 481 */ 482 bsbw getval_dfloat # get operand into %r0 and %r1 483 484 /* Check for sign = 0 and exp = 0; if it is, zeroexit. */ 485 bicl3 $0x7f, %r0, %r4 486 cmpl %r4, $0x0 487 bneq 1f 488 bsbw getval_byte # get multiplier extension operand 489 bsbw getval_dfloat # get target operand 490 jmp zeroexit 4911: 492 493 /* Check for sign = 1 and exp = 0; if it is, do a resopflt. */ 494 cmpw %r0, $0x8000 495 bneq 1f 496 bsbw getval_byte # get multiplier extension operand 497 bsbw getval_dfloat # get operand into %r0 and %r1 498 extzv $0, $0xff, %r0, %r0 # generate a resopflt -- XXX is this ok? 4991: 500 movd %r0, TMPFRACTGT 501 bicl3 $0xffff7fff, %r0, %r6 # Extract the sign while we're here. 502 bsbw getval_byte # get multiplier extension operand 503 movzbl %r0, -(%sp) 504 movd %r9, %r0 505 pushl %r3 506 pushab TMPFRAC1 507 movab TMPFRACTGT, -(%sp) 508 calls $0x4, fltext_De 509 510 bsbw getval_dfloat # get operand into %r0 and %r1 511 512 /* Check for sign = 0 and exp = 0; if it is, zeroexit. */ 513 bicl3 $0x7f, %r0, %r4 514 cmpl %r4, $0x0 515 bneq 1f 516 bsbw getval_byte # get multiplier extension operand 517 bsbw getval_dfloat # get target operand 518 jmp zeroexit 5191: 520 /* Check for sign = 1 and exp = 0; if it is, do a resopflt. */ 521 cmpw %r0, $0x8000 522 bneq 1f 523 bsbw getval_byte # get multiplier extension operand 524 bsbw getval_dfloat # get operand into %r0 and %r1 525 extzv $0, $0xff, %r0, %r0 # generate a resopflt -- XXX is this ok? 5261: 527 528 movd %r0, TMPFRACTGT 529 bicl3 $0xffff7fff, %r0, %r7 # Extract the sign while we're here. 530 movzbl $0x0, -(%sp) # no multiplier extension here 531 pushl %r5 532 pushab TMPFRAC2 533 movab TMPFRACTGT, -(%sp) 534 calls $0x4, fltext_De 535 536 /* first, add exponents */ 537 addl3 (%r5), (%r3), %r9 /* %r9 = exponent (used later) */ 538 subl2 $0x80, %r9 /* we are excess-128 */ 539 540 /* 541 * Let's calculate the target sign. Signs from multipliers are in %r6 and 542 * %r7, and both the fraction and integer parts have the same sign. 543 */ 544 xorl2 %r7, %r6 545 546 pushab TMPFRAC1 547 calls $0x1, bitcnt 548 movl %r0, %r1 /* %r1 = bitcount of TMPFRAC1 */ 549 pushab TMPFRAC2 550 calls $0x1, bitcnt 551 movl %r0, %r2 /* %r2 = bitcount of TMPFRAC2 */ 552 553 /* 554 * Now we get ready to multiply. This multiplies a byte at a time, 555 * converting to double with CVTLD and adding partial results to 556 * TMPFRACTGT. There's probably a faster way to do this. 557 */ 558 clrd TMPFRACTGT 559 pushr $0x7fc 560 subl2 $0x8, %sp /* make some temporary space */ 561 movl %sp, %r1 562 subl2 $0x8, %sp 563 movl %sp, %r2 564 565 movl $PRECIS, %r5 /* %r5 = TMPFRAC1 byte count */ 566 movl $PRECIS, %r6 /* %r6 = TMPFRAC2 byte count */ 567 clrl %r7 568 5691: 570# addl3 %r5, $TMPFRAC1, %r3 /* %r3 - current byte in tmpfrac1 */ 571 movab TMPFRAC1, %r7 572 addl3 %r5, %r7, %r3 573# addl3 %r6, $TMPFRAC2, %r4 /* %r4 - current byte in tmpfrac2 */ 574 movab TMPFRAC2, %r7 575 addl3 %r6, %r7, %r4 576 577 movzbl (%r3), %r10 578 movzbl (%r4), %r11 579 mull3 %r10, %r11, %r7 580 movl %r7, %r3 581 cvtld %r7, (%r2) 582 583 subl3 %r5, $0x8, %r8 584 subl3 %r6, $0x8, %r9 585 addl2 %r8, %r9 586 mull2 $0x8, %r9 587 subl2 $0x40, %r9 588 blss 9f 589 590 /* This may be bigger than a longword. Break it up. */ 5915: cmpl %r9, $0x1e 592 bleq 6f 593 subl2 $0x1e, %r9 594 595 ashl $0x1e, $0x1, %r8 596 cvtld %r8, (%r1) 597 muld2 (%r1), (%r2) 598 jmp 5b 5996: 600 ashl %r9, $0x1, %r8 601 cvtld %r8, (%r1) 602 muld2 (%r1), (%r2) 603 addd2 (%r2), TMPFRACTGT 604 6059: 606 cmpl %r5, $0x0 607 beql 2f 608 decl %r5 609 jmp 1b 6102: cmpl %r6, $0x0 611 beql 3f 612 decl %r6 613 movl $PRECIS, %r5 614 jmp 1b 6153: 616 617 /* 618 * At this point, %r9 might not reflect the final exponent we will use; 619 * i.e., we need post-normalization. Luckily, we still have (in %r7) 620 * the results from the last individual multiplication handy. Here 621 * we calculate how many bits it will take to shift the value in %r7 622 * so that bit 15 = 1. 623 */ 624 addl2 $0x10, %sp 625 movl %r7, 0x14(%sp) /* move %r7 onto the frame we're about to pop off */ 626 popr $0x7fc 627 628 clrl %r3 /* %r3 = counter */ 629 movl %r7, %r8 /* %r8 = temp */ 6301: 631 bicl3 $0xffff7fff, %r8, %r5 632 bneq 2f 633 incl %r3 634 ashl $0x1, %r8, %r5 635 movl %r5, %r8 636 jmp 1b 6372: 638 639 /* 640 * Now we do post-normalization (by subtracting %r3) and 641 * put the exponent (in %r9) into TMPFRACTGT. 642 */ 643 subl2 %r3, %r9 644 insv %r9, $0x7, $0x8, TMPFRACTGT 645 646 bisl2 %r6, TMPFRACTGT # set the sign 647 648 /* 649 * Now we need to separate. CVT* won't work in the case of a 650 * >32-bit integer, so we count the integer bits and use ASHQ to 651 * shift them away. 652 */ 653 cmpl $0x80, %r9 654 blss 7f /* if we are less than 1.0, we can avoid this */ 655 brw 8f 6567: 657 subl3 $0x80, %r9, %r8 658 659 movq TMPFRACTGT, TMPFRAC1 660 /* 661 * Check for integer overflow by comparing the integer bit count. 662 * If this is the case, set V in PSL. 663 */ 664 cmpl %r8, $0x20 665 blss 3f 666 bisl2 $PSL_V, S_PSL 6673: 668 cmpl %r8, $0x38 669 blss 1f 670 /* 671 * In the case where we have more than 55 bits in the integer, 672 * there aren't any bits left for the fraction. Therefore we're 673 * done here; TMPFRAC1 is equal to TMPFRACTGT and TMPFRAC2 is 0. 674 */ 675 movq $0f0.0, TMPFRAC2 676 jmp 9f /* we're done, move on */ 6771: 678 /* 679 * We do the mod by using ASHQ to shift and truncate the bits. 680 * Before that happens, we have to arrange the bits in a quadword such 681 * that the significance increases from start to finish. 682 */ 683 684 movab TMPFRACTGT, %r0 685 movab TMPFRAC1, %r1 686 movb (%r0), 7(%r1) 687 bisb2 $0x80, 7(%r1) 688 movw 2(%r0), 5(%r1) 689 movw 4(%r0), 3(%r1) 690 movb 7(%r0), 2(%r1) 691 movb 6(%r0), 1(%r1) 692 693 /* Calculate exactly how many bits to shift. */ 694 subl3 %r8, $0x40, %r7 695 mnegl %r7, %r6 696 ashq %r6, TMPFRAC1, %r0 # shift right 697 ashq %r7, %r0, TMPFRAC2 # shift left 698 699 /* Now put it back into a D_. */ 700 movab TMPFRAC2, %r0 701 movab TMPFRAC1, %r1 702 extv $0x18, $0x7, 4(%r0), (%r1) 703 extzv $0x7, $0x9, TMPFRACTGT, %r2 704 insv %r2, $0x7, $0x9, (%r1) 705 706 movw 5(%r0), 2(%r1) 707 movw 3(%r0), 4(%r1) 708 movw 1(%r0), 6(%r1) 709 710 # we have the integer in TMPFRAC1, now get the fraction in TMPFRAC2 711 subd3 TMPFRAC1, TMPFRACTGT, TMPFRAC2 712 jmp 9f 713 7148: 715 /* 716 * We are less than 1.0; TMPFRAC1 should be 0, and TMPFRAC2 should 717 * be equal to TMPFRACTGT. 718 */ 719 movd $0f0.0, TMPFRAC1 720 movd TMPFRACTGT, TMPFRAC2 7219: 722 /* 723 * We're done. We can use CVTDL here, since EMODD is supposed to 724 * truncate. 725 */ 726 cvtdl TMPFRAC1, %r4 727 bsbw getaddr_byte 728 movl %r4, (%r0) 729 730 bsbw getaddr_byte 731 movq TMPFRAC2, (%r0) 732 movd TMPFRAC2, %r0 /* move this here so we can test it later */ 733 734 /* Clean up sp. */ 735 736 addl2 $0x74, %sp 737 movl (%sp)+, %ap 738 739 /* 740 * Now set condition codes. We know Z == 0; C is always 0; and V 741 * is set above as necessary. Check to see if TMPFRAC2 is 742 * negative; if it is, set N. 743 */ 744 tstd %r0 745 bgeq 1f /* branch if N == 0 */ 746 bisl2 $PSL_N, S_PSL 7471: 748 brw goback 749zeroexit: 750 /* Z == 1, everything else has been cleared already */ 751 bisl2 $PSL_Z, S_PSL 752 bsbw getaddr_byte 753 movl $0x0, (%r0) 754 bsbw getaddr_byte 755 movd $0f0, (%r0) 756 brw goback 757 758 759 760/* 761 * bitcnt: counts significant bits backwards in a quadword 762 * returns number of bits, unless there aren't any; 763 * in that case it will return $0xffffffff 764 */ 765bitcnt: 766 .word 0xffe /* %r1-%r12 */ 767 768 /* 769 * Our goal is to factor a common power of 2 out of each of the 770 * two factors involved in the multiplication. Once we have that, 771 * we can multiply them as integers. More below. 772 * Right now we are counting bits, starting from the highest octet 773 * of each (the *least* significant bit at this point!) and doing 774 * FFSes until we find a bit set. 775 */ 776 movl 4(%ap), %r0 777 movl $0x8, %r1 7781: decl %r1 779 addl3 %r1, %r0, %r4 780 movzbl (%r4), %r2 781 ffs $0, $0x20, %r2, %r3 782 bneq 2f /* if we found a bit, Z == 0, continue */ 783 cmpl %r1, $0x0 784 jeql 3f /* if %r1 is zero and there's no bit set, qw is 0 */ 785 jmp 1b /* else continue with the loop */ 786 7872: /* 788 * We found a bit; its position in the byte is in %r3, and %r1 is the 789 * position of the byte in the quadword. 790 */ 791 subl3 %r3, $0x8, %r0 792 ashl $0x5, %r1, %r2 793 addl2 %r2, %r0 794 ret 795 7963: /* this quadword is 0 */ 797 movl $0xffffffff, %r0 798 ret 799 800 801/* 802 * The fltext_X routines separate fraction and exponent* bits. 803 * They return (via %r0) the amount of bits in the fraction. 804 * 805 * *: exponents are left in excess-128 form 806 * D_ floating point first word: 807 * F E 7 6 0 808 * +-+--------+-------+ 809 * sign-> |s|exponent| fract.| (10-3F = fraction bits) 810 * +-+--------+-------+ 811 * Significance order: 0-6, 10-1F, 20-2F, 30-3F 812 * 813 * The fourth argument to fltext_De is the eight extra bits for use 814 * in EMOD*, et al. If these bits are not in use, specify 0. 815 */ 816fltext_De: 817 .word 0x831 # %r0 %r1 %r2 %r3 %r4 ap (no return) 818 819 movl 0x4(%ap), %r0 # %r0 - addr of source 820 movl 0x8(%ap), %r1 # %r1 - addr of fraction destination 821 822 movb (%r0), (%r1) 823 bisb2 $0x80, (%r1)+ # This is the hidden bit. 824 825 movb 3(%r0), (%r1)+ 826 movb 2(%r0), (%r1)+ 827 movb 5(%r0), (%r1)+ 828 movb 4(%r0), (%r1)+ 829 movb 7(%r0), (%r1)+ 830 movb 6(%r0), (%r1)+ 831 832 /* 833 * if there are extension bits (EMOD EDIV etc.) they are 834 * low-order 835 */ 836 movb 0x10(%ap), (%r1) 837 838 movl 0x4(%ap), %r0 # %r0 - addr of source 839 movl 0xc(%ap), %r2 # %r2 - addr of exponent destination 840 extzv $0x7, $0x8, (%r0), (%r2) # get exponent out 841 ret 842 843