[BACK]Return to unimpl_emul.s CVS log [TXT][DIR] Up to [local] / sys / arch / vax / vax

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