Reputation: 83
We are working on 8086 microprocessor and NASM assembler. My code assembles fine but when I execute I just get a bunch of random symbols. Our assignment instructions are:
Here is my code which is horribly broken:
org 1000h
; program converts fraction to decimal, where M < N, M & N are both positive, and upto 6 decimal places are printed
section .data
MSG1 dw "Enter the numerator: ", '$'
MSG2 dw "Enter the denominator: ", '$'
EMSG dw "Please enter a number between 0 and 9 ", '$'
section .bss
M RESW 1
N RESW 1
section .text
main:
; print user prompt
mov dx, MSG1 ; get message
mov ah, 09h ; display string function
int 21h ; display it
mov dl, 0Ah ; line feed moved into character display register
mov ah, 02h ; charcter display function
int 21h ; display line feed
mov dl, 0Dh ; carriage return moved into character display register
int 21h ; display carriage return
xor cx, cx ; clear cx
jmp DEC_IN
prompt:
; print second prompt
mov dx, MSG2 ; get message
mov ah, 09h ; display string function
int 21h ; display it
mov dl, 0Ah ; line feed moved into character display register
mov ah, 02h ; charcter display function
int 21h ; display line feed
mov dl, 0Dh ; carriage return moved into character display register
int 21h ; display carriage return
inc cx ; will make next iteration store denominator in N
jmp DEC_IN
DEC_IN:
; input character from keyboard, converts ASCII to appropriate binary, stores into respective memory location
mov ah, 01h ; keyboard input function
int 21h ; character input, copies character into al
mov bx, ax ; moves ax into bx to avoid ax being messed with
cmp bx, 30h ; compares input to ASCII code for 0
jl error ; if input is less than 0 jump to error
cmp bx, 39h ; compares input to ASCII code for 9
jg error ; if input is greater than 9 jump to error
sub bx, 30h ; subtracts 30h to make the ASCII code into the base 10 number
cmp cx, 1 ; check if input is denominator
je prepare
mov word [M], bx ; stores user input into memory location M
jmp prompt
prepare:
; store denominator in N
mov word [N], bx ; stores input into memory location N
mov dl, 2Eh ; moves '.' to display character register
mov ah, 02h ; display character function
int 21h ; displays it
mov cx, 10 ; set loop to run 10 times
mov bx, word [M]
jmp print
print:
; loop to print
mov ax, 10 ; setup for multiplication
mul bx ; multiply numerator by 10
mov bx, word [N]
div bx
push dx
mov dx, ax
mov ah, 09h ; display string function
int 21h ; display it
pop dx
mov bx, dx
loop print
jmp exit
error:
; displays error message then jumps back to DEC_IN
mov dx, EMSG ; moves error message into display string register
mov ah, 09h ; display string function
int 21h ; displays it
mov dl, 0Ah ; line feed moved into character display register
mov ah, 02h ; charcter display function
int 21h ; display line feed
mov dl, 0Dh ; carriage return moved into character display register
int 21h ; display carriage return
jmp DEC_IN
exit:
;exit to DOS
mov ah, 04Ch ; DOS function: Exit program
mov al, 0 ; Return exit code value
int 21h ; Call DOS. Terminate program
Upvotes: 1
Views: 1388
Reputation: 3119
When your code is horribly broken, it's probably a sign that you need to back up and take smaller steps.
org 1000h
is almost certainly wrong. As rjbh says, you don't want an org
for an .exe file (Nasm won't accept it!). I ASSume you're doing a .com file however, which wants org 100h
. This doesn't "cause" us to be loaded at 100h, merely informs Nasm that dos will load us at 100h. If that isn't just a "posto", fixing it should get your prompts on screen, at least.
Your prompts should be db
not dw
. (I ASSume we're not doing UNICODE). You may wish to include the carriage return / linefeed pair in your prompt, rather than printing them in your code. It would make your code slightly smaller and simpler... and thus easier to find the errors. :) Either way works.
Your variables M
and N
are correct. Horrible names - not very "meaningful" - but specified in the assignment. I'd have probably named them "numerator" and "denominator" - more typing, but worth it to keep track of what you're doing (IMO). There'a a little "gotcha" with denominator - we probably don't want to let the user enter 0!
Your code starts off fine, up to jmp DEC_IN
. I think that's supposed to be a subroutine that is called with the call
instruction and returned from with the ret
instruction. It is "usual" to return a value from a subroutine in ax
, but the assignment says bx
. No problem...
; your prompt
call DEC_IN
mov [M], bx
; your other prompt
call DEC_IN
mov [N], bx
; call a display routine?
; or put it in-line?
exit:
; always!
; your subroutines go here
; after the "main" part of your code
That should save you from having to use cx
to know which number you're doing. DEC_IN
will need to end with a ret
, of course, and the assignment says save and restore registers. We can't save and restore bx
of course, we're returning our number in it! You start off...
DEC_IN:
; input character from keyboard, converts ASCII to appropriate binary, stores into respective memory location
mov ah, 01h ; keyboard input function
int 21h ; character input, copies character into al
mov bx, ax ; moves ax into bx to avoid ax being messed with
Don't be in such a rush to get the number into bx
. For one thing, there's still junk in ah
. And first, you want to make sure it's a valid digit. And before that, you probably want to check if it's the carriage return indicating the user's done - we don't want to try to make that part of our number!
DEC_IN:
push ax
xor bx, bx ; zero a register for our number
.top:
mov ah, 1
int 21h
cmp al, 13
je .done
cmp al, '0'
jb error ; jl is for signed comparisons
cmp al, '9'
ja error ; jg is for signed
; okay, we have a good digit
sub al, '0'
; multiply "result so far" by 10
imul bx, 10 ; available on true 8086?
; get rid of the junk in al
mov ah, 0
; NOW we can add it it bx
add bx, ax
jmp .top
.done:
pop ax
ret
I'll let you figure out the rest of it - this answer's getting too long. Ask again if you get stuck.
Upvotes: 4