Hi,
I'm transitioning to assembly, starting with processor 8086.
The attached code is Masm 5 compatible and is a step up from Hello World, which linked and ran okay.
An endless loop exists, giving credence to this note.
Any comments or suggestions to resolve it would be appreciated, thanks!

.model small
.stack 100h
.data

name_prompt         db 'Enter your first name: $'
user_input          db 11, 0 ; Buffer for user's name (up to 10 characters + 1 null terminator)
range_prompt        db 'Enter the range of numbers (e.g., 0 to 10): $'
range_input         db 5, 0 ; Buffer for user's range input (up to 4 characters + 1 null terminator)
lower_bound         dw 0 ; Lower bound of the range
upper_bound         dw 0 ; Upper bound of the range
operand1            dw 0 ; First operand for flash card
operand2            dw 0 ; Second operand for flash card
correct_answer      dw 0 ; Correct answer for flash card
user_answer         db 0 ; User's answer for flash card
correct_count       db 0 ; Counter for correct answers
flash_card_prompt   db 'Flash Card: $'
correct_msg         db 'Correct!', 0Dh, 0Ah, '$'
incorrect_msg       db 'Incorrect!', 0Dh, 0Ah, '$'
result_prompt       db 'Number of Correct Answers: $'
hello_msg           db 'Hello World',0Dh, 0Ah, '$'
debug_msg           db 'Debug: ', 0
debug_end_msg       db 'Debug: End of Execution', 0

.code

 print_number proc
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Display a number
        mov bx, 10 ; Set divisor to 10

        print_digit:
            xor dx, dx ; Clear any previous remainder
            div bx ; Divide AX by 10, result in AX, remainder in DX
            push dx ; Push the remainder onto the stack
            inc dl ; Convert the remainder to ASCII
            add dl, '0'
            mov ah, 02h ; DOS print character function
            int 21h ; Call DOS interrupt

            pop dx ; Pop the remainder from the stack
            cmp ax, 0 ; Check if quotient is zero
            jnz print_digit ; If not, continue the loop
            ret
    print_number endp

    generate_random_number proc
        ; Seed the random number generator
        mov ah, 2Ch ; DOS get system time function
        int 21h ; Call DOS interrupt
        xor ah, ah ; Clear AH
        mov cx, dx ; Use CX as the seed for the random number generator

        ; Generate a random number in the range [lower_bound, upper_bound]
        mov ax, cx ; Use AX to store the random number
        sub ax, [lower_bound]
        inc ax

        ; Move the upper_bound value into a register (BX)
        mov bx, [upper_bound]
        xor dx, dx
        div bx ; Divide AX by BX, result in AX, remainder in DX
        add ax, [lower_bound]
        ret
    generate_random_number endp

    clear_keyboard_buffer proc
        ; Clear the keyboard buffer
        mov ah, 0Ch ; DOS flush keyboard buffer function
        int 21h ; Call DOS interrupt
        ret
    clear_keyboard_buffer endp

