I need to write a code in 8086 emulator where a user gives an input from 0 to 9. If the value is below 3, 'Good morning!' is printed. If the value is greater or equal to 4 and less than 6 (just 4 and 5, basically), 'Good afternoon!' is printed. If the value is greater or equal to 8, 'Good night!' is printed. For the values 3, 6 and 7, the system does nothing. However, in my case, I am getting an output for these three values as well. What are the issues with my code?
.MODEL SMALL
.STACK 100H
.DATA
STRING1 DB "Enter number:$"
STRING2 DB "Good morning!$"
STRING3 DB "Good afternoon!$"
STRING4 DB "Good night!$"
.CODE
MAIN PROC
MOV AX , @DATA
MOV DS , AX
LEA DX , STRING1
MOV AH , 9
INT 21h
MOV AH , 1
INT 21h
SUB AL , 30h
CMP AL , 3
JL good_morning
CMP AL , 6
JL next_check
CMP AL , 8
JGE good_night
good_morning:
LEA DX , STRING2
MOV AH , 9
INT 21h
JMP exit_label
next_check:
CMP AL , 4
JGE good_afternoon
good_afternoon:
LEA DX , STRING3
MOV AH , 9
INT 21h
JMP exit_label
good_night:
LEA DX , STRING4
MOV AH , 9
INT 21h
JMP exit_label
exit_label:
MOV AX , 4C00H
INT 21h
MAIN ENDP
END MAIN
CodePudding user response:
The first issue with your code is that there are no comments! Assembly is hard enough to read with comments; don't make it harder on yourself (or whoever has to go back and maintain this code later). Discipline yourself to write the comments when you write the code. No one ever wants to go back later and just write the comments. As a bonus, writing the comments will (hopefully) force you to think through the logic as you write the code.
[I]n my case, I am getting an output for these three values [3, 6 and 7] as well.
Start by tracing the logic of the code, stepping through it and "executing" it in your head. Since most of the input-processing is working OK, we can assume that the code that reads the input is correct, so we'll start just after that:
CMP AL , 3
JL good_morning ; if AL < 3, jump to "good_morning"; otherwise, fall through
CMP AL , 6
JL next_check ; if AL < 6, jump to "next_check"; otherwise, fall through
CMP AL , 8
JGE good_night ; if AL > 8, jump to "good_night"; otherwise, fall through
Ask yourself: What happens if the input value is 3 (since that's the first value for which you're seeing an incorrect output)? Well, it goes to next_check
. So, go look at that code:
next_check:
CMP AL , 4
JGE good_afternoon ; if AL >= 4, jump to "good_afternoon"; otherwise, fall through
good_afternoon:
LEA DX , STRING3
MOV AH , 9
INT 21h
JMP exit_label
Oops! You fall through to good_afternoon
no matter what the input value is! If AL
is greater than or equal to 4, you jump to it; otherwise, you fall through. But what you fall through to is exactly the same as what you jump to, so you're going to see the output for "good afternoon" for an input value of 3. This is wrong.
You could fix it by adding an unconditional jump after the conditional one:
next_check:
CMP AL , 4
JGE good_afternoon ; if AL >= 4, jump to "good_afternoon"; otherwise, fall through
JMP exit_label
good_afternoon:
LEA DX , STRING3
MOV AH , 9
INT 21h
JMP exit_label
But this is less efficient (and less readable, in my opinion) than reversing the logic of the comparison and thus the direction of the branch:
next_check:
CMP AL , 4
JL exit_label ; if AL < 4, jump to "exit_label"; otherwise, fall through
good_afternoon:
LEA DX , STRING3
MOV AH , 9
INT 21h
JMP exit_label
Based on this technique, you should be able to trace through your code for the other inputs that produce invalid outputs and correct the problem in a similar way.