;
; ASMPI by Rich Geldreich, December 1992 - June 1993
; (A FAST all-assembly PI calculator.)
; Thanks to Victor Yui for suggesting the division optimization.
; (This program has only been verified to 10,000 digits.)
;
.286
IDEAL ; Assembled with TASM v3.0 (sorry MASM guys!)
MODEL SMALL
DOSSEG
STACK 512
DATASEG
;-------------------------------------------------------------------------------
;The following equates specify how many digits of PI are to be calculated.
;I used the QuickBASIC program MAKESZES.BAS to calculate these values.
;(The maximum number of digits this program can handle is about 36,000
;because of memory limitations.)
;NumDigits=564
;MPVSize=224
;Last1=801
;Last2=225
;NumDigits=1064
;MPVSize=448
;Last1=1588
;Last2=436
;NumDigits=2564
;MPVSize=1056
;Last1=3949
;Last2=1069
;NumDigits=5064
;MPVSize=2080
;Last1=7883
;Last2=2124
;NumDigits=10064
;MPVSize=4160
;Last1=15752
;Last2=4234
NumDigits=20064
MPVSize=8320
Last1=31489
Last2=8453
;NumDigits=36064
;MPVSize=14976
;Last1=56669
;Last2=15204
;MPV stands for: multiple precision variable.
EVEN
MPV1 db MPVSize dup(0)
MPV2 db MPVSize dup(0)
MPV3 db MPVSize dup(0)
MPV4 db MPVSize dup(0)
MPVDivZero dw 0
MPVDivZeroSize dw 0
MPVMulZero dw 0
MPVMulZeroSize dw 0
Divisor dw 0
OddEven db 0
Max dw 0
TwiddlePos dw 0
TwiddleStuff db '─','\','|','/'
TwiddleCount db 0
Message1 db 'Machin Series PI Calculator',10,13
db 'by Rich Geldreich, June 1993',10,13,'$'
Message2 db 'Initializing... $'
Message3 db 13,'Calculating group one... $'
Message4 db ' ',13,'Calculating group two... $'
Message5 db ' ',13,'Conterting result to decimal... $'
Message6 db 13,' ',13,10,13,'$'
Message7 db 'Assembled for ','$'
Message8 db ' digits.',10,13,'$'
;-------------------------------------------------------------------------------
FARDATA DigitSeg
Digits db NumDigits dup(0)
ENDS
;-------------------------------------------------------------------------------
CODESEG
ASSUME DS:@DATA, ES:@DATA, CS:@CODE
Start: Cld
Mov ax, @DATA
Mov ds, ax
Mov es, ax
Mov ah, 9
Mov dx, offset Message1
Int 021h
Call PrintNumDigits
Call MPVLOAD10 ;calculate 10^numdigits in binary
Call TERM1 ;calculate term 1
Call TERM2 ;calculate term 2
Call MPVPRINT ;convert result to decimal and
;print to screen
Mov ax, 04C00h ;exit to dos
Int 021h
;-------------------------------------------------------------------------------
EVEN
PROC MPVDIV ;divides an MPV by BX
Std
Mov si, [MPVDivZero]
Mov dx, [MPVDivZeroSize]
Xor ax, ax
Sub di, dx
Sub di, dx
@@10: Cmp dx, MPVSize/2 ;track how big the MPV is
Je @@20
Cmp [si], ax
Jne @@20
Dec si
Dec si
Inc dx
Stosw
Jmp @@10
@@20: Mov [MPVDivZero], si
Mov [MPVDivZeroSize], dx
Mov cx, MPVSize/2
Sub cx, dx
Xor dx, dx
Push cx
And cx, 15
Jcxz @@40
@@30: Lodsw
Div bx
Stosw
Loop @@30
@@40: Pop cx
Shr cx, 4
Jz @@Exit
EVEN
@@50: REPT 16
Lodsw
Div bx
Stosw
ENDM
Loop @@50
@@Exit: Cld
Ret
ENDP MPVDIV
;-------------------------------------------------------------------------------
EVEN
PROC MPVMUL ;multiplies an MPV by BX
Mov si, [MPVMulZero]
Mov cx, [MPVMulZeroSize]
@@01: Cmp [word si], 0 ;track how big the MPV is
Je @@02
Inc si
Inc si
Dec cx
Jnz @@01
@@02:
Mov [MPVMulZero], si
Mov [MPVMulZeroSize], cx
Neg cx
Add cx, MPVSize/2
Mov di, offset MPV4
Mov si, offset MPV4
Xor bp, bp
Push cx
And cx, 7
Jz @@03
@@04: Lodsw
Mul bx
Add ax, bp
Adc dx, 0
Stosw
Mov bp, dx
Loop @@04
@@03: Pop cx
Shr cx, 3
Jnz @@10
Jmp @@Exit
EVEN
@@10: REPT 8
Lodsw
Mul bx
Add ax, bp
Adc dx, 0
Stosw
Mov bp, dx
ENDM
Loop @@10
@@Exit: Mov ax, bp
Stosw
Ret
ENDP MPVMUL
;-------------------------------------------------------------------------------
EVEN
PROC MPVSHIFT ;shifts an MPV over to the left 1 time
Mov cx, (MPVSize/2)/16
Mov dx, 32
Clc
EVEN
@@10: Rcl [word ds:si], 1
Rcl [word ds:si+2], 1
Rcl [word ds:si+4], 1
Rcl [word ds:si+6], 1
Rcl [word ds:si+8], 1
Rcl [word ds:si+10], 1
Rcl [word ds:si+12], 1
Rcl [word ds:si+14], 1
Rcl [word ds:si+16], 1
Rcl [word ds:si+18], 1
Rcl [word ds:si+20], 1
Rcl [word ds:si+22], 1
Rcl [word ds:si+24], 1
Rcl [word ds:si+26], 1
Rcl [word ds:si+28], 1
Rcl [word ds:si+30], 1
Lahf
Add si, dx
Sahf
Loop @@10
Ret
ENDP MPVSHIFT
;-------------------------------------------------------------------------------
EVEN
PROC MPVCOPY ;copies an MPV
Mov cx, MPVSize/2
Rep Movsw
Ret
ENDP MPVCOPY
;-------------------------------------------------------------------------------
EVEN
PROC MPVADD ;adds an MPV with another MPV
Mov cx, MPVSize/2
Sub cx, [MPVDivZeroSize]
Jnz @@10
Ret
@@10:
Mov dx, 32
Push cx
And cx, 15
Jz @@30
Clc
@@20: Lodsw
Adc [ds:di], ax
Inc di
Inc di
Loop @@20
@@30: Pop cx
Lahf
Shr cx, 4
Jnz @@40
Ret
@@40: Sahf
EVEN
@@50: Lodsw
Adc [ds:di], ax
Lodsw
Adc [ds:di+2], ax
Lodsw
Adc [ds:di+4], ax
Lodsw
Adc [ds:di+6], ax
Lodsw
Adc [ds:di+8], ax
Lodsw
Adc [ds:di+10], ax
Lodsw
Adc [ds:di+12], ax
Lodsw
Adc [ds:di+14], ax
Lodsw
Adc [ds:di+16], ax
Lodsw
Adc [ds:di+18], ax
Lodsw
Adc [ds:di+20], ax
Lodsw
Adc [ds:di+22], ax
Lodsw
Adc [ds:di+24], ax
Lodsw
Adc [ds:di+26], ax
Lodsw
Adc [ds:di+28], ax
Lodsw
Adc [ds:di+30], ax
Lahf
Add di, dx
Sahf
Loop @@50
@@60: Jnc @@70
Adc [word ds:di], 0
Inc di
Inc di
Jmp @@60
@@70: Ret
ENDP MPVADD
;-------------------------------------------------------------------------------
EVEN
PROC MPVSUB ;subtracts an MPV from another MPV
Mov cx, MPVSize/2
Sub cx, [MPVDivZeroSize]
Jnz @@10
Ret
@@10:
Mov dx, 32
Push cx
And cx, 15
Jz @@30
Clc
@@20: Lodsw
Sbb [ds:di], ax
Inc di
Inc di
Loop @@20
@@30: Pop cx
Lahf
Shr cx, 4
Jnz @@40
Ret
@@40: Sahf
EVEN
@@50: Lodsw
Sbb [ds:di], ax
Lodsw
Sbb [ds:di+2], ax
Lodsw
Sbb [ds:di+4], ax
Lodsw
Sbb [ds:di+6], ax
Lodsw
Sbb [ds:di+8], ax
Lodsw
Sbb [ds:di+10], ax
Lodsw
Sbb [ds:di+12], ax
Lodsw
Sbb [ds:di+14], ax
Lodsw
Sbb [ds:di+16], ax
Lodsw
Sbb [ds:di+18], ax
Lodsw
Sbb [ds:di+20], ax
Lodsw
Sbb [ds:di+22], ax
Lodsw
Sbb [ds:di+24], ax
Lodsw
Sbb [ds:di+26], ax
Lodsw
Sbb [ds:di+28], ax
Lodsw
Sbb [ds:di+30], ax
Lahf
Add di, dx
Sahf
Loop @@50
@@60: Jnc @@70
Sbb [word ds:di], 0
Inc di
Inc di
Jmp @@60
@@70: Ret
ENDP MPVSUB
;-------------------------------------------------------------------------------
PROC MPVLOAD10 ;initializes MPV4 to a power of 10
Mov ah, 9
Mov dx, offset Message2
Int 021h
Mov [word ds:MPV4+2], 03B9Ah
Mov [word ds:MPV4], 0CA00h
Mov [word MPVMulZero], offset MPV4
Mov [word MPVMulZeroSize], MPVSize/2
EVEN
@@10: Mov bx, 10000
Call MPVMUL
Call Twiddle
Cmp [word ds:MPV4+MPVSize-12], 0 ;fudge factor = 12 bytes
Je @@10
Ret
ENDP MPVLOAD10
;-------------------------------------------------------------------------------
PROC MPVPRINT ;prints an MPV to the screen in decimal
Mov ah, 9
Mov dx, offset Message5
Int 021h
Mov cx, NumDigits/4
Mov [ds:Max], cx
Mov di, offset Digits+NumDigits-1
Mov [ds:MPVDivZero], offset MPV2+MPVSize-2
Mov [ds:MPVDivZeroSize], 0
EVEN
@@10: Push cx di
Mov di, offset MPV2+MPVSize-2
Mov bx, 10000
Call MPVDIV
Pop di cx
Mov ax, DigitSeg
Mov ds, ax
Mov ax, dx
Mov bx, 10
REPT 4
Xor dx, dx
Div bx
Add dl, '0'
Mov [ds:di], dl
Dec di
ENDM
Mov ax, @DATA
Mov ds, ax
Mov ax, NumDigits/4
Sub ax, cx
Call PERCENT
Loop @@10
Mov ah, 9
Mov dx, offset Message6
Int 021h
Mov cx, NumDigits
Mov ax, DigitSeg
Mov ds, ax
Mov si, di
Inc si
@@20: Lodsb
Cmp al, '0'
Jne @@30
Loop @@20
Jmp short @@Exit
@@30:
Mov dl, al
Mov ah, 2
Int 021h
Dec cx
Jz @@Exit
@@40: Lodsb ;this is slower than doing a single
Mov dl, al ;DOS call to print the entire number,
Mov ah, 2 ;but that's good because it doesn't
Int 021h ;zip up the screen as fast
Loop @@40
@@Exit: Ret
ENDP MPVPRINT
;-------------------------------------------------------------------------------
PROC TERM1 ;calculates the first term of the Machin series
Mov ah, 9
Mov dx, offset Message3
Int 021h
Mov [ds:Max], Last1
Mov si, offset MPV4
Mov di, offset MPV1
Call MPVCOPY
Mov [ds:OddEven], -1
Mov [ds:Divisor], 1
Mov [ds:MPVDivZero], offset MPV1+MPVSize-2
Mov [ds:MPVDivZeroSize], 0
EVEN
@@10:
Mov di, offset MPV1+MPVSize-2
Mov bx, 5
Cmp [ds:Divisor], 1
Je @@20
Mov bx, 25
@@20: Call MPVDIV
Mov di, offset MPV3+MPVSize-2
Mov bx, [ds:Divisor]
Call MPVDIV
Mov si, offset MPV3
Mov di, offset MPV2
Cmp [ds:OddEven], 0
Je @@30
Call MPVADD
Jmp short @@40
EVEN
@@30: Call MPVSUB
@@40:
Not [ds:OddEven]
Mov ax, [ds:Divisor]
Inc ax
Inc ax
Mov [ds:Divisor], ax
Cmp ax, Last1
Jae @@Done
Push offset @@10
Jmp PERCENT
@@Done:
Mov si, offset MPV2
Call MPVSHIFT
Mov si, offset MPV2
Call MPVSHIFT
Ret
ENDP TERM1
;-------------------------------------------------------------------------------
PROC TERM2 ;calculates the second term of the Machin series
Mov ah, 9
Mov dx, offset Message4
Int 021h
Mov si, offset MPV4
Mov di, offset MPV1
Call MPVCOPY
Mov [ds:Max], Last2
Mov [ds:OddEven], 0
Mov [ds:Divisor], 1
Mov [ds:MPVDivZero], offset MPV1+MPVSize-2
Mov [ds:MPVDivZeroSize], 0
EVEN
@@10:
Mov di, offset MPV1+MPVSize-2
Mov bx, 239
Cmp [ds:Divisor], 1
Je @@20
Mov bx, 239*239
@@20: Call MPVDIV
Mov di, offset MPV3+MPVSize-2
Mov bx, [ds:Divisor]
Call MPVDIV
Mov si, offset MPV3
Mov di, offset MPV2
Cmp [ds:OddEven], 0
Je @@30
Call MPVADD
Jmp short @@40
EVEN
@@30: Call MPVSUB
@@40:
Not [ds:OddEven]
Mov ax, [ds:Divisor]
Inc ax
Inc ax
Mov [ds:Divisor], ax
Cmp ax, Last2
Jae @@Done
Push offset @@10
Jmp PERCENT
@@Done:
Mov si, offset MPV2
Call MPVSHIFT
Mov si, offset MPV2
Call MPVSHIFT
Ret
ENDP TERM2
;-------------------------------------------------------------------------------
EVEN
PROC TWIDDLE
Mov al, [ds:TwiddleCount]
Inc ax
And al, 01Fh
Mov [byte ds:TwiddleCount], al
Jz @@Update
Ret
@@Update: Mov bx, [ds:TwiddlePos]
Mov dl, [ds:bx+TwiddleStuff]
Inc bx
And bl, 3
Mov [ds:TwiddlePos], bx
Mov ah, 2
Int 021h
Mov dl, 8
Mov ah, 2
Int 021h
Ret
ENDP TWIDDLE
;-------------------------------------------------------------------------------
PROC PERCENT
Mov bl, [ds:TwiddleCount]
Inc bl
Mov [byte ds:TwiddleCount], bl
Jz @@Update
Ret
@@Update:
Push cx
Mov bx, 100
Mul bx
Div [ds:Max]
Mov bp, 10
Xor cx, cx
@@CalcNumber: Xor dx, dx
Div bp
Add dl, '0'
Push dx
Inc cx
And ax, ax
Jnz @@CalcNumber
Mov bp, cx
Mov ah, 2
@@PrintNumber:
Pop dx
Int 021h
Loop @@PrintNumber
Mov dl, '%'
Int 021h
Mov cx, bp
Inc cx
Mov dl, 8
@@BackSpace: Int 021h
Loop @@BackSpace
Pop cx
Ret
ENDP PERCENT
;-------------------------------------------------------------------------------
PROC PrintNumDigits
Mov ah, 9
Mov dx, offset Message7
Int 021h
Mov ax, NumDigits
Mov bx, 10
Xor cx, cx
@@10: Cwd
Div bx
Add dl, '0'
Push dx
Inc cx
And ax, ax
Jnz @@10
Mov ah, 2
@@20: Pop dx
Int 021h
Loop @@20
Mov ah, 9
Mov dx, offset Message8
Int 021h
Ret
ENDP PrintNumDigits
;-------------------------------------------------------------------------------
END