Added MASM-Low_Level_IO.asm
This commit is contained in:
parent
9d36e78bc3
commit
5c90eb9c52
1 changed files with 348 additions and 0 deletions
348
MASM-Low_Level_IO.asm
Normal file
348
MASM-Low_Level_IO.asm
Normal file
|
@ -0,0 +1,348 @@
|
|||
TITLE Project 6 - String Primitives and Macros (MASM_Low-Level-IO.asm)
|
||||
|
||||
; Author: Andrew Scott
|
||||
; Last Modified: 2022-03-13
|
||||
; Course number/section: CS271 Section 400
|
||||
; Project Number: 6 Due Date: 2022-03-13
|
||||
; Description: Program asks for 10 signed integers from the user as strings.
|
||||
; The strings are converted from ASCII to SDWORDs and stored
|
||||
; in an array. Then, their sum, and the truncated average are
|
||||
; calculated. After the calculations all numbers entered by
|
||||
; the user as well as the results are converted back to their
|
||||
; ASCII representations and printed as strings.
|
||||
|
||||
INCLUDE Irvine32.inc
|
||||
|
||||
; name: mGetString
|
||||
; Gets a value from the user
|
||||
; preconditions: global variables are passed by reference
|
||||
; receives: global variables userPrompt, userInput, userInputLen
|
||||
; returns: stores user input in userInput
|
||||
mGetString MACRO prompt:REQ, inString:REQ, stringLen:REQ
|
||||
push EAX
|
||||
push ECX
|
||||
push EDX
|
||||
push EDI
|
||||
mov EDX, prompt
|
||||
call WriteString
|
||||
mov EDX, inString
|
||||
mov ECX, MAXSIZE
|
||||
call ReadString
|
||||
mov EDI, stringLen
|
||||
mov [EDI], EAX
|
||||
pop EDI
|
||||
pop EDX
|
||||
pop ECX
|
||||
pop EAX
|
||||
ENDM
|
||||
|
||||
; name: mDisplayString
|
||||
; Prints a string to the output
|
||||
; preconditions: strings must be passed by reference
|
||||
; receives: outString - offset of string to be written to output
|
||||
; returns: prints outString
|
||||
mDisplayString MACRO outString:REQ
|
||||
push EDX
|
||||
mov EDX, outString
|
||||
call WriteString
|
||||
pop EDX
|
||||
ENDM
|
||||
|
||||
MAXSIZE = 500
|
||||
|
||||
.data
|
||||
|
||||
projectTitle BYTE "Project 6 - String Primitives and Macros, by Andrew Scott",13,10,0
|
||||
description1 BYTE "You will be prompted to enter 10 signed decimal integers. Each integer must fit into a 32-bit register.",13,10,0
|
||||
description2 BYTE "After you've entered 10 valid integers this program will display the integers, their sum, and their truncated average",13,10,13,10,0
|
||||
userPrompt BYTE ". Please enter a signed number: ",0
|
||||
invalidInput BYTE "ERROR: You did not enter a signed number or your number was too big. Please Try again.",13,10,0
|
||||
listLabel BYTE 13,10,"You entered the following numbers:",13,10,0
|
||||
sumLabel BYTE 13,10,"The sum of these numbers is: ",0
|
||||
avgLabel BYTE 13,10,"The truncated average of these numbers is: ",0
|
||||
retryPrompt BYTE "ERROR: Input was not a signed number or was too big. Please try again.",13,10,13,10,0
|
||||
space BYTE " ",0
|
||||
ecOption BYTE "**EC1: Number each line of user input and display a running subtotal of the valid numbers.",13,10,13,10,0
|
||||
|
||||
userInput BYTE MAXSIZE DUP(?)
|
||||
userOutput BYTE MAXSIZE DUP(?)
|
||||
userInputLen DWORD 0
|
||||
userInputNum SDWORD 0
|
||||
inputIsValid DWORD 0
|
||||
userArray SDWORD 10 DUP(0)
|
||||
userArrayLen DWORD LENGTHOF userArray
|
||||
userArraySum SDWORD 0
|
||||
userArrayAvg SDWORD 0
|
||||
inputCount DWORD 1
|
||||
|
||||
.code
|
||||
main PROC
|
||||
; introduce the program
|
||||
push OFFSET projectTitle
|
||||
push OFFSET ecOption
|
||||
push OFFSET description1
|
||||
push OFFSET description2
|
||||
call introduction
|
||||
|
||||
; prepare to get values from user
|
||||
mov ECX, userArrayLen
|
||||
mov EDI, OFFSET userArray
|
||||
; get signed integers from user and store them
|
||||
_fillArray:
|
||||
push OFFSET space
|
||||
push OFFSET userOutput
|
||||
push OFFSET inputCount
|
||||
push OFFSET retryPrompt
|
||||
push OFFSET userPrompt
|
||||
push OFFSET userInput
|
||||
push OFFSET userInputLen
|
||||
push OFFSET userInputNum
|
||||
call ReadVal ; get user input
|
||||
inc inputCount
|
||||
mov EAX, userInputNum
|
||||
mov [EDI], EAX ; store user input
|
||||
mov EAX, 0
|
||||
add EDI, 4
|
||||
loop _fillArray
|
||||
|
||||
; calculate the sum
|
||||
mov ECX, userArrayLen ; prepare registers
|
||||
mov ESI, OFFSET userArray
|
||||
mov userArraySum, 0
|
||||
_calcSum:
|
||||
mov EAX, userArraySum ; begin addition
|
||||
mov EBX, [ESI]
|
||||
add EAX, EBX
|
||||
mov userArraySum, EAX
|
||||
add ESI, 4
|
||||
mov EAX, 0
|
||||
loop _calcSum
|
||||
; find average
|
||||
mov EAX, userArraySum
|
||||
cdq
|
||||
idiv userArrayLen
|
||||
mov userArrayAvg, EAX
|
||||
|
||||
; display all nums entered by user
|
||||
mov ECX, userArrayLen ; prepare registers and display label
|
||||
mov EDI, OFFSET userArray
|
||||
mov EDX, OFFSET listLabel
|
||||
mDisplayString EDX
|
||||
_displayNums: ; begin loop to print nums in userArray
|
||||
push OFFSET space
|
||||
push OFFSET userOutput
|
||||
push EDI
|
||||
call WriteVal
|
||||
add EDI, 4
|
||||
loop _displayNums
|
||||
call CrLf
|
||||
|
||||
; display sum
|
||||
push OFFSET sumLabel
|
||||
push OFFSET userOutput
|
||||
push OFFSET userArraySum
|
||||
call WriteVal
|
||||
call CrLf
|
||||
|
||||
; display truncated average
|
||||
push OFFSET avgLabel
|
||||
push OFFSET userOutput
|
||||
push OFFSET userArrayAvg
|
||||
call WriteVal
|
||||
call CrLf
|
||||
|
||||
Invoke ExitProcess,0 ; exit to operating system
|
||||
main ENDP
|
||||
|
||||
; name: introduction
|
||||
; Introduces the program
|
||||
; preconditions: global variables projectTitle, description1, and description2 are strings
|
||||
; postconditions: none
|
||||
; receives: global variables projectTitle, description1, and description2 from the stack
|
||||
; returns: prints the program intro
|
||||
introduction PROC
|
||||
push EBP
|
||||
mov EBP, ESP
|
||||
mDisplayString [EBP+20]
|
||||
mDisplayString [EBP+16]
|
||||
mDisplayString [EBP+12]
|
||||
mDisplayString [EBP+8]
|
||||
pop EBP
|
||||
ret 16
|
||||
introduction ENDP
|
||||
|
||||
; name: ReadVal
|
||||
; Prompts the user to input a string of digits, validates the input, converts it
|
||||
; to a signed int, then stores it. Uses local variable isNegative as custom
|
||||
; sign flag and convertedInt as temporary storage for the integer after conversion.
|
||||
; preconditions: retryPrompt, userPrompt, userInput are strings and global variables
|
||||
; userInputNum is a DWORD global variable
|
||||
; postconditions: none
|
||||
; receives: global variables retryPrompt, userPrompt, userInput, userInputNum passed on stack by reference
|
||||
; returns: signed integer stored in userInputNum
|
||||
ReadVal PROC
|
||||
;push EBP
|
||||
;mov EBP, ESP
|
||||
local isNegative:DWORD, convertedInt:SDWORD
|
||||
push EAX ; preserve registers
|
||||
push EBX
|
||||
push ECX
|
||||
push EDX
|
||||
push ESI
|
||||
_tryAgain:
|
||||
; prepend line number to prompt
|
||||
mov EDX, [EBP+36]
|
||||
mov EBX, [EBP+32]
|
||||
mov EAX, [EBP+28]
|
||||
push EDX
|
||||
push EBX
|
||||
push EAX
|
||||
call WriteVal
|
||||
; get input from user
|
||||
mGetString [EBP+20], [EBP+16], [EBP+12]
|
||||
mov ESI, [EBP+16] ; prepare isNegative, ESI and ECX for _isNumeric loop
|
||||
mov ECX, [EBP+12]
|
||||
mov ECX, [ECX]
|
||||
mov isNegative, 0
|
||||
cld
|
||||
_isNumeric:
|
||||
; begin loop to check sign and validate input
|
||||
lodsb
|
||||
cmp AL, 43
|
||||
je _positive ; check sign
|
||||
cmp AL, 45
|
||||
je _negative
|
||||
cmp AL, 48 ; check input is numeric
|
||||
jl _invalidNum
|
||||
cmp AL, 57
|
||||
jg _invalidNum
|
||||
jmp _validNum
|
||||
_positive:
|
||||
mov isNegative, 0 ; make sure isNegative is clear
|
||||
jmp _validNum
|
||||
_negative:
|
||||
mov isNegative, 1 ; set isNegative
|
||||
_validNum:
|
||||
loop _isNumeric
|
||||
jmp _continue ; continue to conversion after confirming input is numeric
|
||||
_invalidNum:
|
||||
mDisplayString [EBP+24] ; display error if input is invalid and jump to re-prompt
|
||||
jmp _tryAgain
|
||||
|
||||
_continue:
|
||||
; prepare registers, local, and counter (ECX) for conversion loop
|
||||
mov convertedInt, 0
|
||||
mov ESI, [EBP+16]
|
||||
mov EAX, 0
|
||||
mov EBX, 10
|
||||
mov EDX, 0
|
||||
mov ECX, [EBP+12]
|
||||
mov ECX, [ECX]
|
||||
cld
|
||||
_convert:
|
||||
; begin convert loop
|
||||
lodsb
|
||||
cmp AL, 43 ; compare first character to +/- and skip if present
|
||||
je _skipSign
|
||||
cmp AL, 45
|
||||
je _skipSign
|
||||
sub AL, 48 ; begin conversion to SDWORD
|
||||
push EAX
|
||||
mov EAX, convertedInt
|
||||
imul EBX
|
||||
mov convertedInt, EAX
|
||||
pop EAX
|
||||
jo _invalidNum ; check for overflow before proceeding, jump to error and re-prompt if OV flag = 1
|
||||
cmp isNegative, 1 ; negate if isNegative is set
|
||||
je _convertToNeg
|
||||
_add:
|
||||
add convertedInt, EAX ; add current value to convertedInt
|
||||
jo _invalidNum
|
||||
mov EAX, 0 ; reset EAX to 0
|
||||
_skipSign:
|
||||
loop _convert
|
||||
jmp _storeValue ; jump to saving value to global variable after convert loop complete
|
||||
_convertToNeg:
|
||||
neg EAX
|
||||
jmp _add
|
||||
|
||||
_storeValue: ; store value in variable userInputNum by reference
|
||||
mov EDX, [EBP+8]
|
||||
mov EAX, convertedInt
|
||||
mov [EDX], EAX
|
||||
pop ESI ; restore registers and return
|
||||
pop EDX
|
||||
pop ECX
|
||||
pop EBX
|
||||
pop EAX
|
||||
ret 32
|
||||
ReadVal ENDP
|
||||
|
||||
; name: WriteVal
|
||||
; Converts SDWORD input to ASCII and prints the data with it's corresponding label
|
||||
; preconditions: global variables have been declared for the data label and SDWORD.
|
||||
; Uses local variables remainder and quotient to hold results of division.
|
||||
; postconditions: none
|
||||
; receives: label and data global variables passed on stack
|
||||
; returns: prints the data and label to the output
|
||||
WriteVal PROC
|
||||
local remainder:DWORD, quotient:DWORD
|
||||
push EAX ; preserve registers
|
||||
push EBX
|
||||
push ECX
|
||||
push EDX
|
||||
push ESI
|
||||
push EDI
|
||||
; prepare local vars and registers for conversion and array filling
|
||||
mov remainder, 0
|
||||
mov quotient, 0
|
||||
mov EBX, 10
|
||||
mov ECX, 0
|
||||
mov ESI, [EBP+8]
|
||||
mov EAX, [ESI]
|
||||
mov EDI, [EBP+12]
|
||||
cld
|
||||
cmp EAX, 0
|
||||
jl _negative ; check for negative input
|
||||
_convert:
|
||||
; begin conversion from SDWORD to string
|
||||
cdq
|
||||
idiv EBX
|
||||
mov quotient, EAX
|
||||
mov remainder, EDX
|
||||
add remainder, 48
|
||||
mov EAX, remainder
|
||||
push EAX ; save value to add later
|
||||
inc ECX ; increment counter for adding to byte array later
|
||||
mov EAX, quotient
|
||||
cmp EAX, 0
|
||||
jne _convert ; keep looping until quotient = 0
|
||||
jmp _fillByteArray
|
||||
_negative:
|
||||
mov AL, 45 ; add '-' (ASCII 45) as first byte if negative
|
||||
stosb
|
||||
mov EAX, [ESI]
|
||||
neg EAX ; reverse sign before continuing to _convert
|
||||
jmp _convert
|
||||
|
||||
_fillByteArray:
|
||||
; begin filling array
|
||||
pop EAX ; pop values pushed during conversion
|
||||
stosb ; store popped values in array
|
||||
loop _fillByteArray
|
||||
mov EAX, 0 ; terminate string
|
||||
mov [EDI], EAX
|
||||
; invoke mDisplayString to print byte array
|
||||
mDisplayString [EBP+16]
|
||||
mDisplayString [EBP+12]
|
||||
; restore registers and return
|
||||
pop EDI
|
||||
pop ESI
|
||||
pop EDX
|
||||
pop ECX
|
||||
pop EBX
|
||||
pop EAX
|
||||
ret 12
|
||||
WriteVal ENDP
|
||||
|
||||
END main
|
Loading…
Reference in a new issue