问题
I have found many questions on this issue, however, I have not been able to get my code to run. My program should take a hex value, check to see if it is a valid hex character, then display the hex value as a decimal value. If it is a lower case hex character then it needs to be converted to upper case. All this needs to be in a loop.
I have all of this done except for converting the hex to decimal. I have the code in the program I think should convert it, but it will not compile. I will list the compiler errors below the code. If the code in the label convert: is commented out(except for the last line, "jmp display") then the program will run as it should, but obviously will not show the value as a decimal.
Compiling with nasme: "nasm -fbin getChar.asm -o getChar.com -l getChar.lst"
I am running the program in dosbox.
; This program gets a char from user and prints it out as a decimal
org 100h ; program start point
section .data
msgIn: DB 13, 10, "Enter a Hex Digit: $"
msgOut: DB 13, 10, "Decimal Value: $"
msgOpt: DB 13, 10, "Enter another?(y or n): $"
errMsg: DB 13, 10, "Illegal character, Enter 0..9 or A..F: $"
HNUM: DB 19H
NUM: DB 0
D: DB 10h
H: DB 16
CNT: DB 0
section .text
continue: ; start of loop
mov dx, msgIn ; offset address of message to display
mov ah, 9 ; print string function
int 21h
mov ah, 1 ; keyboard input sub-program
int 21h ; read character into al
mov cl, al
legal: ; compare input to see if valid
cmp cl, 48 ; cl < 0
jl end_if ; yes, error msg
cmp cl, 70 ; cl > F
jg check_case ; yes, error msg
jmp prntMsg2 ; print value of input
check_case: ; check case of input
cmp cl, 97 ; cl < a
jl end_if ; yes, error msg
cmp cl, 102 ; cl > f
jg end_if ; yes, error msg
jmp to_upper ; need to send to function to convert to upper case
; then pass to prntMsg2
to_upper:
and al, 223 ; convert to upper case(0DFh)
jmp prntMsg2
end_if: ; error message if invalid input
mov ah, 9
mov dx, errMsg ; print error message
int 21h
jmp continue ; get a new value
prntMsg2: ; print second message*****
mov dx, msgOut ; offset of second message
mov ah, 9 ; print string function
int 21h ; display message
convert:
mov cx, 00
mov dx, 00
L6: mov ax, 00
mov al, [HNUM]
div word [D]
mov [HNUM], al
mov bx, ax
mov cl, 0
mov ax, 1
L5:
cmp cl, 00
je L7
mul word [H]
sub cl, 1
jmp L5
L7:
mul bh
add dx, ax
add word [CNT], 1
cmp word [HNUM], 0
jg L6
mov [NUM], dl
jmp display
display: ; display character
mov dl, al
mov ah, 2 ; print char function
int 21h
mov ah, 9 ; see if user wants to do it again
mov dx, msgOpt
int 21h
mov ah, 1
int 21h
mov bl, al
cmp bl, 'y' ; bl = y
jne exitPrg ; no, end
jmp continue ; get a new value
exitPrg: ; exit program
mov ah, 4ch ; exit to DOS function
int 21h ; see you later!
The code above has been edited and now compiles and runs. However, it is still not doing the conversion from hex to decimal correctly. It simply doesn't display a value, just blank. It will also hang up if a letter is entered, even a letter a-f. A number does not hang it up, but still a value is not displayed.
Now that I have it running at least I can work on fixing it, however, any guidance is appreciated. Thanks Gene for getting me up and running.
回答1:
NASM memory operands use square brackets to denote dereferencing. So for example you will want:
mov al, [HNUM]
div byte [D]
mov [HNUM], al
The NASM Manual explains this. RTFM!
Without the brackets, the labels are treated as immediate operands equal to the address of the memory location. The first line is no syntax error, but causes al
to be loaded with the low byte of the address of HNUM
. Not what you wanted. The div
is an error because 8086 has no instruction to divide by an immediate quantity. And the mov
is nonsense because you can't write to an immediate value.
So the error messages are telling you what's wrong. In the lines referenced, the operands do not comport with their instructions.
Addition
I went ahead and installed dosbox and NASM. Indeed NASM is not quite as smart as MASM about inferring operand types. So for the div
instruction you need byte
, (not word
) as now reflected above. I could not grok your algorithm. It's more complicated than necessary. Here is my version:
; This program gets a hex digit from user and prints it out as a decimal
org 100h ; program start point
section .data
msgIn: DB 13, 10, "Enter a hex digit or q to quit: $"
msgErr: DB " isn't hex. Must be 0-9, A-F, or a-f.$"
msgOut: DB " has decimal value $"
buffer: DB "xxxxx"
endBuf: DB ".$"
ten: DB 10
section .text
continue: ; start user interaction
mov dx, msgIn ; offset address of message to display
mov ah, 9 ; print string function
int 21h
get_hex_digit:
mov ah, 1
int 21h ; read character into al
check_for_quit:
cmp al, 'q' ; handle quit character
je exit
cmp al, 'Q'
je exit
check_for_digit:
cmp al, '0' ; handle 0-9
jl check_for_upper
cmp al, '9'
jg check_for_upper
sub al, '0' ; convert to numeric value
jmp print_decimal
check_for_upper:
cmp al, 'A' ; handle A-F
jl check_for_lower
cmp al, 'F'
jg check_for_lower
sub al, 'A'-10 ; convert to numeric value
jmp print_decimal
check_for_lower:
cmp al, 'a' ; handle a-f
jl handle_digit_error
cmp al, 'f'
jg handle_digit_error
sub al, 'a'-10 ; convert to numeric value
print_decimal: ; print al contents as decimal 0-255
mov di, endBuf ; set buffer pointer to char after digits
next_digit:
dec di ; advance buffer pointer to next char
xor ah, ah ; clear high byte of ax for division
div byte [ten] ; ah = ax % 10, al = ax / 10
add ah, '0' ; convert ah to ascii
mov [di], ah ; copy to buffer
or al, al ; set condition codes with al
jnz next_digit ; jump if more digits to print
print_digits:
mov dx, msgOut ; offset address of message preamble
mov ah, 9 ; print string function
int 21h
mov dx, di ; offset address of converted digits
mov ah, 9 ; print string function
int 21h
jmp continue ; otherwise, get next input
handle_digit_error:
mov dx, msgErr ; offset address of message to display
mov ah, 9 ; print string function
int 21h
jmp continue
exit: ; exit program
mov ah, 4ch ; exit to DOS function
int 21h ; see you later!
回答2:
check_for_upper:
cmp al, 'A' ; handle A-F
jl check_for_lower
this should go be:
jl handle_digit_error
as Ucase "A" is 41h, and Lcase "a" is 61h
来源:https://stackoverflow.com/questions/21870702/assembly-how-to-convert-hex-input-to-decimal