--- pgp/src/8086.asm 2018/04/24 16:37:53 1.1.1.1 +++ pgp/src/8086.asm 2018/04/24 16:41:15 1.1.1.3 @@ -1,8 +1,11 @@ ; Assembly primitives for RSA multiprecision library -; +; ; Tested with Turbo Assembler 1.0 and masm 1.00 -; +; ; Written by Branko Lankester (lankeste@fwi.uva.nl) 10/10/91 +; +; Modified to add, rather than store carry bit to allow using a +; smaller precision for long division. ; define LDATA and LCODE as follows: ; model: small compact medium large @@ -12,6 +15,9 @@ LDATA equ 1 LCODE equ 1 +; Note: Only the large memory model has been implemented for P_SMULA, +; P_SETRECIP and P_QUO_DIGIT. + IF LDATA DSTPTR equ es:[bx+si] ELSE @@ -44,6 +50,9 @@ scarry equ [bp+6] ENDIF ENDIF +IF NOT LCODE +UPTON_TEXT = _TEXT +ENDIF _TEXT segment byte public 'CODE' DGROUP group _DATA,_BSS @@ -67,6 +76,7 @@ _TEXT segment byte public 'CODE' public _P_SETP public _P_ADDC public _P_SUBB + public _P_MUSUBB public _P_ROTL IF LCODE @@ -93,7 +103,7 @@ _P_SETP: and ax,0fh ; al = prec % 16 mov bx,ax mov cx,ax - shl bx,1 ; multiply by 4 (=number of bytes + shl bx,1 ; multiply by 4 (=number of bytes shl bx,1 ; in instruction sequence) mov dx,bx IFE LDATA @@ -183,6 +193,7 @@ SUBU macro n endm +_P_MUSUBB: ; MULTUNIT is same size as unit _P_SUBB: push bp mov bp,sp @@ -266,12 +277,11 @@ ENDIF fprims endp -_TEXT ends ; *************************************************************** -; P_SMUL (MULTUNIT *prod, MULTUNIT *multiplicand, MULTUNIT multiplier) +; P_SMULA (MULTUNIT *prod, MULTUNIT *multiplicand, MULTUNIT multiplier) ; mp_smul routine from Upton's modmult, converted to assembler ; ; Multiply the single-word multiplier times the multiprecision integer @@ -285,6 +295,9 @@ _TEXT ends ; regardless of byte order of the machine. On an 80x86, this makes ; no difference. But if this assembly function is implemented ; on a 680x0, it becomes important. +; +; This version differs from P_SMUL by adding in, rather than storing, +; the final carry. This better supports use by Smith's modmult. ; *************************************************************** ; Variable assignments: ; multiplier = [bp+14] @@ -293,12 +306,8 @@ _TEXT ends ; unit_prec = cx ; p = ax-dx ; carry = bx -UPTON_TEXT SEGMENT WORD PUBLIC 'CODE' -UPTON_TEXT ENDS -UPTON_TEXT SEGMENT - ASSUME CS: UPTON_TEXT - ASSUME DS: DGROUP - PUBLIC _P_SMUL + + PUBLIC _P_SMULA MULU macro n rept n @@ -313,7 +322,7 @@ MULU macro n endm endm -_P_SMUL PROC FAR +_P_SMULA PROC FAR push bp mov bp,sp push di @@ -344,16 +353,166 @@ mul_units: MULU 15 mul_ref: - ; We know that the high-order word of prod will always be 0 - mov WORD PTR es:[di],bx ;store carry in prod empty high word + add WORD PTR es:[di],bx ;add final carry pop ds pop si pop di pop bp - ret + ret +_P_SMULA ENDP + +; *************************************************************** +; void P_SETRECIP (MULTUNIT reciph, MULTUNIT recipl, short mshift) +; Specify reciprocal factors for use by P_QUO_DIGIT. +; +; This implementation is for 16-bit MULTUNIT. +; +; *************************************************************** + +DGROUP group _DATA,_BSS + assume ds:DGROUP +_BSS segment word public 'BSS' +reciph dw ? ; recip msw +recipl dw ? ; recip lsw +mshift dw ? ; shift adjust +_BSS ends + + PUBLIC _P_SETRECIP + +_P_SETRECIP PROC FAR + push bp + mov bp,sp + + mov ax,6[bp] ; reciph + mov reciph,ax + mov ax,8[bp] ; recipl + mov recipl,ax + mov ax,10[bp] ; mshift + mov mshift,ax + + pop bp + ret +_P_SETRECIP endp + +; *************************************************************** +; MULTUNIT quo_digit (MULTUNIT *dividend) +; Determine the next quotient digit. +; (routine for modmult, converted to assembler) +; +; This implementation is for 16-bit MULTUNIT. +; +; The following items have already been set by calling +; P_SETRECIP: +; reciph, recipl - reciprocal of divisor +; mshift - scaling factor +; +; The dividend parameter points to the most significant word +; of the dividend. +; +; *************************************************************** +; Register assignments: +; dx:ax = product +; cx:bx = temp long +; es:si = dividend pointer +; di = MS word of q0 +; bp = lsb factor +; +; Comments reference the C implementation variables. + +DGROUP group _DATA,_BSS + assume ds:DGROUP + + PUBLIC _P_QUO_DIGIT + + +_P_QUO_DIGIT PROC FAR + push bp + mov bp,sp + push di + push si + + les si,6[bp] ; dividend + mov ax,es:[si-4] ; dividend[-2] + not ax + mul reciph + add ax,reciph + adc dx,0 + mov bx,ax + mov di,dx ; di:bx = q1 + + mov ax,es:[si-2] ; dividend[-1] + not ax + mul recipl + inc dx ; dx:ax = q2 + + mov bp,dx + and bp,di + and bp,1 ; bp = lsb_factor + + add ax,bx + adc di,dx + rcr di,1 ; di = MS word of q0 + + mov ax,es:[si-2] ; dividend [-1] + not ax + mul reciph + mov bx,ax + mov cx,dx ; cx:bx = q1 + + mov ax,es:[si] ; dividend[0] + not ax + mul recipl ; dx:ax = q2 + xor ax,bx + and bp,ax ; lsb correction + xor ax,bx ; restore ax + + add ax,bx + adc dx,cx + rcr dx,1 + rcr ax,1 ; dx:ax = q + + add ax,di ; + scaled q0 + adc dx,0 + add ax,bp ; + lsb correction + adc dx,0 ; q + + shl ax,1 + rcl dx,1 + rcl ax,1 + rcl dx,1 + rcl ax,1 + and ax,3 + mov cx,ax + mov bx,dx ; bx:cx = q >> 14 + + mov ax,es:[si] ; dividend[0] + not ax + mul reciph + shl ax,1 + rcl dx,1 + add ax,bx + adc dx,cx ; q + + mov cx,mshift + shr ax,cl + mov bx,dx + shr dx,cl + neg cx + add cx,16 + shl bx,cl + add ax,bx ; dx:ax = q >> mshift + + or dx,dx + jz no_overflow + mov ax,0ffffh +no_overflow: + pop si + pop di + pop bp + ret +_P_QUO_DIGIT ENDP +_TEXT ends -_P_SMUL ENDP -UPTON_TEXT ends end