'Total Average Grade Calculator emu8086

I'm new to this assembly language emo8086 and I just wanna ask if there's something wrong about this code because I want to display the average grade, but the output is only the word "Average" and it doesn't show any numbers. What should I do to solve or debugg my code?

.MODEL SMALL
.DATA
        VAL1         DB      ?
        DISPLAY1     DB      0AH,0DH,'NUMBER OF SUBJECTS :','$'
        DISPLAY2         DB      0AH,0DH,'ENTER GRADE:','$'
        DISPLAY3         DB      0AH,0DH,'AVEARGE:','$'
    BUFFER       DB      3,4 DUP(?)
.CODE
MAIN    PROC

.STARTUP

        LEA DX,DISPLAY1 
        MOV AH,09H  
        INT 21H

        MOV AH,01H  
        INT 21H
        SUB AL,30H

        MOV CL,AL
        MOV BL,AL   
        MOV AL,00  
        MOV VAL1,AL 

LBL1:
        LEA DX,DISPLAY2 
        MOV AH,09H
        INT 21H

        MOV AH,0AH  
        LEA DX,BUFFER
        INT 21H
        SUB AL,30H

        ADD AL,VAL1 
        MOV VAL1,AL 
        LOOP LBL1   

LBL2:
        LEA DX,DISPLAY3 
        MOV AH,09H
        INT 21H

        MOV AX,00   
        MOV AL,VAL1 
        DIV BL      
        ADD AX,3030H    
        MOV DX,AX   
        MOV AH,02H  
        INT 21H
        
        MOV AH,4CH
        INT 21H

.EXIT

MAIN    ENDP
        END     MAIN


Solution 1:[1]

MOV AH,0AH  
LEA DX,BUFFER
INT 21H
SUB AL,30H

The first error is that you are using the DOS.BufferedInput function 0Ah to input the grade, but you are not retrieving the number from the buffer. You seem to expect to find it in the AL register, as would be the case with the DOS.GetCharacter function 01h.

LOOP LBL1

The second error is that you are using the loop instruction that depends on the whole of the CX register, but your code only ever sets up the CL part of CX. You should never rely on any register content when your program starts, unless such settings were well documented of course.

ADD AX,3030H    
MOV DX,AX   
MOV AH,02H  
INT 21H

The third error is that it looks like you seem to expect to display an average grade composed of two digits and do it with a single invokation of the DOS.PrintCharacter function 02h.


For this simple exercise we can assume that both the number of subjects and their grade are single-digit numbers. Naturally, the average grade will be a single-digit number too.

Using the DOS.Getcharacter function 01h is fine and you are using the correct conversion from character into the value that the digit represents. However, when dealing with user input, you can never truly trust the user to supply a valid input to your program. It's up to you to validate the input. For a single-digit number it's easy enough:

GetDigit0_9:
  mov  ah, 01h    ; DOS.GetCharacter
  int  21h        ; -> AL
  sub  al, '0'
  cmp  al, 9
  ja   GetDigit0_9

Pay attention to the unintentional 'infinite loop' and 'division by zero' problems.
You cannot allow the grade loop to run or the div bl instruction to execute if the user inputted 0 for the number of subjects. Use the jcxz (JumpOnCXZero) instruction to either

  • redo asking the user for a value in [1,9]

    LBL0:
      call GetDigit0_9   ; -> AX=[0,9]
      mov  cx, ax
      jcxz LBL0          ; Guard against 0 number of subjects
    
  • or skip right to the end of the program

      jcxz LBL3          ; Guard against 0 number of subjects
    LBL1:
      ...
      loop LBL1
    LBL2:
      ...
    LBL3:
      mov  ax, 4C00h     ; DOS.Terminate
      int  21h
    

Revised code:

  ...

  LEA  DX, DISPLAY1 
  MOV  AH, 09h       ; DOS.PrintString
  INT  21h
  call GetDigit0_9   ; -> AX=[0,9]
  mov  cx, ax
  mov  bl, al        ; (*)
  MOV  VAL1, 0 

  jcxz LBL3          ; Guard against 0 number of subjects
LBL1:
  LEA  DX, DISPLAY2 
  MOV  AH, 09h       ; DOS.PrintString
  INT  21h
  call GetDigit0_9   ; -> AX=[0,9]
  add  VAL1, al 
  loop LBL1

LBL2:
  LEA  DX, DISPLAY3 
  MOV  AH, 09h       ; DOS.PrintString
  INT  21h
  mov  ah, 0   
  mov  al, VAL1 
  div  bl            ; (*)
  add  al, '0'    
  mov  dl, al
  mov  ah, 02h       ; DOS.PrintCharacter
  int  21h

LBL3:
  mov  ax, 4C00h     ; DOS.Terminate
  int  21h

; IN () OUT (ax)
GetDigit0_9:
  mov  ah, 01h       ; DOS.GetCharacter
  int  21h           ; -> AL
  sub  al, '0'
  cmp  al, 9
  ja   GetDigit0_9
  mov  ah, 0
  ret

  ...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1