main proc
    mov ax, @data
    mov ds, ax
    mov es, ax
    mov ss, ax

    ; Display prompt for user's name
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h         ; DOS print string function
    mov dx, offset name_prompt ; Offset of the message
    int 21h             ; Call DOS interrupt

    ; Read user's first name
    mov ah, 0Ah         ; DOS buffered input function
    lea dx, user_input  ; DX points to the buffer for input
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    int 21h             ; Call DOS interrupt

    ; Clear the keyboard buffer
    call clear_keyboard_buffer

    ; Display prompt for the range of numbers
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h         ; DOS print string function
    mov dx, offset range_prompt ; Offset of the message
    int 21h             ; Call DOS interrupt

    ; Read lower bound of the range
    mov ah, 0Ah         ; DOS buffered input function
    lea dx, range_input ; DX points to the buffer for input
    int 21h             ; Call DOS interrupt

    ; Convert ASCII input to integer (lower bound)
    mov al, [range_input + 2] ; ASCII character
    sub al, '0'               ; Convert ASCII to integer
    mov bl, 10                ; Multiplier for tens place
    mul bl                    ; Multiply AL by BL, result in AX
    mov [lower_bound], ax     ; Store the result

    ; Debug print for lower bound
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset range_prompt ; Prompt for debug print
    int 21h ; Call DOS interrupt

    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ax, [lower_bound] ; Load lower_bound into AX
    call print_number ; Display the lower bound
    mov ah, 09h ; DOS print string function
    mov dx, offset debug_msg ; Debug message
    int 21h ; Call DOS interrupt

    ; Read upper bound of the range
    mov ah, 0Ah         ; DOS buffered input function
    lea dx, range_input ; DX points to the buffer for input
    int 21h             ; Call DOS interrupt

    ; Convert ASCII input to integer (upper bound)
    mov al, [range_input + 3] ; ASCII character for tens place
    sub al, '0'
    mov bl, 10
    mul bl                    ; Multiply AL by BL, result in AX
    mov bh, 0                 ; Clear BH
    mov bl, [range_input + 2] ; ASCII character for units place
    sub bl, '0'               ; Convert ASCII to integer
    add ax, bx                ; Add to result (upper bound)
    mov [upper_bound], ax     ; Store the result

    ; Debug print for upper bound
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset range_prompt ; Prompt for debug print
    int 21h ; Call DOS interrupt

    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ax, [upper_bound] ; Load upper_bound into AX
    call print_number ; Display the upper bound
    mov ah, 09h ; DOS print string function
    mov dx, offset debug_msg ; Debug message
    int 21h ; Call DOS interrupt

    ; Preserve dx before calling generate_random_number
    push dx

    ; Generate random numbers in the specified range
    call generate_random_number   ; Call the generate_random_number procedure
    mov [operand1], ax

    call generate_random_number   ; Call the generate_random_number procedure
    mov [operand2], ax

    ; Restore dx after generate_random_number
    pop dx

    ; Generate and display flash cards
    mov cx, 10 ; Number of flash cards

    flash_cards_loop:
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Add debug print to check loop iteration
        mov ah, 09h ; DOS print string function
        mov dx, offset debug_msg
        int 21h ; Call DOS interrupt

        mov ax, cx
        call print_number ; Display loop iteration number

        ; Generate random numbers in the specified range
        call generate_random_number   ; Call the generate_random_number procedure
        mov [operand1], ax

        call generate_random_number   ; Call the generate_random_number procedure
        mov [operand2], ax

        ; Display flash card
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 09h ; DOS print string function
        mov dx, offset flash_card_prompt
        int 21h ; Call DOS interrupt

        ; Display the first operand
        mov ax, [operand1]
        call print_number ; Display the operand

        ; Display operator (+ or -)
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 02h ; DOS print character function
        mov dl, '+'
        int 21h ; Call DOS interrupt

        ; Display the second operand
        mov ax, [operand2]
        call print_number ; Display the operand

        ; Display equals sign
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 02h ; DOS print character function
        mov dl, '='
        int 21h ; Call DOS interrupt

        ; Display the second operand
        mov ax, [operand2]
        call print_number;Display operand A2102 SYMBOL NOT DEFINED

        ; Display equals sign
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 02h ; DOS print character function
        mov dl, '='
        int 21h ; Call DOS interrupt

        ; Read user's answer
        mov ah, 01h      ; DOS input character function
        int 21h          ; Call DOS interrupt
        sub al, '0'      ; Convert ASCII to integer
        mov bh, 0        ; Clear BH
        mov bX, [correct_answer];Load correct_answer into BL A2048 OP.MUST BE SAME SIZE

        ; Calculate the correct answer
        add bl, bh ; Clear high bits of BL
        cmp al, bl ; Compare AL with BL
        je  correct_answer_handler ; Jump if equal

        ; Display incorrect message
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 09h ; DOS print string function
        mov dx, offset incorrect_msg
        int 21h ; Call DOS interrupt
        jmp next_flash_card ; Jump to the next flash card

    correct_answer_handler:
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Add debug print to check correct answer handling
        mov ah, 09h ; DOS print string function
        mov dx, offset debug_msg
        int 21h ; Call DOS interrupt

        mov dx, [correct_answer]
        call print_number ; Display correct answer

        ; Display correct message
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        mov ah, 09h ; DOS print string function
        mov dx, offset correct_msg
        int 21h ; Call DOS interrupt

        ; Increment correct answer count
        mov al, [correct_count] ; Load the byte value into AL
        inc al                  ; Increment AL
        mov [correct_count], al ; Store the result back in memory
    next_flash_card:
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
        ; Add debug print to check loop termination
        mov ah, 09h ; DOS print string function
        mov dx, offset debug_msg
        int 21h ; Call DOS interrupt
        ; Move to the next flash card
        dec cx ; Decrement the loop counter
        jnz flash_cards_loop ; Jump if not zero
    ; Display the number of correct answers
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset result_prompt
    int 21h ; Call DOS interrupt
    ; Display the number of correct answers
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 02h ; DOS print character function
    mov dl, [correct_count]
    add dl, '0'
    int 21h ; Call DOS interrupt
    ; Exit program
    mov ah, 4Ch ; DOS exit function
    int 21h ; Call DOS interrupt
