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