Assemble Your Primes

In todays code example we are going to look at a bit of code in MASM Assembly that calculates a series of prime numbers up to a user given value. Enjoy.

TITLE Lab7 - No Calculus Primes! (Lab7.asm)

; Program Description: Calculate the first 1000 or so prime numbers
; Author: Bob Chatman
; Date: Nov. 20, 2008

INCLUDE Irvine32.inc

UPPERLIMIT		EQU 7919
NUMELEMENTS		EQU 999
FIRSTELEMENT	EQU 5
SIZEOFDATA		EQU 4
NUMPERLINE		EQU 10

.stack

.data
space				BYTE " "					, 0
upperLimitPrompt	BYTE "Upper Limit: "		, 0
upperLimitError		BYTE "Resetting to "		, 0
headerString		BYTE "The Primes are... "	, 0

primes				WORD 2, 3, NUMELEMENTS DUP(0)

StringOut MACRO s

    push EDX				; Save the EDX register
    mov EDX, OFFSET s		; Move the address in
    call WriteString		; Call the procedure to write it
    pop EDX					; Revert EDX

ENDM

IntOut MACRO i

    push EAX				; Save the EAX register
    mov EAX, i				; Move in the value
    call WriteDec			; Call the procedure to write it
    pop EAX					; Revert EAX
    StringOut space			; Output a space

ENDM

.code
main PROC

	; Reserve space for return value
    push OFFSET primes
    sub ESP, 4

    call GetLimit
    call GenPrimes

    ; Dont need this returned variable any more
    add ESP, 4

    call PrintPrimes

    exit

main ENDP

GetLimit PROC

    ; Set up the stack
    push EBP
    mov EBP, ESP

    ; Push Registers onto the stack
    push EAX

    ; Output the prompt and get the input
    StringOut upperLimitPrompt
    call ReadDec

    ; Make sure the input is within the limit
    cmp EAX, UPPERLIMIT
    jbe GOODINPUT

    ; Output an error message that we are changing the value
    StringOut upperLimitError
    IntOut UPPERLIMIT
    call CRLF

    ; Cant copy to the stack from immediate b/c of Immediate to memory issues
    mov EAX, UPPERLIMIT
    GOODINPUT:

	; Put the return value here
    mov [EBP + 8], EAX

	; Revert used registers
    pop EAX
    pop EBP

    ret
GetLimit ENDP

GenPrimes PROC

    ; Set up the stack, Again
    push EBP
    mov EBP, ESP

    ; Push Registers onto the stack
    push ECX
    push EBX
    push EAX
    push EDX
    push ESI

	; Setup our calculations
    mov CX, FIRSTELEMENT	; Start at 5
    mov EBX, [EBP + 12]		; Get the address of the array
    mov ESI, EBX			; Duplicate the EBX register
    add ESI, SIZEOFDATA		; Increment ESI to next open spot

    NEEDMOAR:

    DIVIDE:
    add EBX, 2				; Increment to next element [Begins at 3]
    mov AX, CX				; Revert AX to our test value
    mov DX, 0				; Clear out DX register for division
    div WORD PTR [ebx]		; Do some cool division
    cmp DX, 0				; Check the remainder
    JE NEXTNUMBER			; if its a clear division, jump
    cmp AX, WORD PTR [ebx]	; Compare the dividend to the divisor
    JA DIVIDE				; If its larger, jump and do again

    ; Add this value to our array and increment the walker register
    mov [ESI], CX
    add ESI, 2

	; Revert and increment our registers for the next pass.
    NEXTNUMBER:
    mov EBX, [EBP + 12]
    add CX, 2
    cmp CX, [EBP + 8]
    JBE NEEDMOAR			; Do we need more values?

	; Revert used registers
    pop ESI
    pop EDX
    pop EAX
    pop EBX
    pop ECX
    pop EBP

    ret
GenPrimes ENDP

PrintPrimes PROC

    ; Set up the stack, Again, Again
    push EBP
    mov EBP, ESP

    ; Push Registers onto the stack
    push EAX
    push EBX
    push ECX

    StringOut headerString
    call CRLF

    ; Setup registers
    mov ECX, NUMPERLINE
    mov EBX, [EBP + 8]
    mov EAX, 0
    mov AX, [EBX]

    NEXTELEMENT:

    IntOut EAX

    ; Check the counter value
    dec ECX
    cmp ECX, 0
    jne NONEXTLINE

    ; Revert the counter and call new line
    mov ECX, NUMPERLINE
    call CRLF

    NONEXTLINE:

	; Increment to the next element and check the value
    add EBX, 2
    mov AX, [EBX]
    cmp AX, 0
    jg NEXTELEMENT

	; Revert used registers
    pop ECX
    pop EBX
    pop EAX
    pop EBP

    ret
PrintPrimes ENDP

END main

Leave a Reply