Hello, here is my project instructions: Introduction

This program, the portfolio project for the class, is the final step up in difficulty.  Remember, grace days cannot be used on this assignment. Once again the Rubric (see below) now has a number of point deductions for not meeting requirements. It it not uncommon for a student to generate a program that meets the Program Description but violates several Program Requirements, causing a significant loss in points. Please carefully review the Rubric to avoid this circumstance.

The purpose of this assignment is to reinforce concepts related to string primitive instructions and macros (CLO 3, 4, 5).

    Designing, implementing, and calling low-level I/O procedures
    Implementing and using macros

What you must do
Program Description

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?