Annotation of pgp/src/vax.mar, revision 1.1.1.1

1.1       root        1: ;Last Modified:  16-APR-1992 09:06:30.46
                      2:        .title  fprims  Fast Multiple Precision Primitives
                      3:        .ident  /V1.7B/
                      4: ;+
                      5: ; **-FPRIMS-Fast Multiple Precision Primitives
                      6: ;
                      7: ; Facility:     PGP
                      8: ;
                      9: ; Language:     Macro-32
                     10: ;
                     11: ; Functional Description:
                     12: ;
                     13: ; This module contains fast multiple precision routines for operating on arrays
                     14: ; of long words. Error checking is minimised at the expense of speed.
                     15: ;
                     16: ; Restrictions:
                     17: ;
                     18: ; This code is shareable but NOT reentrant as written because of static data.
                     19: ; A reentrant version of this module could be written but it would be slower!
                     20: ;
                     21: ; Version:      1
                     22: ;
                     23: ; Original:     00A     Date:   17-Sep-1991     Author: Hugh A.J. Kennedy
                     24: ;
                     25: ; Based on FPRIMS.ASM written by Zhahai Stewart for the Intel 8086
                     26: ; architecture.
                     27: ;
                     28: ; Modification: 02A     Date:   27-Sep-1991     Author: Hugh A.J. Kennedy.
                     29: ;
                     30: ; Add fast multiply routine, P_SMUL.
                     31: ; Re-organise code slightly.
                     32: ; Ammend/clarify copyright and license statement.
                     33: ; Add checking for maximum precision exceeded, display a warning message
                     34: ; and bomb!
                     35: ;
                     36: ; Modification: 03A     Date:   16-Mar-1992     Author: Hugh A.J. Kennedy.
                     37: ;
                     38: ; Sniff for MSB in P_SMUL. In this way, avoid multiplies by leading zeroes
                     39: ; (not efficient).
                     40: ;
                     41: ; Modification: 05A     Date:   17-Mar-1992     Author: Hugh A.J. Kennedy.
                     42: ;
                     43: ; Encode entire double precision multiply in VAX assembler.
                     44: ; Correct some minor problems with handling embedded zeroes.
                     45: ;
                     46: ; Modification: 06A     Date:   17-Mar-1992     Author: Hugh A.J. Kennedy
                     47: ;
                     48: ; Align everything for speed. VAXen like stuff on 64-bit, or at least 32-bit
                     49: ; boundaries. Therefore, we align the add, subtract and rotate tables and then
                     50: ; we align the multiply loops. The extra NOPs used to pad these loops are of
                     51: ; negligable cost because they already exist in the memory buffer. When the
                     52: ; following instruction is aligned, it executes MUCH faster.
                     53: ;
                     54: ; Modification: 07A     Date:   24-Mar-1991     Author: Hugh A.J. Kennedy.
                     55: ;
                     56: ; Implement fast compare.
                     57: ;-
                     58: 
                     59:        .sbttl  Copyright Notice And License To Use
                     60: ;
                     61: ;                 Copyright (c) 1991-1992, All Rights Reserved by
                     62: ;                            Hugh A.J. Kennedy.
                     63: ;
                     64: ;       A license to use and adapt this software without payment is hereby 
                     65: ;       granted subject to the following conditions:
                     66: ;
                     67: ;       1) It may only be copied with the inclusion of this copyright
                     68: ;       notice in the program source with these associated conditions.
                     69: ;
                     70: ;       2) No title to or ownership of this software is hereby 
                     71: ;       transferred.
                     72: ;
                     73: ;       3) The  information  in this software is subject  to change 
                     74: ;       without notice and should  not be construed as a  commitment  by  
                     75: ;       Hugh Kennedy.
                     76: ;
                     77: ;       4) The author assumes no liability for any damages arising from the 
                     78: ;       use of this software, even if said damages  arises from defects in 
                     79: ;       this software.
                     80: ;
                     81: ;       5) No warranty as to merchantability or fitness of purpose is 
                     82: ;       expressed or implied.
                     83: ;
                     84: ;       6) Any modifications to this source must be clearly identified as
                     85: ;       such and added to the modification history.
                     86: ;
                     87: ;       7) These routines may not be incorporated in a commercial cryptographic
                     88: ;       product.
                     89: ;
                     90: ; If you can not comply with these conditions, you *must* contact the author
                     91: ; and obtain permission other wise you are in violation of copyright.
                     92: 
                     93:        .sbttl  Misc Macros & Definitions
                     94: ;
                     95: ; Assembly Parameters
                     96: ;
                     97: max_unit_prec   =       72                      ; Maximum unit precision
                     98: supersniffer    =       1                       ; Enable bit msb locator.
                     99: ;
                    100: ; The following parameter is dependent on the kind of VAX you are running on
                    101: ; and should be defined if the execution time of the SOBGTR loop control
                    102: ; instruction and the appropriate operation (ADWC or SBWC) from cache is much
                    103: ; less than the execution time in main memory. If you have a slow VAX you
                    104: ; should comment the following line out to use a vector of instructions.
                    105: ;
                    106: novector        =       1                       ; Use loops rather than vectors.
                    107: 
                    108: .macro  ascid   .string
                    109: ;+
                    110: ; *-ASCID-Build An ASCII String Referenced By Descriptor
                    111: ;
                    112: ; Functional Description:
                    113: ;
                    114: ;       This macro is a little like the system supplied .ASCID directive
                    115: ; but it uses a separate program section to store the ASCII data.
                    116: ;
                    117: ; Arguments:
                    118: ;
                    119: ;       STRING          String to create
                    120: ;-
                    121:        .nocross
                    122: 
                    123:        .save_psect
                    124: 
                    125:        .psect  puret
                    126: 
                    127: $$$t0   =       .
                    128:        .ascii  @.string@
                    129: $$$t1   =       .-$$$t0
                    130: 
                    131:        .restore_psect
                    132: 
                    133:        .word   $$$t1
                    134:        .byte   dsc$k_dtype_t
                    135:        .byte   dsc$k_class_s
                    136:        .address -
                    137:                $$$t0
                    138:        .cross
                    139: 
                    140: .endm   ascid
                    141: 
                    142:        .sbttl  Misc Data Areas
                    143: ;
                    144: ; Misc. Data Areas
                    145: ;
                    146:        .psect  impurd,con,lcl,noshr,exe,rd,wrt,long
                    147: 
                    148: ;
                    149: ; This data is static and is used to hold the current precision established
                    150: ; by P_SETP for other calls to this library.
                    151: ;
                    152: .if not_defined novector
                    153: 
                    154: addoff:                                         ; Offset into add table.
                    155:        .blkl   1                               ; also for sub and rot.
                    156: .endc
                    157: 
                    158: precis:                                         ; Precision in longwords.
                    159:        .blkl   1
                    160: 
                    161:        .psect  pure,con,rel,shr,exe,rd,nowrt,quad
                    162: 
                    163:        .align  quad
                    164: 
                    165: .ifndef novector
                    166: 
                    167: prectoobig:
                    168:        ascid   <PGP (FPRIMS) - Requested precision (!ZL) exceeds capacity (!ZL)>
                    169: 
                    170: .endc
                    171: 
                    172:        .sbttl  Start of Code
                    173: 
                    174:        .sbttl  P_CMP           Compare two very long integers
                    175: ;+
                    176: ; **-P_COMP-Compare two very long integers
                    177: ;
                    178: ; Functional Description:
                    179: ;
                    180: ; This procedure is invoked to compare two extended precision unsigned
                    181: ; integers.
                    182: ;
                    183: ; Calling Sequence
                    184: ;
                    185: ;       short P_CMP ( r1, r2)
                    186: ;
                    187: ; Parameters:
                    188: ;
                    189: ;       R1      ->      Extended Precision Integer 1
                    190: ;       R2      ->      Extended Precision Integer 2
                    191: ;
                    192: ; Implicit Inputs:
                    193: ;
                    194: ;       PRECIS          lr*r    Precision expresses in longs.
                    195: ;
                    196: ; Returns:
                    197: ;
                    198: ;       -1      if r1 < r2
                    199: ;        0      if r1 = r2
                    200: ;       +1      if r1 > r2
                    201: ;
                    202: 
                    203: ;-
                    204: 
                    205:        .align  long
                    206: 
                    207:        .entry  p_cmp,^m<r2>
                    208: 
                    209:        movl    4(ap),r1                        ; R1 -> Sum.
                    210:        movl    8(ap),r2                        ; R2 -> Addend.
                    211:        movl    precis,r0                       ; R0 = Precision.
                    212:        moval   (r1)[r0],r1                     ; Get MS longwords.
                    213:        moval   (r2)[r0],r2                     ; Get MS longwords.
                    214: .align  long    1                               ; Align loop with NOPS.
                    215: 10$:    cmpl    -(r1),-(r2)                     ; Compare.
                    216:        bnequ   20$                             ; If ne, then exit loop.
                    217:        sobgtr  r0,10$                          ; Loop until done.
                    218:        ret                                     ; R0 = zero so R1 = R2.
                    219: 20$:
                    220:        bgtru   30$                             ; If R1 > R2 then branch.
                    221:        movw    #-1,r0                          ; Flag <.
                    222:        ret
                    223: 30$:
                    224:        movw    #1,r0                           ; Flag >.
                    225:        ret
                    226: 
                    227:        .sbttl  P_ADDC          Add two very long integers with carry
                    228: ;+
                    229: ; **-P_ADDC-Add very long integers
                    230: ;
                    231: ; Functional Description:
                    232: ;
                    233: ; This procedure is invoked to add two very long integers with carry. Each
                    234: ; integer is represented as an array of longwords, least significant first.
                    235: ;
                    236: ; Calling Sequence:
                    237: ;
                    238: ;       P_ADDC  sum,addend,carry
                    239: ;
                    240: ; Parameters:
                    241: ;
                    242: ;       sum             lm*r            Sum.
                    243: ;       addend          lr*r            Addend.
                    244: ;       carry           lr*v            Carry bit.
                    245: ;
                    246: ; Implicit Inputs:
                    247: ;
                    248: ;       Addoff          This is used as an offset into the various tables
                    249: ;                       of adds, subtracts and rotates to implement the
                    250: ;                       operation to the requested precsion.
                    251: ;
                    252: ; Status Returns:
                    253: ;
                    254: ;       R0      Resulting carry bit.
                    255: ;-
                    256: 
                    257:        .align  long
                    258: 
                    259:        .entry  p_addc,^m<r2,r3>
                    260: 
                    261:        movl    4(ap),r1                        ; R1 -> Sum.
                    262:        movl    8(ap),r2                        ; R2 -> Addend.
                    263: 
                    264: .if defined novector
                    265: 
                    266:        movl    precis,r3                       ; R3 = Precision.
                    267:        subl3   12(ap),#0,r0                    ; Set carry bit.
                    268:        .align  quad,1                          ; Align loop with NOPs
                    269: 10$:    adwc    (r2)+,(r1)+                     ; Add with carry one longword.
                    270:        .align  quad,1                          ; Align next instruction.
                    271:        sobgtr  r3,10$                          ; Loop until done.
                    272: 
                    273: .iff ; novector
                    274: 
                    275:        moval   10$,r3
                    276:        addl2   addoff,r3                       ; Jump into table.
                    277:        subl3   12(ap),#0,r0                    ; Set carry bit.
                    278:        jmp     (r3)
                    279: 
                    280:        .align  quad
                    281: 
                    282: 10$:
                    283:        .rept   max_unit_prec
                    284: $$$     =       .
                    285:        adwc    (r2)+,(r1)+                     ; Add with carry one longword.
                    286:        nop
                    287: addsiz  =       .-$$$
                    288:        .endr
                    289: 
                    290: .endc ; novector
                    291: 
                    292:        clrl    r0                              ; Assume carry clear.
                    293:        bcc     20$                             ; Carry set?
                    294:        incl    r0                              ; Flag carry was set.
                    295: 20$:    ret
                    296: 
                    297:        .sbttl  P_SUBB  Subtract very long integers with borrow
                    298: ;+
                    299: ; **-P_SUBB-Subtract very long integers
                    300: ;
                    301: ; Functional Description:
                    302: ;
                    303: ; This procedure is invoked to add subtract very long integers with carry. Each
                    304: ; integer is represented as an array of longwords, least significant first.
                    305: ;
                    306: ; Calling Sequence:
                    307: ;
                    308: ;       P_SUBB  diff,sub,borrow
                    309: ;
                    310: ; Parameters:
                    311: ;
                    312: ;       diff            lm*r            Difference
                    313: ;       sub             lr*r            Subtrahend.
                    314: ;       borrow          lr*v            Borrow bit.
                    315: ;
                    316: ; Implicit Inputs:
                    317: ;
                    318: ;       Addoff          This is used as an offset into the various tables
                    319: ;                       of adds, subtracts and rotates to implement the
                    320: ;                       operation to the requested precsion.
                    321: ;
                    322: ; Status Returns:
                    323: ;
                    324: ;       R0      Resulting carry bit.
                    325: ;-
                    326: 
                    327:        .align  long
                    328: 
                    329:        .entry  p_subb,^m<r2,r3>
                    330: 
                    331:        movl    4(ap),r1                        ; R1 -> Difference.
                    332:        movl    8(ap),r2                        ; R2 -> Minuend.
                    333: 
                    334: .if defined novector
                    335: 
                    336:        movl    precis,r3                       ; R3 = No. of longs.
                    337:        subl3   12(ap),#0,r0                    ; Set borrow bit.
                    338:        .align  quad,1                          ; Align loop with NOPs.
                    339: 10$:    sbwc    (r2)+,(r1)+                     ; Subtract with borrow one long.
                    340:        .align  quad,1                          ; Align with NOPs.
                    341:        sobgtr  r3,10$                          ; Loop through.
                    342: 
                    343: .iff ; novector
                    344: 
                    345:        moval   10$,r3
                    346:        addl2   addoff,r3                       ; Jump into table.
                    347:        subl3   12(ap),#0,r0                    ; Set borrow bit.
                    348:        jmp     (r3)
                    349: 
                    350:        .align  quad
                    351: 10$:
                    352:        .rept   max_unit_prec
                    353:        sbwc    (r2)+,(r1)+                     ; Subtract w/carry one longword.
                    354:        nop
                    355:        .endr
                    356: 
                    357: .endc ; novector
                    358: 
                    359:        clrl    r0                              ; Assume carry clear.
                    360:        bcc     20$                             ; Carry set?
                    361:        incl    r0                              ; Flag carry was set.
                    362: 20$:    ret
                    363: 
                    364:        .sbttl  P_ROTL  Rotate left a very long integer with carry.
                    365: ;+
                    366: ; **-P_ROTL-Rotate left one bit very long integers
                    367: ;
                    368: ; Functional Description:
                    369: ;
                    370: ; This procedure is invoked to rotate left one bit (e.g. divide by 2) very 
                    371: ; long integers with carry. Each integer is represented as an array of 
                    372: ; longwords, least significant first. Note that we use the add with carry
                    373: ; instruction here because the VAX (unlike the dear old PDP-11) lacks a
                    374: ; rotate instruction that includes the carry bit.
                    375: ;
                    376: ; Calling Sequence:
                    377: ;
                    378: ;       P_ROTL  num,carry
                    379: ;
                    380: ; Parameters:
                    381: ;
                    382: ;       num             lm*r            Number to be shifted
                    383: ;       carry           lr*v            Carry bit.
                    384: ;
                    385: ; Implicit Inputs:
                    386: ;
                    387: ;       Addoff          This is used as an offset into the various tables
                    388: ;                       of adds, subtracts and rotates to implement the
                    389: ;                       operation to the requested precsion.
                    390: ;
                    391: ; Status Returns:
                    392: ;
                    393: ;       R0      Resulting carry bit.
                    394: ;-
                    395: 
                    396:        .align  long
                    397: 
                    398:        .entry  p_rotl,^m<r3>
                    399: 
                    400:        movl    4(ap),r1                        ; R1 -> Sum.
                    401: 
                    402: .if defined novector
                    403: 
                    404:        movl    precis,r3                       ; R3 = No. of longwords.
                    405:        subl3   8(ap),#0,r0                     ; Set carry bit.
                    406:        .align  quad,1                          ; Align loop with NOPs
                    407: 10$:    adwc    (r1),(r1)+                      ; Add to itself with carry.
                    408:        .align  quad,1                          ; Align with NOPs.
                    409:        sobgtr  r3,10$                          ; Loop until done.
                    410: 
                    411: .iff ; novector
                    412: 
                    413:        moval   10$,r3
                    414:        addl2   addoff,r3                       ; Jump into table.
                    415:        subl3   8(ap),#0,r0                     ; Set carry bit.
                    416:        jmp     (r3)
                    417: 
                    418:        .align  quad
                    419: 10$:
                    420:        .rept   max_unit_prec
                    421:        adwc    (r1),(r1)+                      ; *2+carry.
                    422:        nop
                    423:        .endr
                    424: 
                    425: .endc ; novector
                    426:        clrl    r0                              ; Assume carry clear.
                    427:        bcc     20$                             ; Carry set?
                    428:        incl    r0                              ; Flag carry was set.
                    429: 20$:    ret
                    430: 
                    431:        .sbttl  P_DMUL  Extended Multiple Precision Multiply
                    432: ;*
                    433: ; **-P_DMUL-Extended Multiple Precision Multiply
                    434: ;
                    435: ; Functional Description:
                    436: ;
                    437: ; This procedure multiplies an unsigned single precision multiplier by a 
                    438: ; single precision multiplicand. The product register is double precision.
                    439: ; It is expected that the length of the single precision multiplier and
                    440: ; multiplicand has been previously set by a call to P_SETP. Note that the
                    441: ; entire length of the product register is zeroed - so it must be a full
                    442: ; double precision size.
                    443: ;
                    444: ; Calling Sequence:
                    445: ;
                    446: ;       P_DMUL  prod, multiplicand, multiplier
                    447: ;
                    448: ; Parameters:
                    449: ;
                    450: ;       prod            lw*r    Product.
                    451: ;       multuplicand    lr*r    Multiplicand
                    452: ;       multiplier      lr*r    Multiplier
                    453: ;
                    454: ; Implicit Inputs:
                    455: ;
                    456: ;       PRECIS          lr*r    Precision expresses in longs.
                    457: ;
                    458: ; Status Returns:
                    459: ;
                    460: ;       None.
                    461: ;-
                    462: 
                    463:        .align  long
                    464: 
                    465:        .entry  p_dmul,^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
                    466: 
                    467:        movl    4(ap),r8                        ; R8 -> Product.
                    468:        beql    49$                             ; If eq, not specified.
                    469:        movl    precis,r10                      ; R10 = Precision (longs)
                    470:        ashl    #3,r10,r2                       ; R0 = No. of bytes to zero.
                    471:        movc5   #0,#0,#0,r2,(r8)                ; Zero product buffer.
                    472:        movl    8(ap),r3                        ; R3 -> Multiplicand.
                    473:        beql    49$                             ; If eq, not specified.
                    474:        pushl   r3                              ; Save for posterity.
                    475:        movl    12(ap),r11                      ; R11 -> Multiplier.
                    476:        beql    49$                             ; If eq, not specified.
                    477:        movl    r10,r12                         ; R12 = Multiplicand prec.
                    478: 
                    479: .if     defined SUPERSNIFFER
                    480: 
                    481: ;
                    482: ; Here we calculate the effective maximum precision for the multiply by
                    483: ; locating the long containing the most significant bit of the multiplier
                    484: ; and the multiplicand.
                    485: ;
                    486:        moval   (r11)[r10],r0                   ; Supersniffer...
                    487:        .align  quad,1                          ; Align with nops
                    488: 45$:    tstl    -(r0)                           ; Examine next long.
                    489:        bneq    50$                             ; If ne, then we found msb.
                    490:        sobgtr  r10,45$                         ; Loop until done.
                    491: 49$:    ret                                     ; Multiplier = 0!
                    492: 50$:
                    493:        moval   (r3)[r12],r0                    ; Supersniffer...
                    494:        .align  quad,1                          ; Align with nops
                    495: 55$:    tstl    -(r0)                           ; Examine next long.
                    496:        bneq    200$                            ; If ne, then we found msb.
                    497:        sobgtr  r12,55$                         ; Loop until done.
                    498:        ret                                     ; Multiplicand = 0!
                    499: .iff
                    500: 
                    501:        brb     200$
                    502: 49$:
                    503:        ret
                    504: 
                    505: .endc   ; SUPERSNIFFER
                    506: 
                    507: ;
                    508: ; Multiplier Loop
                    509: ;
                    510: ; R12 = Count of multiplicand longs to process.
                    511: ; R11 -> Next long of multiplier.
                    512: ; R10 = Count of multiplier longs to process.
                    513: ; R8 -> Next long of product.
                    514: ;
                    515:        .align  quad,1                          ; Align with nops
                    516: 200$:   movl    r12,r5                          ; Multiplicand precision.
                    517:        moval   (r8)+,r4                        ; R4 -> Next long of product.
                    518:        movl    (sp),r3                         ; R3 -> 1st multiplier long.
                    519:        movl    (r4),r0                         ; R0,R1 = Partial Sum.
                    520:        movl    4(r4),r1
                    521:        clrl    r7                              ; Zero look-ahead carry.
                    522: ;
                    523: ; Perform an extended multiply of two unsigned numbers. This means that
                    524: ; we have to compensate the hi-order product because either the multiplier
                    525: ; or the multiplicand may be apparently a negative number. EMUL is a signed
                    526: ; multiply - so we must be careful. Also, the EMUL longword addend is sign 
                    527: ; extended before adding into the product so we have to add the hard way.
                    528: ;
                    529: ; R6 =          Current Multiplicand
                    530: ; R2 =          Multiplier
                    531: ; R4 ->         Current quadword of partial product.
                    532: ; R0,R1 =       Partial sum to which product is added
                    533: ; R7 =          Lookahead carry. This gets set if we try to carry after adding
                    534: ;               the partial product to the partial sum. This gets a little more
                    535: ;               complicated because here we are setting the high-order long of
                    536: ;               the next quadword to be operated on.
                    537: ;
                    538: ; Essentially the algorithm is as follows:
                    539: ;
                    540: ; 0) R0,R1 = (R4)               ; Save current partial sum.
                    541: ; 1) R6 = Next longword of multiplicand.
                    542: ; 2) (R4) = R6 * R2             ; quad result compensating for negative numbers)
                    543: ; 3) (R4) = (R4) + R0,R1        ; add back partial sum.
                    544: ; 4) R7 = Carry bit.
                    545: ; 5) R4 = R4 + 4                ; Point to next long.
                    546: ; 6) R1 = 4(R4) + R7            ; Propagate carry to high order of next partial
                    547: ;                               ; sum.
                    548: ; 7) Loop back to step 1 until multiplicand completely processed.
                    549: ;
                    550:        movl    (r11)+,r2                       ; R2 = Multiplier.
                    551:        beql    999$                            ; If eq, not specified.
                    552:        blss    1500$                           ; This unfolds the compensation
                    553:                                                ; test out of the loop.
                    554: ;
                    555: ; This version of the multiply loop is entered when the multiplier is positive
                    556: ; saving three instructions per unit of precision.
                    557: ;
                    558:        .align  quad,1                          ; Align with NOPs.
                    559: 500$:   movl    (r3)+,r6                        ; R6 = Current multplicand.
                    560:        emul    r2,r6,#0,(r4)                   ; Multiply (64-bit result).
                    561: ;
                    562: ; Because we have removed leading zeroes, multiplication by zero is very
                    563: ; unlikely, 1 in 2^32 or so. It is therefore easier to perform the test after
                    564: ; the EMUL (looking at the zero product) that the multiplicand was zero so we 
                    565: ; don't need any special case logic later to adjust the product pointer.
                    566: ;
                    567:        beql    550$                            ; If result eq, skip.
                    568:        tstl    r6                              ; Was multiplicand negative?
                    569:        bgeq    550$                            ; No, skip.
                    570:        addl2   r2,4(r4)                        ; Yes, compensate.
                    571: 550$:   addl2   r0,(r4)+                        ; Accumulate.
                    572:        adwc    r1,(r4)+
                    573:        movl    (r4),r1                         ; R1 = Next hi-end partial sum.
                    574:        adwc    r7,r1                           ; Add carry if needed.
                    575:        clrl    r7                              ; Reset lookahead register.
                    576:        adwc    #0,r7                           ; Save lookahead carry.
                    577:        movl    -(r4),r0                        ; R0 = Next lo-end partial.
                    578:        sobgtr  r5,500$                         ; More units?
                    579: 999$:   sobgtr  r10,200$                        ; Nope, go get next multiplier
                    580:        ret
                    581: ;
                    582: ; This version of the above multiply loop is entered when the multiplier is
                    583: ; negative - and we must compensate by adding the multiplicand to the hi-order
                    584: ; product. This saves a test and a conditional branch per unit of precision.
                    585: ;
                    586:        .align  quad,1                          ; Align with NOPs.
                    587: 1500$:
                    588:        movl    (r3)+,r6                        ; R6 = Current multplicand.
                    589:        emul    r2,r6,#0,(r4)                   ; Multiply (64-bit result).
                    590: ;
                    591: ; Because we have removed leading zeroes, multiplication by zero is very
                    592: ; unlikely, 1 in 2^32 or so. It is therefore easier to perform the test after
                    593: ; the EMUL (looking at the zero product) that the multiplicand was zero so we 
                    594: ; don't need any special case logic later to adjust the product pointer.
                    595: ;
                    596:        beql    1560$                           ; If result eq, skip.
                    597:        tstl    r6                              ; Was multiplicand negative?
                    598:        bgeq    1550$                           ; No, skip.
                    599:        addl2   r2,4(r4)                        ; Yes, compensate.
                    600: 1550$:
                    601: ; As documented above, we unfolded the following to save instructions
                    602: ;       tstl    r2                              ; Multiplier negative?
                    603: ;       bgeq    1560$                           ; No, skip.
                    604:        addl2   r6,4(r4)                        ; Yes, compensate.
                    605: 1560$:  addl2   r0,(r4)+                        ; Accumulate.
                    606:        adwc    r1,(r4)+                        ; R1 = High-end partial sum.
                    607:        movl    (r4),r1                         ; R1 = Next hi-end partial sum.
                    608:        adwc    r7,r1                           ; Add carry if needed.
                    609:        clrl    r7                              ; Reset lookahead register.
                    610:        adwc    #0,r7                           ; Save lookahead carry.
                    611:        movl    -(r4),r0                        ; R0 = Next lo-end partial.
                    612:        sobgtr  r5,1500$                        ; More units?
                    613:        sobgtr  r10,200$                        ; Nope, go get next multiplier
                    614:        ret
                    615: 
                    616:        .sbttl  P_SETP          Set Precison.
                    617: ;+
                    618: ; **-P_SETP-Set Precision
                    619: ;
                    620: ; Functional Description:
                    621: ;
                    622: ; This procedure is invoked to set the operating precision of the package.
                    623: ;
                    624: ; Calling Sequence:
                    625: ;
                    626: ;       P_SETP  nbits
                    627: ;
                    628: ; Parameters:
                    629: ;
                    630: ;       nbits           rw*v    Number of bits in number.
                    631: ;
                    632: ; Implicit Outputs:
                    633: ;
                    634: ;       Precis          Set to the number of longwords required to implement
                    635: ;                       the requested precision.
                    636: ;       Addoff          This is used as an offset into the various tables
                    637: ;                       of adds, subtracts and rotates to implement the
                    638: ;                       operation to the requested precsion.
                    639: ;
                    640: ; Status Returns:
                    641: ;
                    642: ;       None.
                    643: ;
                    644: ; Side Effects:
                    645: ;
                    646: ;       If the maximum precision set in 32-bit units by the assembly
                    647: ;       parameter "max_unit_prec" is exceeded, a message to that effect will
                    648: ;       be displayed and the program will terminate with a fatal error.
                    649: ;-
                    650: 
                    651:        .entry  p_setp,^m<>
                    652: 
                    653:        movzwl  4(ap),r1                        ; R1 = No. of bits.
                    654:        addl2   #31,r1                          ; Round up to next long word.
                    655:        ashl    #-5,r1,r1                       ; R1 = No. of 32 bit words.
                    656:        movl    r1,precis                       ; Save precision.
                    657: 
                    658: .if not_defined novector
                    659: 
                    660:        subl3   r1,#max_unit_prec,r0            ; R0 = Number of steps reqd.
                    661:        blss    10$                             ; If > 0 then exit.
                    662:        mull3   #addsiz,r0,addoff               ; Get add table offset.
                    663: 
                    664: .iftf ; novector
                    665: 
                    666:        ret
                    667: 
                    668: .ift ; novector
                    669: 
                    670: 10$:                                            ; Table size exceeded!
                    671:        movab   -80(sp),sp                      ; Output buffer.
                    672:        pushab  (sp)                            ; Build descriptor
                    673:        movzwl  #80,-(sp)
                    674:        clrl    -(sp)                           ; Receive return length.
                    675:        pushl   #max_unit_prec                  ; Compiled max table size.
                    676:        pushl   r1                              ; Requested table size.
                    677:        pushaq  8+4(sp)                         ; -> Output buffer descriptor.
                    678:        pushaw  12(sp)                          ; -> Returned length.
                    679:        pushaq  prectoobig                      ; -> FAO control string.
                    680:        calls   #5,g^sys$fao                    ; Format output string.
                    681:        movl    (sp)+,(sp)                      ; Set actual buffer size.
                    682:        pushaq  (sp)                            ; -> Output buffer descr.
                    683:        calls   #1,g^lib$put_output             ; Output message.
                    684:        $exit_s -                               ; Exit with severe error.
                    685:                code=#4
                    686: 
                    687: .endc ; novector
                    688: 
                    689:        .end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.