main endp
END main
.text
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov ah, 09h ; DOS print string function
    mov dx, offset hello_msg
    int 21h ; Call DOS interrupt
    mov ah, 09h ; DOS print string function
    ; Set DS to point to the data segment
    mov ax, @data
    mov ds, ax
    mov dx, offset debug_end_msg ; Debug message
    int 21h ; Call DOS interrupt
    mov ah, 4Ch ; DOS exit function
    int 21h ; Call DOS interrupt

Recommended Answers

All 5 Replies

With 330 lines of code supplied, it will be difficult to try and figure out where your code errors or loops infinitely. You need to break it down for us and point to the line where the loop occurs, the well know abbreviation applies here -

TLDR is an acronym that stands for "Too Long Didn't Read"

Let's say it did loop. Wouldn't I trace said code or use the debugger to see where it's looping?
And at over 300 lines of code, I won't be reading all that. You need to find where it's looping.

Please show us the looping output. You say it just loops, but you need to show us the issue so we don't have to guess and reverse engineer your entire code block.

Many on this site are very happy to assist, but do as much as you can to respect our time by giving us complete data on the problem, thank you.

The 70's are calling and they want their 8086 and assembler back...

Hi,
DOS assembler reference:
link

Wrapper used:

: make.bat [SRC] ; omit .asm
jwasmr.exe -ms %1.asm
wlink format dos file %1.obj
del %1.obj
%1

Code flow chart:

+-------------------------+
|           Start         |
+-------------------------+
             |
             V
    +------------------+
    | Print Name Prompt|
    +------------------+
             |
             V
    +------------------------+
    | Read User's First Name |
    +------------------------+
             |
             V
    +------------------------+
    | Print Greeting Message |
    +------------------------+
             |
             V
    +----------------------------+
    | Read Upper Bound of Range  |
    +----------------------------+
             |
             V
    +---------------------------+
    | Generate Random Numbers   |
    |   in the Specified Range  |
    +---------------------------+
             |
             V
    +------------------------+
    | Loop for Flash Cards   |
    +------------------------+
             |
             V
    +-----------------------+
    | Display Flash Card    |
    +-----------------------+
             |
             V
    +--------------------------+
    | Read User's Answer       |
    +--------------------------+
             |
             V
    +--------------------------+
    | Check Correctness        |
    |   and Display Messages   |
    +--------------------------+
             |
             V
    +-----------------------+
    | Update Correct Count  |
    +-----------------------+
             |
             V
    +------------------------+
    | Check Loop Termination |
    +------------------------+
             |
             V
    +----------------------+
    | Display Correct Count|
    +----------------------+
             |
             V
    +------------------------+
    | End of Program         |
    +------------------------+

Updated code with added print debug statements to isolate endless loop:

.stack 100h

.data
    name_prompt         db 'Enter your name: $'
    greeting_msg        db 'Hello, ', 0
    range_prompt        db 'Please answer the following random pop quiz addition or subtraction problems. What is the highest number you want to work with, 10-100? $'
    flash_card_prompt   db 'Flash Card: $'
    correct_msg         db 'Correct!', 0Dh, 0Ah, '$'
    incorrect_msg       db 'Incorrect!', 0Dh, 0Ah, '$'
    result_prompt       db 'Number of Correct Answers: $'
    user_input          db 11 dup (?)
    range_input         db 5 dup (?)
    operand1            dw ?
    operand2            dw ?
    correct_answer      dw ?
    user_answer         db 1 dup (?)
    correct_count       db ?

    lower_bound         dw 0 ; Define lower_bound as a word (2 bytes)
    upper_bound         dw 0 ; Define upper_bound as a word (2 bytes)
    debug_msg           db 'Debug: ', 0
    debug_end_msg       db 'Debug: End of Execution', 0
    division_error_msg  db 'Error: Division by zero', 0Dh, 0Ah, '$'
    debug_msg_before_input db 'Debug: Before reading user input', 0Dh, 0Ah, '$'
    debug_msg_after_input db 'Debug: After reading user input', 0Dh, 0Ah, '$'

