home *** CD-ROM | disk | FTP | other *** search
- ;-----------------------------------------------------------------------
- TITLE PRIMES
- ; (c) 1991 W.C. Parke
- ;-----------------------------------------------------------------------
- CR EQU 13
- LF EQU 10
- ;-----------------------------------------------------------------------
- START SEGMENT
- ASSUME CS:START,DS:START,ES:START,SS:START
- ORG 100H
- PUBLIC FIRST,BEGIN
- FIRST: JMP BEGIN
- CPWP DB 'Primes V1.4 (c) W.C. Parke, 1991$',1AH
- EVEN
- PUBLIC NPRINT1,NPRINT2,NLINE,NPRIME,NPRIME2,TLINE,PBUF,EXTRA,NPS,NP$
- PUBLIC CRLF,NUMBUF
- NPRINT1 DW 1
- NPRINT12 DW 0
- NPRINT2 DW 0
- NPRINT22 DW 0
- NLINE DW 8
- NPRIME DW 0
- NPRIME2 DW 0
- TLINE DW 9
- PBUF DW 0
- EXTRA DB 0
- NPS DB CR,LF,'The number of primes was '
- NP$ DB '0000000000$'
- ERROR DB CR,LF,'Error in '
- DHELP DB 'Syntax: PRIMES n1 n2'
- DB CR,LF,CR,LF,' where 0 < n1 < n2 < 1048576'
- CRLF DB CR,LF,'$'
- STSI DW 0
- LSTB DW 0
- INIM DB 0
- ERIN DB 0
- FLG DB 0
- ;-----------------------------------------------------------------------
- PUBLIC EXIT
- ; Process error message and exit
- EXITE: MOV DX,OFFSET ERROR
- EXITH: MOV AH,9
- INT 21H
- MOV AX,4C00H
- INT 21H
- EXIT: PUSH CS
- POP ES
- MOV AL,ERIN
- AND AL,AL
- JNZ EXITE
- MOV AX,NPRIME
- MOV DX,NPRIME2
- MOV DI,OFFSET NP$
- PUSH DI
- CALL BINDEC32
- POP SI
- CMP BYTE PTR NP$+9,' '
- JNZ EXIT1
- MOV BYTE PTR NP$+9,'0'
- EXIT1: MOV DX,OFFSET NPS
- MOV AH,9
- INT 21H
- CALL SCRLF
- MOV AL,0
- MOV AH,4CH
- INT 21H
- HELP: CALL SCRLF
- MOV DX,OFFSET DHELP
- JMP EXITH
- ;-----------------------------------------------------------------------
- PUBLIC BEGIN
- ; Begin by getting command line numbers
- BEGIN:
- CALL SCRLF
- MOV DX,OFFSET CPWP
- MOV AH,9
- INT 21H
- CALL SCRLF
- MOV SI,OFFSET 81H
- MOV DI,OFFSET NUMBUF
- CALL GETNUM
- JNC BEG1
- MOV ERIN,1
- JMP EXIT
- BEG1: JCXZ BEG2
- PUSH SI
- MOV SI,OFFSET NUMBUF
- MOV DI,OFFSET NPRINT1
- CALL DECBIN32
- POP SI
- MOV DI,OFFSET NUMBUF
- CALL GETNUM
- BEG2: JCXZ BEG3
- MOV SI,OFFSET NUMBUF
- MOV DI,OFFSET NPRINT2
- CALL DECBIN32
- BEG3:
- MOV CX,NPRINT2
- MOV DX,NPRINT2+2 ; dx:cx = second number
- MOV SI,NPRINT1
- MOV AX,NPRINT1+2 ; ax:si = first number
- MOV BX,SI ; table index = 16*si + 2*b + 1
- OR BX,AX
- JZ HELP
- MOV BX,CX
- OR BX,DX
- JZ HELP
- TEST DX,0FFF0H
- JNZ BEG4
- TEST AX,0FFF0H
- JNZ BEG4
- AND AX,AX
- JNZ BEG31
- CMP SI,3
- JNC BEG31
- MOV SI,1
- MOV FLG,1
- BEG31: MOV DI,DX ; nprint22
- MOV BX,CX ; nprint2
- SUB BX,SI ; nprint2-nprint1
- SBB DI,AX ; nprint22-nprint12-c
- JNC BEG5
- BEG4: MOV ERIN,1
- JMP EXIT
- BEG5: OR BX,DI
- JZ BEG4
- OR SI,1 ; make nprint1 odd
- TEST CX,1
- JNZ BEG6 ; odd already
- SUB CX,1
- SBB DX,0 ; get next lower odd
-
- BEG6: MOV BX,SI ; nprint1
- AND BX,0FH ; start to print after div by 16
- SHR BX,1 ; get bit index for starting number
-
- SHR AX,1 ; divide first number by 16
- RCR SI,1
- SHR AX,1
- RCR SI,1
- SHR AX,1
- RCR SI,1
- SHR AX,1
- RCR SI,1 ; si now has [#/16]
- MOV STSI,SI
-
- MOV AX,CX ; nprint2
- AND AX,0FH ; extra to print
- SHR AX,1 ; but only odds
- MOV EXTRA,AL
-
- SHR DX,1 ; divide second number by 16
- RCR CX,1
- SHR DX,1
- RCR CX,1
- SHR DX,1
- RCR CX,1
- SHR DX,1
- RCR CX,1
- MOV DX,CX ; save index of last byte-mask to print
- MOV LSTB,DX ; last byte ptr
-
- ; Extimate square root of last byte using
- ; 2**(k-1) + #/2**(k+1)
- ; where k is largest integer for which # ~ 2**2k
-
- MOV AX,CX
- MOV CX,16
- BEG7: SHL AX,1
- JC BEG8
- LOOP BEG7
- BEG8: SHR CX,1 ; k
- MOV AX,1
- SHL AX,CL ; 2**k
- INC CX ; k+1
- SHR DX,CL ; #/2**(k+1)
- SHR AX,1 ; 2**(k-1)
- ADD DX,AX
- INC DX
-
- MOV BP,DX ; save for later comparison
-
- MOV CX,BX
- AND CL,7
- MOV AL,1
- SHL AL,CL ; get initial mask
- MOV INIM,AL
-
- MOV AX,OFFSET STK
- MOV SP,AX ; set up our stack
- MOV BX,OFFSET BUF
- PUSH DS
- POP AX
- ADD BX,15
- SHR BX,1
- SHR BX,1
- SHR BX,1
- SHR BX,1
- ADD AX,BX
- MOV PBUF,AX ; the prime bit buffer
- ASSUME ES:NOTHING,DS:NOTHING
- MOV ES,AX
- MOV DS,AX
- XOR AX,AX
- MOV SI,AX
- MOV DI,AX
- MOV CX,32768
- REP STOSW ; zero 64K buffer
- MOV BX,1 ; bit tester register will be BL
- MOV CH,8 ; CH=8, CL bit pointer
- PUSH CX
- PUSH SI ; address in buffer
- ;-----------------------------------------------------------------------
- PUBLIC NEXTP
- ; Start Eratosthenes sieve
- NEXTP: POP SI ; byte pointer
- POP CX ; bit counter
- NEXTP1: INC CL ; pointer in 8 bits
- ROL BL,1 ; bit mask, 8 bit roll and set C
- JNC NEXTP2 ; not yet finished with byte
- XOR CL,CL ; reset bit pointer
- INC SI ; point to next byte in buffer
- CMP SI,BP ; are we finished?
- JNC FINS2 ; yes
- PUBLIC NEXTP2
- NEXTP2: MOV AL,[SI] ; get byte
- AND AL,BL ; is it a prime, i.e. still a zero bit ?
- JNZ NEXTP1 ; no, its bit is set to 1, its not prime
- PUSH CX ; save bit counter
- PUSH SI ; save byte pointer
- MOV DI,SI ; put prime byte index in di
- MOV DL,CL ; put prime bit index in dl
- SHL DI,1 ; since we are doing only odds, double first
- JC NEXTP ; more than half done
- SHL DL,1 ; double bit index also
- INC DL ; and add 1 to make 2*i+1
- CMP DL,CH ; bigger than 8 ?
- JC DELN ; no
- SUB DL,CH ; reset bit index: DL - 8
- INC DI ; point to next byte index
- JZ NEXTP
- DELN: ADD SI,DI ; point to next non-prime byte
- JC NEXTP
- ADD CL,DL ; point to next non-prime bit in byte
- CMP CL,CH
- JC DELN1
- SUB CL,CH
- INC SI
- JZ NEXTP
- DELN1: MOV AL,1
- SHL AL,CL
- OR [SI],AL ; mask this bit to show non-prime
- JMP SHORT DELN
- ;-----------------------------------------------------------------------
- PUBLIC FINS2
- ; Now print all flagged (prime) bits up to requested number
- FINS2:
- PUSH CS
- POP DS
- ASSUME DS:START
- MOV DI,OFFSET NP$
-
- MOV CX,LSTB ; last byte pointer
- MOV SI,STSI ; initial byte pointer
- MOV AL,INIM ; initial mask
- TEST FLG,1
- JZ FINS21
- DEC TLINE
- MOV AX,2
- XOR DX,DX
- MOV BP,AX
- CALL PRT3
- MOV AX,BP
- FINS21: CMP CX,SI
- JZ FINS5
- FINS3: MOV AH,AL
- AND AH,ES:[SI]
- MOV BP,AX
- JNZ FINS4
- CALL PRINT
- FINS4: MOV AX,BP
- ROL AL,1
- JNC FINS3
- INC SI
- CMP SI,CX
- JC FINS3
- JZ FINS5
- MOV ERIN,0
- JMP EXIT
- FINS5: XOR CX,CX
- MOV CL,EXTRA
- JCXZ FINS9
- MOV CH,1
- SHL CH,CL
- MOV CL,CH
- ROL CL,1
- FINS6: MOV AH,AL
- AND AH,ES:[SI]
- MOV BP,AX
- JNZ FINS8
- CALL PRINT
- FINS8: MOV AX,BP
- ROL AL,1
- CMP AL,CL
- JNZ FINS6
- FINS9: MOV ERIN,0
- JMP EXIT
- PUBLIC PRINT
- PRINT: DEC TLINE ; # on line
- JNZ PRT1
- CALL PRTCR
- PRT1: MOV BH,AL
- XOR DX,DX
- MOV AX,SI
- SHL AX,1
- RCL DX,1
- SHL AX,1
- RCL DX,1
- SHL AX,1
- RCL DX,1
- SHL AX,1
- RCL DX,1
- MOV BL,0
- PRT2: INC BL
- ROR BH,1
- JNC PRT2
- XOR BH,BH
- SHL BX,1
- DEC BX
- ADD AX,BX
- ADC DX,0
- PRT3: ADD WORD PTR NPRIME,1
- ADC WORD PTR NPRIME2,0
- ;-----------------------------------------------------------------------
- PUBLIC OUTDEC
- ; Output a decimal number
- OUTDEC:
- PUSH AX
- PUSH CX
- PUSH DI
- PUSH DX
- PUSH ES
- PUSH CS
- POP ES
- MOV DI,OFFSET NP$
- CALL BINDEC32
- XCHG SI,DI
- ADD SI,2
- MOV AH,2
- MOV CX,8
- OUTDS: LODSB
- MOV DL,AL
- INT 21H
- LOOP OUTDS
- XCHG SI,DI
- POP ES
- POP DX
- POP DI
- POP CX
- POP AX
- RET
- ;-----------------------------------------------------------------------
- PUBLIC PRTCR
- ; Print a carriage return and line feed and reset number/line count
- PRTCR:
- PUSH AX
- CALL SCRLF
- MOV AX,NLINE
- MOV TLINE,AX
- POP AX
- RET
- ;-----------------------------------------------------------------------
- PUBLIC CKNUM
- ; Check if character is a number
- CKNUM:
- CMP AL,':'
- CMC
- JC CKNE
- CMP AL,'0'
- CKNE: RET
- ;-----------------------------------------------------------------------
- PUBLIC GETNUM
- ; Get an ASCII number
- GETNUM:
- CALL SKIPS
- XOR CX,CX
- GETN1: LODSB
- CMP AL,CR
- JZ GETNE
- CMP AL,' '
- JZ GETNE
- CALL CKNUM
- JC GETNC
- INC CX
- STOSB
- JMP SHORT GETN1
- GETNC: RET
- GETNE: CMP CX,8
- CMC
- RET
- ;-----------------------------------------------------------------------
- PUBLIC DECBIN32
- ; Convert a decimal number to 32 bit binary number
- DECBIN32:
- PUSH DI
- PUSH BP
- PUSH BX
- XOR AX,AX ; zero initial
- MOV DX,AX ; binary double word
- MOV BX,AX ; and our decimal digit holder
- MOV BP,10 ; multiplier
- JMP DECBS ; skip first multiplication
- DECBL: XCHG DI,AX ; save current low word
- MOV AX,DX ; get high word
- MUL BP ; mult high word by 10
- XCHG DI,AX ; save and get low word
- MUL BP ; mult low word by 10
- ADD DX,DI ; add 10*hi to overflow of 10*lo
- DECBS: MOV BL,[SI] ; get next decimal
- INC SI ; bump buffer pointer
- SUB BL,30H ; drop ascii bias
- ADD AX,BX ; add next decimal to low word
- ADC DX,0 ; and carry to high word
- LOOP DECBL ; continue for 10 digits
- POP BX
- POP BP
- POP DI
- STOSW
- MOV AX,DX
- STOSW
- RET
- ;-----------------------------------------------------------------------
- PUBLIC SKIPS
- ; Skip space characters in a string
- SKIPS:
- CMP BYTE PTR [SI],' '
- JNZ SKIPE
- INC SI
- JMP SHORT SKIPS
- SKIPE: RET
- ;-----------------------------------------------------------------------
- PUBLIC SCRLF
- ; Send a carriage return and line feed
- SCRLF:
- PUSH DX
- MOV DX,OFFSET CRLF
- MOV AH,9
- INT 21H
- POP DX
- RET
- ;-----------------------------------------------------------------------
- PUBLIC BINDEC32
- ; Convert 32 bit binary to decimal
- BINDEC32: ; Convert 32 bit number to decimal
- PUSH BX ; save bx
- PUSH CX ; save cx
- PUSH SI ; save si
- PUSH DI ; save buffer pointer
- MOV DI,DX ; save binary double word
- MOV SI,AX ; in DI,SI
- XOR AX,AX ; zero high decimal accumulator
- MOV BX,AX ; BX will hold high packed BCD
- MOV DX,AX ; DX will hold low packed BCD
- MOV CX,32 ; use all 32 bits of double word
- BIND1: SHL SI,1 ; shift low word left
- RCL DI,1 ; rotate hi word left through carry
- XCHG DX,AX ; use DX low 4 digits first
- ADC AL,AL ; add al to al with carry bit
- DAA ; decimal adj al
- XCHG AL,AH ; now do the same with ah
- ADC AL,AL ; double and add carry
- DAA ; decimal adj
- XCHG AL,AH ; restore ax order
- XCHG DX,AX ; save resultant low BCD quartet
- XCHG BX,AX ; now use BX high 4 digits
- ADC AL,AL ; add al to al with carry bit
- DAA ; decimal adj al
- XCHG AL,AH ; now do the same with ah
- ADC AL,AL ; double and add carry
- DAA ; decimal adj
- XCHG AL,AH ; restore ax order
- XCHG BX,AX ; save resultant high BCD quartet
- ADC AL,AL ; accum highest digits in AL
- DAA ; as a pair of BCDs
- LOOP BIND1 ; do all 32 bits
- MOV SI,OFFSET TMPBUF ; our temporary buffer for packed BCD
- POP DI ; get buffer pointer
- PUSH DI ; save again
- MOV [SI],BX ; middle word
- MOV [SI+2],DX ; low word
- MOV CX,1 ; local count
- MOV DX,3 ; anticipate two more words to unpack
- MOV AH,AL ; save nibble pair
- JMP SHORT UNPL ; start with first nibble pair
- BINDU: ; expand packed BCD to ascii string
- XCHG DX,CX ; save external count
- LODSW ; get packed BCD word
- MOV CX,2 ; local count
- MOV BX,AX ; save ax
- MOV AL,AH ; start with ah
- UNPL: SHR AL,1 ; shift hi nibble
- SHR AL,1 ; note that four 1 bit shifts are
- SHR AL,1 ; 8 clock cycles, while shr al,cl(4)
- SHR AL,1 ; takes 24 clock cycles
- OR AL,30H ; add ascii bias
- STOSB ; save
- MOV AL,AH ; get back ah
- AND AL,0FH ; mask lo nibble
- OR AL,30H ; add ascii bias
- STOSB ; save
- MOV AX,BX ; get back word
- MOV AH,AL ; save low byte
- LOOP UNPL ; local loop
- XCHG CX,DX ; restore external count
- LOOP BINDU ; finish all packed BCDs
- POP DI ; recover buffer pointer
- POP SI ; old saved si
- POP CX
- POP BX
- ;-----------------------------------------------------------------------
- PUBLIC BLANK
- ; Replace leading zeros by space
- BLANK:
- PUSH DI
- BLANKL: CMP BYTE PTR [DI],'0'
- JNZ BLANKE
- MOV BYTE PTR [DI],' '
- INC DI
- JMP SHORT BLANKL
- BLANKE: POP DI
- RET
-
- TMPBUF DW 2 DUP(0)
-
- EVEN
- STK EQU $+256
- BUF EQU STK+4
- NUMBUF EQU BUF
- START ENDS
- END FIRST
- ;-----------------------------------------------------------------------
-