home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 15 / CDACTUAL15.iso / cdactual / program / asm / LMPRIME1.ZIP / LMPRIME1.ASM next >
Encoding:
Assembly Source File  |  1991-11-26  |  17.9 KB  |  795 lines

  1.     TITLE    LMPRIME1        ; Bill Parke's PRIME14 modified for 80386
  2.  
  3. PAGE    60,132
  4. BELL    EQU    7
  5. TAB    EQU    9
  6. CR    EQU    13
  7. LF    EQU    10
  8.  
  9. IS8087    EQU    0            ; Change to 1 for use with an 80x87 math coprocessor
  10.  
  11.     .386
  12. START    SEGMENT USE16
  13.     ASSUME    CS:START,DS:START,ES:START,SS:START
  14.     ORG    100H
  15.  
  16. FIRST:    JMP    BEGIN
  17.  
  18.     DB    'Copyright Les Moskowitz 1991'
  19. NPS1    DB    CR,LF,'There are$'
  20. NPS2    DB    ' primes$'
  21. NPS2A    DB    ' between$'
  22. NPS3    DB    ' and$'
  23. ERROR    DB    'Error in ',BELL
  24. DHELP    DB    'Syntax:  LMPRIME1 n1 n2 [/]',CR,LF
  25.     DB    TAB,TAB,'where 0 < n1 < n2 < 4,294,967,295',CR,LF
  26.     DB    TAB,TAB,'Optional / will suppress listing of individual primes'
  27. CRLF    DB    CR,LF,'$'
  28. NOT386    DB    BELL,CR,LF,'Sorry - This program needs an 80386 cpu.',CR,LF,'$'
  29.  
  30. IF    IS8087
  31. CW    DW    0000101110111111B    ; 8087 control word - round up
  32. ENDIF
  33.  
  34. STSI    DD    0
  35. LSTB    DD    0
  36. INIM    DB    0
  37. ERIN    DB    0
  38. FLG1    DB    0            ; Used to test for n1 < 3.
  39. FLG2    DB    0            ; 0 - show all primes; 1 - suppress primes
  40.  
  41. ; The next 4 items must be in this order
  42. NO1A    DD    ?
  43. NPRINT1 DD    ?            ; Starting number
  44. NPRINT2 DD    ?            ; Ending number
  45. NO2A    DD    ?
  46.  
  47. SSIZE    DW    0            ; Sieve size (numbers) = square root of n2
  48. THISPRIME DT    ?            ; Current prime in packed BCD format
  49. TMPBUF    DQ    0
  50. SIFLAG    DB    0            ; 0 - working on 1-ssize, 1 - working on n1-n2
  51. SSIZE2    DD    0            ; Sieve size divided by 8
  52. ARGSIZE DW    ?
  53. N23    DD    ?
  54. NPRIME    DD    0            ; Number of primes
  55. EXTRA    DB    0
  56. DIGITS    DW    ?            ; Required digits (including leading space)
  57. NLINE    DW    ?            ; Number of primes to print per line
  58. TLINE    DW    ?
  59. SSIZEF    DW    1            ; Odd numbers starting with 1
  60. NP$    DB    10 DUP ('0')
  61. NP1    DB    '0$  '
  62. NPADDR    DW    OFFSET NP$
  63.  
  64. BEGIN:    CALL    CHK386            ; Make sure this is a 386 cpu
  65.     JC    SHORT EXIT        ; If not, then exit
  66.     CALL    SETUP            ; Get command line input and initialize
  67.     JC    SHORT EXIT        ; Exit, if we got an error
  68. BEG2:    CALL    BUFFER            ; Set up 64k buffer for our data
  69.     MOV    BL,1
  70.     CALL    NOCOMP            ; Eliminate all composite numbers
  71.     CALL    FINI            ; Print our remaining prime numbers
  72.     PUSH    DS
  73.     POP    ES
  74.     MOV    SI,OFFSET NPRINT2
  75.     MOV    DI,OFFSET NO2A
  76.     CMPSD
  77.     JE    SHORT EXIT
  78.     MOV    SSIZEF,1
  79.     XOR    EAX,EAX
  80.     MOV    SI,OFFSET NPRINT2
  81.     MOV    DI,OFFSET NPRINT1
  82.     MOVSD                ; NPRINT2 --> NPRINT1
  83.     MOVSD                ; NO2A --> NPRINT2
  84.     INC    NPRINT1
  85.     MOV    DI,OFFSET SSIZE
  86.     CALL    SQROOT            ; Store square root of NPRINT2 in SSIZE
  87.     CALL    SET4
  88.     JMP    BEG2
  89. EXIT:    PUSH    CS
  90.     POP    ES
  91.     MOV    AL,ERIN
  92.     OR    AL,AL            ; Was there an error ?
  93.     JNZ    SHORT EXITE        ; Yes  - exit immediately
  94.     CALL    SUMMARY         ; Indicate the total number of primes
  95.     CALL    SCRLF
  96.     MOV    AX,4C00H
  97.     INT    21H            ; Exit - everything ok
  98. EXITE:    MOV    AH,9            ; Print out the error message
  99.     INT    21H
  100.     MOV    AH,4CH
  101.     INT    21H            ; Exit with error level set to ERIN
  102.  
  103. CHK386    PROC    NEAR            ; Set the carry flag if not an 80386 cpu
  104.     PUSHF
  105.     POP    BX
  106.     MOV    AX,0FFFH
  107.     AND    AX,BX
  108.     PUSH    AX
  109.     POPF
  110.     PUSHF
  111.     POP    AX
  112.     AND    AX,0F000H
  113.     CMP    AX,0F000H
  114.     JE    SHORT NO        ; We're finished - it's an 8086
  115.     OR    BX,0F000H
  116.     PUSH    BX
  117.     POPF
  118.     PUSHF
  119.     POP    AX
  120.     AND    AX,0F000H
  121.     JNZ    SHORT YES        ; We're finished - it's an 80386 or 80486
  122. NO:    STC
  123.     MOV    DX,OFFSET NOT386
  124.     RET
  125. YES:    CLC
  126.     RET
  127. CHK386    ENDP
  128.  
  129. SETUP    PROC    NEAR            ; Initialize everything
  130.     XOR    EAX,EAX         ; Make sure these registers are
  131.     XOR    EBX,EBX         ;    initially set to zero.
  132.     XOR    ECX,ECX         ;    NOTE - DOS doesn't automatically
  133.     XOR    EDX,EDX         ;    do this for the high order bytes
  134.     XOR    ESI,ESI         ;    in 32-bit registers.
  135.     CALL    SCRLF
  136.     MOV    SI,80H
  137.     LODSB
  138.     MOV    CL,AL
  139.     MOV    AL,'/'
  140.     MOV    DI,81H
  141.     REPNE    SCASB            ; Total number of primes only?
  142.     SETZ    FLG2            ; Set the flag to 1 if found
  143.     CMP    BYTE PTR [DI],'?'
  144.     JNE    SHORT SET0
  145.     MOV    DX,OFFSET DHELP
  146.     INC    ERIN
  147.     STC
  148.     RET
  149. SET0:    MOV    SI,81H
  150.     MOV    DI,OFFSET TMPBUF
  151.     CALL    GETNUM            ; Get first number from the command line
  152.     JNC    SHORT SET2        ; Continue unless we got an error
  153. SET1:    INC    ERIN            ; If there's an error, then we're finished
  154.     MOV    DX,OFFSET ERROR
  155.     STC
  156.     RET
  157. SET2:    JCXZ    SHORT SET3
  158.     PUSH    SI
  159.     MOV    SI,OFFSET TMPBUF
  160.     MOV    DI,OFFSET NPRINT1
  161.     CALL    DECBIN32        ; Store n1 in NPRINT1 as binary number
  162.     POP    SI
  163.     PUSH    NPRINT1
  164.     POP    NO1A
  165.     JC    SET1            ; Exit if number exceeds 4,294,967,296
  166.     MOV    DI,OFFSET TMPBUF
  167.     CALL    GETNUM            ; Get second number from the command line
  168.     JC    SET1            ; Exit if we got an error
  169.     PUSH    DS
  170.     XOR    AX,AX
  171.     MOV    DS,AX
  172.     MOV    SI,44AH
  173.     LODSB                ; AL now contains the screen width
  174.     POP    DS
  175.     INC    CL
  176.     MOV    DIGITS,CX
  177.     DIV    CL
  178.     DEC    CL
  179.     CMP    AH,0
  180.     JNE    SHORT KEEP
  181.     DEC    AL
  182. KEEP:    CBW
  183.     MOV    NLINE,AX
  184.     INC    AX
  185.     MOV    TLINE,AX
  186.     ADD    NPADDR,10
  187.     SUB    NPADDR,CX
  188. SET3:    MOV    SI,OFFSET TMPBUF
  189.     MOV    DI,OFFSET NPRINT2
  190.     CALL    DECBIN32        ; Store n2 in NPRINT2 as binary number
  191.     PUSH    NPRINT2
  192.     POP    NO2A
  193.     JC    SET1            ; Exit if number exceeds 4,294,967,296
  194.     MOV    DI,OFFSET SSIZE
  195.     CALL    SQROOT            ; Store square root of NPRINT2 in SSIZE
  196. SET4:    MOV    EBX,DWORD PTR [DI]
  197.     SHR    EBX,3
  198.     MOV    SSIZE2,EBX
  199.     MOV    ECX,NPRINT2        ; n2
  200.     MOV    ESI,NPRINT1        ; n1
  201.     MOV    DX,OFFSET DHELP
  202.     OR    ESI,0            ; Is n1 = 0 ?
  203.     JZ    SHORT SET5        ; Yes - print help message and exit
  204.     CMP    ESI,ECX         ; Is n1 < n2 ?
  205.     JB    SHORT SET6
  206.     MOV    DX,OFFSET ERROR
  207. SET5:    INC    ERIN            ; No - print error message and exit
  208.     STC
  209.     RET
  210. SET6:    CMP    ESI,3
  211.     SETB    FLG1
  212.     OR    ESI,1            ; Make nprint1 odd
  213.     TEST    CX,1            ; Is nprint2 odd?
  214.     JNZ    SHORT SET7        ; Yes - jump
  215.     DEC    ECX            ; No  - we don't need the last even number
  216.     OR    FLG1,00000010B
  217. SET7:    MOV    EBX,ESI         ; Nprint1
  218.     AND    EBX,0FH         ; Start to print after div by 16
  219.     SHR    BX,1            ; Get bit index for starting number
  220.     MOV    EAX,ESI         ; N23 will be the number represented
  221.     SHR    EAX,4            ;    by bit 0 of the byte at
  222.     SHL    EAX,4            ;    STSI.
  223.     INC    EAX
  224.     MOV    N23,EAX
  225.     SHR    ESI,4            ; Divide first number by 16
  226.     MOV    STSI,ESI
  227.     MOV    AX,CX            ; Nprint2
  228.     AND    AX,0FH            ; Extra to print
  229.     SHR    AX,1            ; But only odds
  230.     MOV    EXTRA,AL
  231.     MOV    EDX,ECX         ; Save index of last byte-mask to print
  232.     SHR    EDX,4            ; Divide second number by 16
  233.     MOV    EBP,STSI
  234.     CMP    EBP,SSIZE2
  235.     JB    SHORT SET8
  236.     SUB    EDX,STSI
  237.     ADD    EDX,SSIZE2
  238. SET8:    MOV    EBP,EDX
  239.     MOV    LSTB,EDX         ; Last byte pointer
  240.     INC    EDX
  241.     SUB    EDX,SSIZE2
  242.     CMP    EDX,65536
  243.     MOV    ARGSIZE,DX
  244.     JAE    SHORT SET10
  245.     CMP    DX,3584         ; Test is not necessary if DX<2^16 - 2^16/8
  246.     JBE    SHORT SET9        ; (n2 can be any number up to 2^32)
  247.     SUB    EDX,65536        ; Otherwise, make sure that
  248.     NEG    EDX            ;    our test range lies
  249.     SHL    EDX,3            ;    within 1 64k sector
  250.     MOV    EAX,EDX
  251.     MUL    EAX            ; EDX:EAX now contains maximum allowable n2
  252.     JC    SHORT SET9        ; We're ok if EDX>0, otherwise
  253.     MOV    EDX,NPRINT2        ; Check EAX against the requested value
  254.     CMP    EDX,EAX
  255.     JA    SHORT SET10
  256. SET9:    MOV    CL,BL
  257.     AND    CL,00000111B        ; CL cannot exceed 7
  258.     MOV    INIM,1
  259.     SHL    INIM,CL         ; Get initial mask
  260.     XOR    EDX,EDX
  261.     XOR    ESI,ESI
  262.     CLC
  263.     RET
  264.  
  265. ; Replace value in nprint2 with 1048545+n1-2(n1+1048545)^.5
  266. ; Note - If n1 > 4293918750, then n1+1048545 will be greater than 4294967295
  267. ;     which will cause a carry error.  In this case, set nprint2 equal to
  268. ;     4294443023, which is halfway between 4293918750 and 4294967295.
  269. ; n1 and n2 must satisfy the relationship: n2/16 + (n2^.5)/8  <  65536 + n1/16
  270.  
  271. SET10:    TEST    FLG1,10B
  272.     JZ    SHORT SET11
  273.     INC    ECX
  274. SET11:    MOV    NO2A,ECX
  275.     MOV    DI,OFFSET NPRINT2
  276.     MOV    ECX,NPRINT1
  277.     ADD    ECX,1048545
  278.     JNC    SHORT SET12
  279.     MOV    EAX,4294443023
  280.     JMP    SHORT SET13
  281. SET12:    MOV    NPRINT2,ECX
  282.     CALL    SQROOT            ; Store square root of NPRINT2 in NPRINT2
  283.     MOV    SI,OFFSET NPRINT2
  284.     LODSD
  285.     SHL    EAX,1
  286.     SUB    ECX,EAX
  287.     MOV    EAX,ECX
  288. SET13:    STOSD
  289.     MOV    DI,OFFSET SSIZE
  290.     CALL    SQROOT            ; Store square root of NPRINT2 in SSIZE
  291.     JMP    SET4
  292. SETUP    ENDP
  293.  
  294. BUFFER    PROC    NEAR
  295.     MOV    AX,OFFSET STK
  296.     POP    BX
  297.     MOV    SP,AX
  298.     PUSH    BX
  299.     MOV    BX,AX
  300.     PUSH    DS
  301.     POP    AX
  302.     ADD    BX,15
  303.     SHR    BX,4
  304.     ADD    AX,BX
  305.     MOV    ES,AX
  306.     MOV    DS,AX
  307.     XOR    EAX,EAX
  308.     MOV    SI,AX
  309.     MOV    DI,AX
  310.     MOV    CX,16384
  311.     REP    STOSD            ; Zero 64K buffer
  312.     RET
  313. BUFFER    ENDP
  314.  
  315. ; At this point everything has been initialized.  We now start to eliminate
  316. ; all the composite numbers from 1-ssize and from n1-n2.
  317.  
  318. NOCOMP    PROC    NEAR
  319.     ASSUME    ES:NOTHING,DS:NOTHING
  320.     MOV    SIFLAG,0
  321.     ADD    SSIZEF,2        ; Next odd number
  322.     JC    SHORT NCMP1
  323.     CMP    SSIZE,0
  324.     JE    SHORT NCMPX
  325.     MOV    AX,SSIZEF
  326.     CMP    AX,SSIZE
  327.     JA    SHORT NCMP1
  328. NCMPX:    INC    CL            ; pointer in 8 bits
  329.     ROL    BL,1            ; bit mask, 8 bit roll and set Composite
  330.     JNC    SHORT NCMP2
  331.     XOR    CL,CL            ; Reset the bit counter back to zero
  332.     INC    SI
  333.     CMP    ESI,EBP
  334.     JB    SHORT NCMP2
  335. NCMP1:    RET
  336. NCMP2:    MOV    AL,[SI]
  337.     AND    AL,BL            ; is it a prime, i.e. still a zero bit?
  338.     JNZ    NOCOMP            ; no, its bit is set to 1
  339.     PUSH    BX
  340.     PUSH    CX            ; save bit counter
  341.     PUSH    ESI            ; save byte pointer
  342.  
  343.     MOV    BX,SSIZEF
  344.     MOV    DI,BX
  345.     MOV    EAX,EBX
  346.     SHR    DI,3
  347.     AND    BX,7
  348.     MUL    EAX
  349.     MOV    DX,BX
  350.     MOV    ESI,EAX
  351.     MOV    CX,AX
  352.     CMP    SSIZE,0
  353.     JE    SHORT NCMP3
  354.     MOV    AX,SSIZEF
  355.     CMP    AX,SSIZE
  356.     JB    SHORT NCMP3
  357.     POP    ESI
  358.     POP    CX
  359.     POP    BX
  360.     RET
  361. NCMP3:    SHR    ESI,4
  362.     AND    CX,0FH
  363.     SHR    CX,1
  364.     CMP    ESI,EBP
  365.     JB    SHORT NCMP6
  366.     MOV    SIFLAG,1
  367.     CMP    ESI,SSIZE2
  368.     JB    NCMP12
  369.     MOV    ESI,SSIZE2        ; We get here if ESI > EBP and
  370.     JMP    NCMP7            ;    SSIZE2 <= SI
  371.  
  372. NCMP4:    ADD    SI,DI            ; point to next non-prime byte
  373.     JC    NCMP12
  374.     ADD    CX,DX            ; point to next non-prime bit in byte
  375.     CMP    CL,8
  376.     JB    SHORT NCMP5
  377.     SUB    CL,8
  378.     INC    SI            ; Don't allow SI to cross the
  379.     JZ    NCMP12            ;    segment boundary
  380.  
  381. NCMP5:    CMP    ESI,EBP
  382.     JBE    SHORT NCMP6
  383.     XOR    SIFLAG,1        ; Reverse the flag
  384.     JZ    NCMP12            ; Jump if it was previously 1
  385.  
  386.     CMP    STSI,ESI
  387.     JBE    NCMP12
  388.  
  389.     MOV    ESI,EBP         ; We get here if EBP < ESI < STSI
  390.     SUB    SI,ARGSIZE
  391.     INC    SI
  392.     JMP    SHORT NCMP7
  393. NCMP6:    CMP    SIFLAG,1
  394.     JE    SHORT NCMP11
  395.  
  396.     CMP    ESI,SSIZE2
  397.     JB    SHORT NCMP11
  398.     CMP    STSI,ESI
  399.     JBE    SHORT NCMP11
  400.  
  401.     MOV    SIFLAG,1        ; We get here if ESI <= EBP and
  402.     MOV    ESI,SSIZE2        ;    SSIZE2 <= SI < STSI
  403.  
  404. ; We get here the first time we enter the second area (n1 through n2).    This
  405. ; area re-calculates our byte pointer (SI) and our bit pointer (CL).
  406. NCMP7:    PUSH    EBX
  407.     PUSH    EDX
  408.     XOR    DX,DX
  409.     MOV    BX,DX
  410.     MOV    EAX,N23
  411.     MOV    BX,SSIZEF
  412.     DIV    EBX            ; remainder in EDX
  413.     MOV    ECX,EDX
  414.     CMP    ECX,0
  415.     JE    SHORT NCMP9
  416.     NEG    ECX
  417.     ADD    ECX,EBX
  418.     TEST    ECX,1            ; Is it odd?
  419.     JE    SHORT NCMP8        ; No it's even - jump
  420.     ADD    ECX,EBX         ; Yes
  421. NCMP8:    SHR    ECX,1
  422. NCMP9:    CMP    ECX,8
  423.     JB    SHORT NCMP10
  424.     SUB    ECX,8
  425.     INC    ESI
  426.     CMP    ESI,EBP
  427.     JBE    NCMP9
  428.     POP    EDX
  429.     POP    EBX
  430.     JMP    SHORT NCMP12
  431. NCMP10: POP    EDX
  432.     POP    EBX
  433.  
  434. NCMP11: MOV    AL,1
  435.     SHL    AL,CL
  436.     OR    [SI],AL         ; mask this bit to show non-prime
  437.     JMP    NCMP4
  438. NCMP12: POP    ESI            ; byte pointer
  439.     POP    CX            ; bit counter
  440.     POP    BX
  441.     JMP    NOCOMP
  442. NOCOMP    ENDP
  443.  
  444. ; At this point we have all our prime numbers set.  The only thing left to
  445. ; do is to print them on the screen.
  446.  
  447. FINI    PROC    NEAR
  448.     ASSUME    DS:START,ES:START
  449.     PUSH    CS
  450.     POP    DS
  451.     MOV    DI,OFFSET NP$
  452.     MOV    ECX,LSTB         ; last byte pointer
  453.     MOV    EAX,STSI
  454.     CMP    EAX,SSIZE2
  455.     JBE    SHORT FINI1
  456.     MOV    EAX,SSIZE2
  457. FINI1:    MOV    ESI,EAX         ; initial byte pointer
  458.     MOV    AL,INIM         ; initial mask
  459.     TEST    FLG1,1
  460.     JZ    SHORT FINI2
  461.     DEC    TLINE
  462.     MOV    EDX,2            ; Force the first prime to be 2
  463.     INC    NPRIME
  464.     MOV    AL,2
  465.     CMP    FLG2,1            ; Suppress individual primes ?
  466.     JE    SHORT FINI2
  467.     CALL    PRT3
  468.     MOV    AL,2
  469. FINI2:    CMP    ECX,ESI
  470.     JE    SHORT FINI4
  471. FINI3:    CALL    PRTEST
  472.     JNC    FINI3
  473.     INC    SI            ; Prepare to address the next byte
  474.     CMP    SI,CX            ; Have we reached the end ?
  475.     JB    FINI3            ; Not yet - go check out this byte
  476. FINI4:    XOR    CX,CX
  477.     MOV    CL,EXTRA
  478.     MOV    CH,1
  479.     SHL    CH,CL
  480.     ROL    CH,1
  481. FINI5:    CALL    PRTEST
  482.     CMP    AL,CH
  483.     JNE    FINI5
  484.     RET
  485. FINI    ENDP
  486.  
  487. PRINT    PROC    NEAR
  488.     BSF    BX,AX
  489.     SHL    BX,1
  490.     INC    BX
  491.     DEC    TLINE            ; # on line
  492.     JNZ    SHORT PRT1        ; Jump if more numbers for this line
  493.     CALL    SCRLF            ; Scroll screen 1 line
  494.     PUSH    NLINE            ; Move this number
  495.     POP    TLINE            ;    into this area
  496. PRT1:    XOR    EDX,EDX
  497.     MOV    DX,SI
  498.     MOV    EAX,STSI
  499.     CMP    EAX,SSIZE2
  500.     JB    SHORT PRT2
  501.     ADD    EDX,STSI
  502.     SUB    EDX,SSIZE2
  503. PRT2:    SHL    EDX,4
  504.     ADD    EDX,EBX
  505. PRT3:    PUSH    CX
  506.     PUSH    SI
  507.     PUSH    ES
  508.     PUSH    CS
  509.     POP    ES
  510.     MOV    DI,OFFSET NP$
  511.     CALL    BINDEC32        ; Convert binary EDX to decimal ES:DI
  512.     MOV    SI,[NPADDR]
  513.     MOV    AH,2
  514.     MOV    CX,DIGITS
  515. OUTDS:    LODSB
  516.     MOV    DL,AL
  517.     INT    21H
  518.     LOOP    OUTDS
  519.     POP    ES
  520.     POP    SI
  521.     POP    CX
  522.     RET
  523. PRINT    ENDP
  524.  
  525. PRTEST    PROC    NEAR
  526.     MOV    AH,AL
  527.     AND    AH,ES:[SI]        ; Test this bit to see if it's a prime
  528.     PUSH    AX            ; Store AX
  529.     JNZ    SHORT PRTEST1        ; Jump if not a prime
  530.     INC    NPRIME
  531.     CMP    FLG2,1
  532.     JE    SHORT PRTEST1
  533.     CALL    PRINT
  534. PRTEST1:POP    AX            ; Recall AX
  535.     ROL    AL,1            ; Get ready to look at the next bit
  536.     RET
  537. PRTEST    ENDP
  538.  
  539. PRTX    PROC    NEAR
  540.     MOV    DI,OFFSET NP$
  541.     CALL    BINDEC32        ; Convert binary EDX to decimal ES:DI
  542.     MOV    SI,[NPADDR]
  543.     MOV    AH,2
  544.     MOV    CX,DIGITS
  545. OUTDS2: LODSB
  546.     CMP    BYTE PTR [SI],' '
  547.     JE    SHORT PRTX2
  548.     MOV    DL,AL
  549.     INT    21H
  550. PRTX2:    LOOP    OUTDS2
  551.     RET
  552. PRTX    ENDP
  553.  
  554. GETNUM    PROC    NEAR
  555. GETN0:    CMP    BYTE PTR [SI],' '    ; Ignore any leading blanks
  556.     JNE    SHORT SKIPE
  557.     INC    SI
  558.     JMP    GETN0
  559. SKIPE:    XOR    CX,CX            ; Initialize the digit counter
  560. GETN1:    LODSB                ; Get the first digit
  561.     CMP    AL,CR            ; Carriage return?
  562.     JE    SHORT GETNE        ; Yes - we've gotten all our digits
  563.     CMP    AL,' '            ; Space?
  564.     JE    SHORT GETNE        ; Yes - we've gotten all our digits
  565.     CMP    AL,3AH            ; Below 3Ah? (this will determine carry flag)
  566.     CMC                ; Reverse the carry flag
  567.     JC    SHORT CKNE        ; Jump if AL > 3Ah
  568.     CMP    AL,30H            ; If AL >= 30h then AL is an ASCII number.
  569. CKNE:    JB    SHORT GETNC        ; If AL < 30h, we're finished.
  570.     INC    CL            ; Otherwise, increase the digit counter
  571.     STOSB                ;    store this digit and
  572.     JMP    GETN1            ;    look for our next digit
  573. GETNC:    RET                ; Return with carry flag set
  574. GETNE:    CMP    CL,11            ; First set the carry less than 11 digits
  575.     CMC                ; Then reverse (clear) the carry flag
  576.     RET                ; Return
  577. GETNUM    ENDP
  578.  
  579. ; Convert ascii decimal value in DS:SI to binary dword - result goes into ES:DI
  580. ; EAX register destroyed
  581. DECBIN32 PROC    NEAR
  582.     PUSH    EBX
  583.     XOR    EBX,EBX         ; zero initial binary double word
  584.     MOV    EAX,EBX         ;    and our decimal digit holder
  585.     JMP    SHORT DECBS        ; skip first multiplication
  586. DECBL:    IMUL    EBX,10            ; multiply EBX by 10
  587. DECBS:    LODSB                ; get next decimal
  588.     SUB    AL,30H            ; drop ascii bias
  589.     ADD    EBX,EAX         ; add next decimal to word
  590.     LOOP    DECBL            ; continue for the rest of the digits
  591.     MOV    EAX,EBX
  592.     STOSD
  593.     POP    EBX
  594.     RET
  595. DECBIN32 ENDP
  596.  
  597. SCRLF    PROC    NEAR
  598.     MOV    DX,OFFSET CRLF
  599.     MOV    AH,9
  600.     INT    21H
  601.     RET
  602. SCRLF    ENDP
  603.  
  604. ; Convert 32 bit binary number in EDX to decimal - result in ES:DI
  605. BINDEC32 PROC    NEAR
  606. IF    IS8087
  607.  
  608.     PUSH    DI
  609.     PUSH    CX
  610.     PUSH    SI
  611.     MOV    DWORD PTR TMPBUF+4,0
  612.     MOV    DWORD PTR TMPBUF,EDX
  613.     FINIT
  614.     FILD    TMPBUF            ; Load EDX
  615.     FBSTP    THISPRIME        ; Store it as a packed BCD
  616.     MOV    SI,OFFSET THISPRIME
  617.     MOV    AL,'0'
  618.     STOSB
  619.     MOV    AL,[SI+4]
  620.     MOV    AH,AL
  621.     ROL    AL,4
  622.     AND    AX,0F0FH
  623.     OR    AX,3030H
  624.     STOSW
  625.     MOV    CX,8
  626.     LODSD
  627. BINLOOP:ROL    EAX,4
  628.     PUSH    EAX
  629.     AND    AL,0FH
  630.     OR    AL,30H
  631.     STOSB
  632.     POP    EAX
  633.     LOOP    BINLOOP
  634.     POP    SI
  635.     POP    CX
  636.     POP    DI
  637.     PUSH    DI
  638.  
  639. ELSE
  640.     PUSH    BX
  641.     PUSH    CX
  642.     PUSH    SI
  643.     PUSH    DI
  644.     MOV    ESI,EDX         ; save binary double word
  645.     XOR    AX,AX            ; zero high decimal accumulator
  646.     MOV    BX,AX            ; BX will hold high packed BCD
  647.     MOV    DX,AX            ; DX will hold low packed BCD
  648.     MOV    CX,32            ; use all 32 bits of double word
  649. BIND1:    SHL    ESI,1            ; shift low word left
  650.     XCHG    DX,AX            ; use DX low 4 digits first
  651.     ADC    AL,AL            ; add al to al with carry bit
  652.     DAA                ; decimal adj al
  653.     XCHG    AL,AH            ; now do the same with ah
  654.     ADC    AL,AL            ; double and add carry
  655.     DAA                ; decimal adj
  656.     XCHG    AL,AH            ; restore ax order
  657.     XCHG    DX,AX            ; save resultant low BCD quartet
  658.     XCHG    BX,AX            ; now use BX high 4 digits
  659.     ADC    AL,AL            ; add al to al with carry bit
  660.     DAA                ; decimal adj al
  661.     XCHG    AL,AH            ; now do the same with ah
  662.     ADC    AL,AL            ; double and add carry
  663.     DAA                ; decimal adj
  664.     XCHG    AL,AH            ; restore ax order
  665.     XCHG    BX,AX            ; save resultant high BCD quartet
  666.     ADC    AL,AL            ; accum highest digits in AL
  667.     DAA                ;  as a pair of BCDs
  668.     LOOP    BIND1            ; do all 32 bits
  669.     MOV    SI,OFFSET TMPBUF    ; our temporary buffer for packed BCD
  670.     MOV    [SI],BX         ; middle word
  671.     MOV    [SI+2],DX        ; low word
  672.     MOV    CX,1            ; local count
  673.     MOV    DX,3            ; anticipate two more words to unpack
  674.     MOV    AH,AL            ; save nibble pair
  675.     PUSH    AX
  676.     MOV    AL,'0'
  677.     STOSB
  678.     POP    AX
  679.     JMP    SHORT UNPL        ; start with first nibble pair
  680. BINDU:                    ; expand packed BCD to ascii string
  681.     XCHG    DX,CX            ; save external count
  682.     LODSW                ; get packed BCD word
  683.     MOV    CX,2            ; local count
  684.     MOV    BX,AX            ; save ax
  685.     MOV    AL,AH            ; start with ah
  686. UNPL:    SHR    AL,4            ; shift hi nibble
  687.     OR    AL,30H            ; add ascii bias
  688.     STOSB                ; save
  689.     MOV    AL,AH            ; get back ah
  690.     AND    AL,0FH            ; mask lo nibble
  691.     OR    AL,30H            ; add ascii bias
  692.     STOSB                ; save
  693.     MOV    AX,BX            ; get back word
  694.     MOV    AH,AL            ; save low byte
  695.     LOOP    UNPL            ; local loop
  696.     XCHG    CX,DX            ; restore external count
  697.     LOOP    BINDU            ; finish all packed BCDs
  698.     POP    DI
  699.     POP    SI
  700.     POP    CX
  701.     POP    BX
  702.     PUSH    DI
  703.  
  704. ENDIF
  705.  
  706. BLANKL: CMP    BYTE PTR [DI],'0'    ; Replace leading zeros with blanks,
  707.     JNE    SHORT BLANKE
  708.     MOV    BYTE PTR [DI],' '
  709.     INC    DI
  710.     JMP    BLANKL
  711. BLANKE: POP    DI
  712.     RET
  713. BINDEC32 ENDP
  714.  
  715. SUMMARY PROC    NEAR
  716.     CMP    NPRIME,1
  717.     JNE    SHORT SUMM1
  718.     MOV    SI,OFFSET NPS1
  719.     MOV    DWORD PTR [SI+7],'$si ' ; If 1 prime, change "There are" to "There is"
  720.     MOV    SI,OFFSET NPS2
  721.     MOV    BYTE PTR [SI+6],'$'    ;    and change "primes" to "prime"
  722. SUMM1:    MOV    DX,OFFSET NPS1        ; CR,LF,'There are$'
  723.     MOV    AH,9
  724.     INT    21H
  725.     MOV    EDX,NPRIME        ; Total number of primes
  726.     OR    EDX,0            ; Any primes ?
  727.     JE    SHORT SUMM2        ; If 0, change to the word "no"
  728.     CALL    PRTX            ; Otherwise print the number
  729.     JMP    SHORT SUMM3        ;    and continue with the text
  730. SUMM2:    MOV    DWORD PTR NP1,'$on '    ; ' no$'
  731.     MOV    DX,OFFSET NP1
  732.     MOV    AH,9
  733.     INT    21H
  734. SUMM3:    MOV    DX,OFFSET NPS2        ; ' primes$'
  735.     MOV    AH,9
  736.     INT    21H
  737.     MOV    DX,OFFSET NPS2A     ; ' between$'
  738.     MOV    AH,9
  739.     INT    21H
  740.     MOV    EDX,[NO1A]        ; Starting number
  741.     CALL    PRTX
  742.     MOV    DX,OFFSET NPS3        ; ' and$'
  743.     MOV    AH,9
  744.     INT    21H
  745.     MOV    EDX,[NPRINT2]        ; Ending number
  746.     CALL    PRTX
  747.     RET
  748. SUMMARY ENDP
  749.  
  750. IF    IS8087
  751.  
  752. SQROOT    PROC    NEAR            ; Store square root of NPRINT2 in ES:DI
  753.     FINIT
  754.     FLDCW    CW            ; Set 8087 control word
  755.     MOV    DWORD PTR TMPBUF+4,0    ; Needed in case nprint2 > 2,147,483647
  756.     PUSH    NPRINT2
  757.     POP    DWORD PTR TMPBUF
  758.     FILD    TMPBUF            ; Load nprint2 into the 8087
  759.     FSQRT                ; Calculate the exact square root
  760.     FIST    DWORD PTR ES:[DI]    ; Store it, rounding to the next higher integer
  761.     RET
  762. SQROOT    ENDP
  763.  
  764. ELSE
  765.  
  766. SQROOT    PROC    NEAR            ; Estimate square root of nprint2 using
  767.     PUSH    EAX            ; 2**(k-1) + nprint2/2**(k+1) where k
  768.     PUSH    ECX            ; is the largest integer for which
  769.     PUSH    EDX            ; nprint2 = 2**2k
  770.     MOV    EAX,NPRINT2
  771.     MOV    EDX,EAX
  772.     BSR    ECX,EAX
  773.     INC    CX
  774.     SHR    CX,1            ; k
  775.     MOV    AX,1
  776.     SHL    EAX,CL            ; 2**k
  777.     INC    CX            ; k+1
  778.     SHR    EDX,CL            ; nprint2/2**(k+1)
  779.     SHR    EAX,1            ; 2**(k-1)
  780.     ADD    AX,DX
  781.     INC    AX
  782.     STOSW
  783.     POP    EDX
  784.     POP    ECX
  785.     POP    EAX
  786.     RET
  787. SQROOT    ENDP
  788.  
  789. ENDIF
  790.  
  791.     EVEN
  792. STK    EQU    $+512
  793. START    ENDS
  794.     END    FIRST
  795.