Hello, I am working on a MASM program for fun. But I am running into difficulties. Can you fix errors in my current code? I want to compare it to the edits I made myself

Write and test a MASM program to perform the following tasks (check the Requirements section for specifics on program modularization):

Implement and test two macros for string processing. These macros should use Irvine’s ReadString to get input from the user, and WriteString procedures to display output.
mGetString: Display a prompt (input parameter, by reference), then get the user’s keyboard input into a memory location (output parameter, by reference). You may also need to provide a count (input parameter, by value) for the length of input string you can accommodate and a provide a number of bytes read (output parameter, by reference) by the macro.
mDisplayString: Print the string which is stored in a specified memory location (input parameter, by reference).
Implement and test two procedures for signed integers which use string primitive instructions
ReadVal:
Invoke the mGetString macro (see parameter requirements above) to get user input in the form of a string of digits.
Convert (using string primitives) the string of ascii digits to its numeric value representation (SDWORD), validating the user’s input is a valid number (no letters, symbols, etc).
Store this one value in a memory variable (output parameter, by reference).
WriteVal:
Convert a numeric SDWORD value (input parameter, by value) to a string of ASCII digits.
Invoke the mDisplayString macro to print the ASCII representation of the SDWORD value to the output.
Write a test program (in main) which uses the ReadVal and WriteVal procedures above to:
Get 10 valid integers from the user. Your ReadVal will be called within the loop in main. Do not put your counted loop within ReadVal.
Stores these numeric values in an array.
Display the integers, their sum, and their truncated average.
Your ReadVal will be called within the loop in main. Do not put your counted loop within ReadVal.

Program Requirements

User’s numeric input must be validated the hard way:
Read the user’s input as a string and convert the string to numeric form.
If the user enters non-digits other than something which will indicate sign (e.g. ‘+’ or ‘-‘), or the number is too large for 32-bit registers, an error message should be displayed and the number should be discarded.
If the user enters nothing (empty input), display an error and re-prompt.
ReadInt, ReadDec, WriteInt, and WriteDec are not allowed in this program.
mDisplayString must be used to display all strings.
Conversion routines must appropriately use the LODSB and/or STOSB operators for dealing with strings.
All procedure parameters must be passed on the runtime stack using the STDCall calling convention (see Module 7, Exploration 1 - Passing Parameters on the Stack). Strings also must be passed by reference.
Prompts, identifying strings, and other memory locations must be passed by address to the macros.
Used registers must be saved and restored by the called procedures and macros.
The stack frame must be cleaned up by the called procedure.
Procedures (except main) must not reference data segment variables by name. There is a significant penalty attached to violations of this rule. Some global constants (properly defined using EQU, =, or TEXTEQU and not redefined) are allowed. These must fit the proper role of a constant in a program (master values used throughout a program which, similar to HI and LO in Project 5).
The program must use Register Indirect addressing or string primitives (e.g. STOSD) for integer (SDWORD) array elements, and Base+Offset addressing for accessing parameters on the runtime stack.
Procedures may use local variables when appropriate.
The program must be fully documented and laid out according to the CS271 Style Guide

Download CS271 Style Guide. This includes a complete header block for identification, description, etc., a comment outline to explain each section of code, and proper procedure headers/documentation.

Notes

For this assignment you are allowed to assume that the total sum of the valid numbers will fit inside a 32 bit register.
We will be testing this program with positive and negative values.
When displaying the average, only display the integer part (that is, drop/truncate any fractional part).
Check the Course Syllabus

Download Course Syllabus for late submission guidelines.
Find the assembly language instruction syntax and help in the CS271 Instructions Guide
Download CS271 Instructions Guide.
To create, assemble, run, and modify your program, follow the instructions on the course Syllabus Page’s “Tools” tab.

Here is my current code:
INCLUDE Irvine32.inc

; Macro Definitions
mGetString MACRO stringToWrite:REQ, userEntry:REQ, maxBufferSize:REQ, bytesRead:REQ
PUSHAD
MOV EDI, OFFSET userEntry
MOV ECX, maxBufferSize
XOR AL, AL
REP STOSB
MOV EDX, OFFSET stringToWrite
CALL WriteString
MOV EDX, OFFSET userEntry
MOV ECX, maxBufferSize
CALL ReadString
MOV bytesRead, EAX
CMP EAX, 0
JE emptyInputError
POPAD
JMP done

emptyInputError:
mDisplayString errorMsgEmptyInput
JMP done

done:
ENDM

mDisplayString MACRO stringToPrint:REQ
PUSHAD
MOV EDX, OFFSET stringToPrint
CALL WriteString
POPAD
ENDM

; Constant Definitions
MAX_BUFFER_SIZE EQU 32
ARRAY_SIZE EQU 10

.data

programHeader BYTE “PROGRAMMING ASSIGNMENT 6: Designing low-level I/O procedures”, 0
programName BYTE “Written by: John Pino”, 0
instructOne BYTE “Please provide 10 signed decimals.”, 0
instructTwo BYTE “Each number must be small enough to fit in a 32-bit register.”, 0
userPrompt BYTE "Please enter a signed number: ", 0
arrayText BYTE "Values of user array: ", 0
comma BYTE ", ", 0
sum BYTE "Sum: ",0
average BYTE "Truncated average: ",0
userEntry BYTE MAX_BUFFER_SIZE DUP(0)
userArray SDWORD ARRAY_SIZE DUP(0)
bytesRead DWORD ?

arraySum SDWORD ?
outputBuffer BYTE 16 DUP(0)
convertedString BYTE 16 DUP(0)