.code

generate_random_number proc
    ; Seed the random number generator
    mov ah, 2 ; DOS get system time function
    int 21h ; Call DOS interrupt
    xor ah, ah ; Clear AH
    mov cx, dx ; Use CX as the seed for the random number generator

    ; Check if upper_bound is zero
    mov bx, [upper_bound]
    test bx, bx
    jz  division_by_zero_error ; Jump to error if upper_bound is zero

    ; Generate a random number in the range [lower_bound, upper_bound]
    mov ax, cx ; Use AX to store the random number
    xor dx, dx ; Clear DX for 16-bit division
    sub bx, [lower_bound]
    add bx, 1 ; Adjust range to be inclusive
    div bx ; Divide AX by BX, result in AX, remainder in DX
    add ax, [lower_bound] ; Result in the range [lower_bound, upper_bound]
    ret
generate_random_number endp

division_by_zero_error proc
    ; Display an error message
    mov ah, 09h ; DOS print string function
    lea dx, division_error_msg ; Offset of the error message
    int 21h ; Call DOS interrupt

    ; Exit program
    mov ah, 4Ch ; DOS exit program function
    int 21h ; Call DOS interrupt
    ret
division_by_zero_error endp

print_number proc
    ; Display a number
    mov bx, 10 ; Set divisor to 10

    print_digit:
        xor dx, dx ; Clear any previous remainder
        div bx ; Divide AX by 10, result in AX, remainder in DX
        push dx ; Push the remainder onto the stack
        inc dl ; Convert the remainder to ASCII
        add dl, '0'
        mov ah, 2 ; DOS print character function
        int 21h ; Call DOS interrupt

        pop dx ; Pop the remainder from the stack
        cmp ax, 0 ; Check if quotient is zero
        jnz print_digit ; If not, continue the loop
        ret
print_number endp

main proc

; After setting up the data segment
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg ; Offset of the debug message
    int 21h ; Call DOS interrupt

; After setting up the data segment
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg ; Offset of the debug message
    int 21h ; Call DOS interrupt

; Delay loop
    mov cx, 5000 ; Adjust the delay count as needed
    delay_loop_1:
        loop delay_loop_1

; Clear the screen
    mov ah, 06h ; DOS function to scroll the screen
    mov al, 0   ; Scroll entire window
    mov bh, 07h ; Text attribute (white on black)
    mov cx, 0   ; Upper-left corner (row 0, column 0)
    mov dx, 184fh ; Lower-right corner (row 24, column 79)
    int 10h ; Call BIOS interrupt to scroll the screen

; Dislay prompt for user's name
    mov ah, 09h ; DOS print string function
    lea dx, name_prompt ; Offset of the message
    int 21h ; Call DOS interrupt

; Debug: Print a message indicating the completion of the name prompt
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg ; Offset of the debug message
    int 21h ; Call DOS interrupt



; Before reading user's first name
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg_before_input ; Offset of the debug message
    int 21h ; Call DOS interrupt

; Before reading user's first name
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg_before_input ; Offset of the debug message
    int 21h ; Call DOS interrupt

; Delay loop
    mov cx, 5000 ; Adjust the delay count as needed
    delay_loop_2:
        loop delay_loop_2

; Read user's first name
    mov ah, 0Ah ; DOS buffered input function
    lea dx, user_input ; DX points to the buffer for input
    int 21h ; Call DOS interrupt

; Debug: Print the contents of user_input
    mov ah, 09h ; DOS print string function
    lea dx, user_input ; Offset of the buffer
    int 21h ; Call DOS interrupt

; After reading user's first name
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg_after_input ; Offset of the debug message
    int 21h ; Call DOS interrupt
;
; After reading user's first name
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg_after_input ; Offset of the debug message
    int 21h ; Call DOS interrupt

