; =====> SBIGMATH.ASM ;*************************************** ;* TIPC Scheme '84 Runtime Support * ;* Bignum Math Utilities * ;* * ;* (C) Copyright 1984,1985 by Texas * ;* Instruments Incorporated. * ;* All rights reserved. * ;* * ;* Date Written: June 1984 * ;* Last Modification: 27 May 1986 * ;*************************************** include scheme.equ DGROUP group data data segment word public 'DATA' assume DS:DGROUP data ends XGROUP GROUP PROGX PROGX segment byte public 'PROGX' assume CS:XGROUP,DS:DGROUP ; Convert a bignum to a flonum ; Calling sequence: big2flo(bigptr,floptr) ; Where: bigptr ---- pointer to bignum workspace ; floptr ---- pointer to flonum b2fargs struc dw ? ;Caller's BP dd ? ;Return address dw ? ;Another return address big dw ? ;Pointer to bignum flo dw ? ;Pointer to flonum b2fargs ends %big2flo proc far push BP mov BP,SP cld ;Direction forward mov SI,[BP].big ;Point DS:SI to working bignum mov CX,[SI] ;Get size cmp CX,3 ja all64 ;Jump if at least 64 bits add SI,3 ;Point to bignum proper xor BX,BX xor DI,DI lodsw ;Fetch least sig. word mov DX,AX ;Store in DX dec CX jcxz smljust ;Jump if no more bignum words lodsw ;Else get next least sig. word mov DI,AX dec CX jcxz smljust ;Jump if no more bignum words lodsw ;Get 3rd least sig. word mov BX,AX smljust: xor AX,AX ;Clear most sig. word jmp short justify ;Left-justify the number all64: shl CX,1 ;Point SI to 4th most sig. word add SI,CX sub SI,5 lodsw ;Load bignum into registers mov DX,AX lodsw mov DI,AX lodsw mov BX,AX lodsw ;JUSTIFY: At this stage, the 64 most significant bignum bits are in ; AX:BX:DI:DX respectively, AX most significant justify: mov SI,[BP].big ;Fetch pointer to bignum again mov CX,[SI] ;Get size (words) cmp CX,40h ja toobig ;Jump if bignum too big cmp CX,4 ;Skip if not a small bignum jae enough mov CX,4 ;Otherwise, start with constant enough: shl CX,1 ;Multiply by 16 (size in bits) shl CX,1 shl CX,1 shl CX,1 justflp: dec CX ;Reduce exponent shl DX,1 ;Shift bignum left rcl DI,1 rcl BX,1 rcl AX,1 jnc justflp ;Until most significant 1 vanishes add CX,3ffh ;Add flonum exponent constant mov SI,DI ;Now use SI for num, DI for address shftrt: shr CX,1 ;Shift CX:AX:BX:SI:DX as one rcr AX,1 rcr BX,1 rcr SI,1 rcr DX,1 cmp CX,80h ;Until most sig. exponent bit is in 2nd jae shftrt ; most sig. bit of CL mov DI,[BP].big ;Get pointer to bignum again test byte ptr[DI]+2,1 ;Negative? jz posskip ;No, skip or CL,80h ;Set sign bit posskip: mov DI,[BP].flo ;Point ES:DI to flonum push AX ;Save part of new flonum mov AL,DH ;Write to flonum space stosb mov AX,SI stosw mov AX,BX stosw pop AX stosw mov AL,CL stosb xor AX,AX ;Return 0 if all well pop BP ;Restore BP ret toobig: mov AX,1 ;Return 1 if conversion impossible pop BP ret %big2flo endp ; Convert fixnum to bignum ; Calling sequence: fix2big(fixnum,bigptr) ; Where: fixnum ---- Integer of small absolute value ; bigptr ---- Pointer to bignum space f2bargs struc dw ? ;Caller's BP dd ? ;Return address dw ? ;Another return address fix dw ? ;Fixnum bigp dw ? ;Pointer to bignum f2bargs ends %fix2big proc far push BP mov BP,SP mov DI,[BP].bigp ;Point ES:DI to bignum mov AX,1 ;Fill size field stosw xor AL,AL ;Clear AL mov BX,[BP].fix ;Fetch fixnum value shl BX,1 ;Put sign bit in AL rcl AL,1 stosb ;Fill sign field sar BX,1 ;Restore fixnum or AL,AL ;Negative fixnum? jz posfx ;Skip if positive neg BX ;Otherwise, find absolute value posfx: mov [DI],BX ;Store magnitude of fixnum pop BP ;Restore BP ret %fix2big endp ;;;; Decrement bignum ;;;; Calling sequence: sub1big(buf) ;;;; Where: buf ---- pointer to bignum ;;;unibig struc ;;; dw ? ;Return address ;;;bbuf dw ? ;Pointer to working bignum ;;;unibig ends ;;; public sub1big ;;;sub1big proc far ;;; mov BX,SP ;Get bignum pointer ;;; mov SI,SS:[BX].bbuf ;;; test byte ptr[SI]+2,1 ;Is bignum negative? ;;; jnz incbig ;If so, increase magnitude ;;; jmp short decbig ;Else decrease magnitude ;;;sub1big endp ;;;; Increment bignum ;;;; Calling sequence: add1big(buf) ;;; public add1big ;;;add1big proc far ;;; mov BX,SP ;Get bignum pointer ;;; mov SI,SS:[BX].bbuf ;;; test byte ptr[SI]+2,1 ;Is bignum negative? ;;; jnz decbig ;Yes, decrease magnitude ;;;;INCBIG increments magnitude of working bignum at DS:SI ;;;incbig: mov DI,SI ;Save bignum pointer ;;; mov CX,[SI] ;Get length (words) ;;; add SI,3 ;Point to bignum proper ;;;carrylp: inc word ptr[SI] ;Increment bignum ;;; jnz done ;If no carry, finished ;;; inc SI ;Else go to next word ;;; inc SI ;;; loop carrylp ;Loop while not end of bignum ;;; mov word ptr[SI],1 ;Else place final 1 ;;; inc word ptr[DI] ;Lengthen bignum ;;;done: ret ;;;;DECBIG decrements magnitude of working bignum at DS:SI ;;;decbig: mov DI,SI ;Save pointer ;;; mov CX,[SI] ;Get length ;;; add SI,3 ;Point to bignum proper ;;; dec CX ;CX = (length - 1) ;;;borrowlp: lodsw ;Load current word ;;; sub AX,1 ;Decrement and store ;;; mov [SI-2],AX ;;; jnc done ;Jump if no borrow ;;; loop borrowlp ;Loop if not on last word ;;; dec word ptr[SI] ;Else decrement last word ;;; jnz done ;Jump if bignum not to be shortened ;;; dec word ptr[DI] ;Else shorten ;;; ret ;;;add1big endp ; set up big1's index for comparison, used with %magcomp %pbig1 proc near shl CX,1 dec SI add SI,CX shr CX,1 ret %pbig1 endp ; set up big1's index for comparison, used with %magcomp %pbig2 proc near shl CX,1 dec DI add DI,CX shr CX,1 ret %pbig2 endp ; Compare magnitudes of two bignums ; Calling sequence: data = magcomp(big1,big2) ; Where: big1,big2 -- pointers to bignum buffers ; data ------- a positive integer as follows: ; Bit 0 set iff |BIG1| < |BIG2| ; Bit 1 set iff |BIG1| > |BIG2| ; Bit 2 set iff BIG1 < BIG2 ; Bit 3 set iff BIG1 > BIG2 ; Bit 4 set iff BIG1,BIG2 have same sign twobigs struc dd ? ;Return address dw ? ;Another return address big1 dw ? ;First bignum big2 dw ? ;Second bignum twobigs ends %magcomp proc far xor AL,AL ;Clear AL xor DX,DX ; clear DX mov BX,SP ;Fetch bignum pointers mov SI,[BX].big1 mov DI,[BX].big2 mov AH,[SI]+2 ;Get sign bits mov DH,[DI]+2 xor DH,AH ;Put XOR of signs into carry shr DH,1 jc sgnskp ;Jump if different signs or AL,16 ;Else set proper bit in AL sgnskp: rcl AH,1 mov CX,[SI] ;Get BIG1's length mov DX,[DI] ; get BIG2's length cld ;Direction forward cmpsw ;Compare lengths jb bigr2 ;Jump if BIG2 longer ja bigr1 ;Jump if BIG1 longer same_ln: call %pbig1 ;If same size, point SI,DI to last words call %pbig2 ; (most significant) std ;Direction backward repe cmpsw ;Repeat until unequal jb rbig2 ja rbig1 test AH,1 ;Signs same? jz compend ;Yes, exit difsign: test AH,2 ;Is BIG1 positive? jnz grtr2 ;No, BIG2 is greater jz grtr1 ;Else BIG1 is greater bigr1: call %pbig1 cmp word ptr [SI],0 ; check high word, jne rbig1 ; big1 is really bigger mov SI,[BX].big1 ; restore SI inc SI inc SI dec CX ; high order word is empty cmp CX,DX ; compare length's again je same_ln ; same length jmp bigr1 ; repeat until unequal or same lengths rbig1: or AL,2 ;Set the |BIG1|>|BIG2| bit test AH,1 ;Signs same? jnz difsign ;No, different signs test AH,2 ;Both positive? jnz grtr2 ;No, so BIG2 is greater grtr1: or AL,8 ;Set the BIG1>BIG2 bit cld ; Set direction forward (JCJ-12/6/84) ret bigr2: push CX mov CX,DX ; swap CX and DX pop DX call %pbig2 ; Set up big2's pointers cmp word ptr [DI],0 ; check high word jne rbig2 ; big2 really is bigger mov DI,[BX].big2 ; restore DI inc DI inc DI dec CX ; high order word is empty cmp DX,CX ; compare length's again je same_ln ; jmp bigr2 ; repeat until unequal or same lengths rbig2: or AL,1 ;Set the |BIG1|<|BIG2| bit test AH,1 ;Signs same? jnz difsign ;No, different signs test AH,2 ;Both positive? jnz grtr1 ;No, BIG1 is greater grtr2: or AL,4 ;Set the BIG1