; Error Messages
errorMsgEmptyInput BYTE “Error: Empty input. Please enter a valid value.”, 0
errorMsgInvalidInput BYTE “Error: Invalid input. Please enter a valid number.”, 0

.code
main PROC

; Display program header
mDisplayString programHeader
CALL CRLF

; Display program name
mDisplayString programName
CALL CRLF

; Display instructions
mDisplayString instructOne
mDisplayString instructTwo
CALL CRLF

MOV EDX, 1

inputLoop:
; Prompt the user for a number and store it in the array
mGetString userPrompt, userEntry, MAX_BUFFER_SIZE, bytesRead
MOV ESI, OFFSET userArray
CALL ReadVal

; Calculate the indexed address using EBX as a temporary register
MOV EBX, EDX
SUB EBX, 1
SHL EBX, 2 ; Multiply by 4 to get the offset
ADD EDI, EBX ; Add the offset to the base address

; Load the value at the indexed address into EAX
MOV EAX, [EDI]

; Store the new value in the indexed address
MOV [EDI], EAX

INC EDX
CMP EDX, ARRAY_SIZE
JLE inputLoop

; Print the values of userArray
mDisplayString arrayText
MOV EDX, 1
XOR ESI, ESI
MOV ESI, OFFSET userArray

printLoop:
MOV EAX, [ESI + EDX * 4]
CALL WriteVal
INC EDX
CMP EDX, ARRAY_SIZE
JLE printLoop

; Calculate the sum and average
JMP calculateSumAndAverage

calculateSumAndAverage:
; Calculate the sum
MOV EAX, 0
MOV ECX, ARRAY_SIZE
MOV EDX, 0
MOV ESI, OFFSET userArray

sumLoop:
ADD EAX, [ESI + EDX * 4]
INC EDX
LOOP sumLoop
MOV arraySum, EAX

; Print the sum
mDisplayString CRLF
mDisplayString sum
MOV EAX, arraySum
CALL WriteVal

; Calculate the truncated average
MOV EBX, ARRAY_SIZE
CDQ
IDIV EBX
MOV ECX, EAX

; Print the truncated average
mDisplayString CRLF
mDisplayString average
MOV EAX, ECX
CALL WriteVal

; Exit the program
MOV EAX, 0
RET

main ENDP

ReadVal PROC
PUSHAD
MOV EBX, 10 ; Base 10
MOV EDX, OFFSET userEntry ; Load the address of the user entry buffer
XOR ECX, ECX ; Clear ECX
MOV CL, BYTE PTR [EDX] ; Load the length of the string in CL
MOV EDI, EDX ; Copy the address of the user entry buffer to EDI
INC EDI ; Move to the next character in the buffer
XOR EAX, EAX ; Clear EAX

checkFirstChar:
MOV AL, BYTE PTR [EDI] ; Load the first character of the string in AL
CMP AL, ‘-’ ; Check if the number is negative
JE negativeNumber ; If the first character is “-”, jump to negativeNumber
CMP AL, ‘+’ ; Check if the number is positive (optional)
JE positiveNumber ; If the first character is “+”, jump to positiveNumber
CMP AL, ‘0’ ; Check if the first character is “0”
JL readNumber ; If the first character is less than “0”, jump to readNumber
CMP AL, ‘9’ ; Check if the first character is greater than “9”
JG readNumber ; If the first character is greater than “9”, jump to readNumber
JMP singleDigitNumber ; If the first character is a single digit, jump to singleDigitNumber

singleDigitNumber:
SUB AL, ‘0’ ; Convert the character to its numeric value
MOVZX EAX, AL ; Copy the single-digit value to EAX
INC EDI ; Move to the next character in the buffer
JMP endRead

negativeNumber:
INC EDI ; Move to the next character in the buffer
JMP readNumber

positiveNumber:
INC EDI ; Move to the next character in the buffer

readNumber:
XOR EAX, EAX ; Clear EAX
XOR EDX, EDX ; Clear EDX

readLoop:
MOV AL, BYTE PTR [EDI] ; Load the next character of the string in AL
CMP AL, ‘0’ ; Check if the character is “0”
JL checkNumber ; If the character is less than “0”, jump to checkNumber
CMP AL, ‘9’ ; Check if the character is “9”
JG checkNumber ; If the character is greater than “9”, jump to checkNumber
IMUL EAX, EBX ; Multiply EAX by 10
SUB AL, ‘0’ ; Convert the character to its numeric value
ADD EAX, EDX ; Add EDX to EAX
CMP EAX, 0 ; Check if the number is too large for a 32-bit register
JL invalidNumber ; If the number is less than 0, jump to invalidNumber
INC EDI ; Move to the next character in the buffer
JMP readLoop

checkNumber:
CMP AL, 0 ; Check if the end of the string has been reached
JE endRead ; If the end of the string is reached, jump to endRead
JMP invalidNumber ; Otherwise, the number is invalid

invalidNumber:
; Display error message for invalid input
mDisplayString errorMsgInvalidInput
MOV EAX, 0 ; Set the return value to 0
JMP endRead

endRead:
POPAD
RET
ReadVal ENDP



WriteVal PROC
PUSHAD
MOV EDX, OFFSET userArray
MOV ECX, ARRAY_SIZE

printLoop:
MOV EAX, [EDX + ECX * 4]
CALL WriteInt
DEC ECX
CMP ECX, 0
JE printEnd

MOV EDX, OFFSET comma
CALL WriteString
JMP printLoop

printEnd:
CALL CRLF
POPAD
RET
WriteVal ENDP

END main

Can you help me fix any errors?