; Delay loop
    mov cx, 5000 ; Adjust the delay count as needed
    delay_loop_3:
        loop delay_loop_3    
;
; Remove the newline character from the buffer
    mov si, offset user_input + 2 ; SI points to the third byte (LF)
    mov cx, 10 ; Set maximum loop count
    remove_newline:
    cmp byte ptr [si], 13 ; Check for carriage return (CR)
    je  newline_found ; Jump if found
    inc si ; Move to the next character
    loop remove_newline ; Continue loop
newline_found:

    ; Display greeting message
    mov ah, 09h ; DOS print string function
    lea dx, greeting_msg ; Offset of the message
    int 21h ; Call DOS interrupt

    ; Read upper bound of the range
    mov ah, 0Ah ; DOS buffered input function
    lea dx, range_input ; DX points to the buffer for input
    int 21h ; Call DOS interrupt

    ; Convert ASCII input to integer (upper bound)
    mov al, [range_input + 3] ; ASCII character for tens place
    sub al, '0'
    mov bl, 10
    mul bl ; Multiply AL by BL, result in AX
    mov bh, 0 ; Clear BH
    mov bl, [range_input + 2] ; ASCII character for units place
    sub bl, '0' ; Convert ASCII to integer
    add ax, bx ; Add to result (upper bound)

    ; Check if upper bound is zero
    test ax, ax
    jz  division_by_zero_error ; Jump to error if upper_bound is zero
    mov [upper_bound], ax ; Store the result

    ; Generate and display flash cards
    mov cx, 10 ; Number of flash cards

flash_cards_loop:
    call generate_random_number ; Call the generate_random_number procedure
    mov [operand1], ax

    call generate_random_number ; Call the generate_random_number procedure
    mov [operand2], ax

    ; Display flash card prompt
    mov ah, 09h ; DOS print string function
    lea dx, flash_card_prompt ; Offset of the message
    int 21h ; Call DOS interrupt

    ; Display operands and operator
    mov ax, [operand1]
    call print_number ; Display the operand

    ; Display operator (+ or -)
    mov ah, 02h ; DOS print character function
    mov dl, '+'
    int 21h ; Call DOS interrupt

    ; Display the second operand
    mov ax, [operand2]
    call print_number ; Display the operand

    ; Display equals sign
    mov ah, 02h ; DOS print character function
    mov dl, '='
    int 21h ; Call DOS interrupt

    ; Read user's answer
    mov ah, 01h ; DOS input character function
    int 21h ; Call DOS interrupt
    sub al, '0' ; Convert ASCII to integer
    mov bx, [correct_answer] ; Load correct_answer into BX
    ; A2048 OP.MUST BE SAME SIZE

    ; Calculate the correct answer
    add bx, 0 ; Clear high bits of BX
    cmp ax, bx ; Compare AX with BX
    je  correct_answer_handler ; Jump if equal

    ; Display incorrect message
    mov ah, 09h ; DOS print string function
    lea dx, incorrect_msg ; Offset of the message
    int 21h ; Call DOS interrupt
    jmp next_flash_card ; Jump to the next flash card

correct_answer_handler:
    ; Display correct message
    mov ah, 09h ; DOS print string function
    lea dx, correct_msg ; Offset of the message
    int 21h ; Call DOS interrupt

    ; Increment correct answer count
    mov al, [correct_count] ; Load the byte value into AL
    inc al ; Increment AL
    mov [correct_count], al ; Store the result back in memory

next_flash_card:
    ; Add debug print to check loop termination
    mov ah, 09h ; DOS print string function
    lea dx, debug_msg ; Offset of the message
    int 21h ; Call DOS interrupt

    ; Move to the next flash card
    dec cx ; Decrement the loop counter
    jnz flash_cards_loop ; Jump if not zero

    ; Display the number of correct answers
    mov ah, 09h ; DOS print string function
    lea dx, result_prompt ; Offset of the message
    int 21h ; Call DOS interrupt

    ; Display the number of correct answers
    mov ah, 02h ; DOS print character function
    mov dl, [correct_count]
    add dl, '0'
    int 21h ; Call DOS interrupt

    ; Exit program
    mov ah, 4Ch ; DOS exit program function
    int 21h ; Call DOS interrupt

main endp
end main

Please confirm endless loop exists on another environment and report your findings to thread, thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.