我正在尝试在 emu8086 中构建一个程序,该程序将作为输入 1 8 位二进制数给出,然后在输出中显示它的十六进制形式。
我的代码是这样的:
data segment
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
mov ax,data
mov ds,ax
mov cx,0
mov bl,8
input:
mov ah,07h
int 21h
cmp al,46
sub al,30h
cmp al,0
je valid
cmp al,1
je valid
jmp input
valid:
cmp bl,0
je exit
sub bl,1
shl cl,1
add cl,al
jmp input
exit:
mov bl,15
and bl,cl
cmp bl,0
je printzero
cmp bl,1
je printone
cmp bl,2
je printtwo
cmp bl,3
je printthree
cmp bl,4
je printfour
cmp bl,5
je printfive
cmp bl,6
je printsix
cmp bl,7
je printseven
cmp bl,8
je printeight
cmp bl,9
je printnine
cmp bl,10
je printa
cmp bl,11
je printb
cmp bl,12
je printc
cmp bl,13
je printd
cmp bl,14
je printe
cmp bl,15
je printf
printzero:
mov dl,'0'
mov ah,02h
int 21h
jmp exit2
printone:
mov dl,'1'
mov ah,02h
int 21h
jmp exit2
printtwo:
mov dl,'2'
mov ah,02h
int 21h
jmp exit2
printthree:
mov dl,'3'
mov ah,02h
int 21h
jmp exit2
printfour:
mov dl,'4'
mov ah,02h
int 21h
jmp exit2
printfive:
mov dl,'5'
mov ah,02h
int 21h
jmp exit2
printsix:
mov dl,'6'
mov ah,02h
int 21h
jmp exit2
printseven:
mov dl,'7'
mov ah,02h
int 21h
jmp exit2
printeight:
mov dl,'8'
mov ah,02h
int 21h
jmp exit2
printnine:
mov dl,'9'
mov ah,02h
int 21h
jmp exit2
printa:
mov dl,'A'
mov ah,02h
int 21h
jmp exit2
printb:
mov dl,'B'
mov ah,02h
int 21h
jmp exit2
printc:
mov dl,'C'
mov ah,02h
int 21h
jmp exit2
printd:
mov dl,'D'
mov ah,02h
int 21h
jmp exit2
printe:
mov dl,'E'
mov ah,02h
int 21h
jmp exit2
printf:
mov dl,'F'
mov ah,02h
int 21h
jmp exit2
exit2:
mov bl,240
and bl,cl
cmp bl,0
je printzero2
cmp bl,1
je printone2
cmp bl,2
je printtwo2
cmp bl,3
je printthree2
cmp bl,4
je printfour2
cmp bl,5
je printfive2
cmp bl,6
je printsix2
cmp bl,7
je printseven2
cmp bl,8
je printeight2
cmp bl,9
je printnine2
cmp bl,10
je printa2
cmp bl,11
je printb2
cmp bl,12
je printc2
cmp bl,13
je printd2
cmp bl,14
je printe2
cmp bl,15
je printf2
printzero2:
mov dl,'0'
mov ah,02h
int 21h
jmp exit3
printone2:
mov dl,'1'
mov ah,02h
int 21h
jmp exit3
printtwo2:
mov dl,'2'
mov ah,02h
int 21h
jmp exit3
printthree2:
mov dl,'3'
mov ah,02h
int 21h
jmp exit3
printfour2:
mov dl,'4'
mov ah,02h
int 21h
jmp exit3
printfive2:
mov dl,'5'
mov ah,02h
int 21h
jmp exit3
printsix2:
mov dl,'6'
mov ah,02h
int 21h
jmp exit3
printseven2:
mov dl,'7'
mov ah,02h
int 21h
jmp exit3
printeight2:
mov dl,'8'
mov ah,02h
int 21h
jmp exit3
printnine2:
mov dl,'9'
mov ah,02h
int 21h
jmp exit3
printa2:
mov dl,'A'
mov ah,02h
int 21h
jmp exit3
printb2:
mov dl,'B'
mov ah,02h
int 21h
jmp exit3
printc2:
mov dl,'C'
mov ah,02h
int 21h
jmp exit3
printd2:
mov dl,'D'
mov ah,02h
int 21h
jmp exit3
printe2:
mov dl,'E'
mov ah,02h
int 21h
jmp exit3
printf2:
mov dl,'F'
mov ah,02h
int 21h
jmp exit3
exit3:
mov ax, 4c00h
int 21h
ends
end start
我很快意识到你不需要将每个输入存储在数组中,你可以将存储数字的寄存器的值左移 1,然后添加输入(1 或 0)。我希望我的代码能够工作,但是我遇到一个问题:
存储我的号码值的寄存器是
CL
。如果我按此顺序键入11110000
,则它会正确运行,CL
的值将变为F0
,这就是我想要的。我将其通过AND Fh
的掩码来提取4个LSB,然后通过F0h
的AND掩码来提取4个MSB,但是在输出中我得到了00
。老实说,我不知道我错在哪里。BL
的值寄存器与CL
寄存器的值相同,但仍然不起作用。
mov bl,8 input: mov ah,07h int 21h cmp al,46 sub al,30h cmp al,0 je valid cmp al,1 je valid jmp input valid: cmp bl,0 je exit sub bl,1 shl cl,1 add cl,al jmp input exit:
cmp al,46
指令没有任何作用。这是之前编辑留下的内容:只需将其删除即可。您可以简化检查以及循环:
mov bl, 8
input:
mov ah, 07h ; DOS.DirectSTDINInput
int 21h ; -> AL
sub al, 30h ; Convert from character to number [0,9]
cmp al, 1 ; Everything other than [0,1] is ABOVE 1 ...
ja input ; and so `JA input` will go repeat the input
shl cl, 1 ; Make room in CL
add cl, al ; Add the new digit
dec bl ; `DEC` already sets the flags
jnz input ; Repeating 8 times means we jump back 7 times
exit:
exit: mov bl,15 and bl,cl cmp bl,0 je printzero cmp bl,1 je printone ... exit2: mov bl,240 and bl,cl cmp bl,0 je printzero2 cmp bl,1 je printone2 ...
and
的作用是从 BL 寄存器中删除低半字节,但高半字节仍然保留在原来的位置。这意味着 BL 中的值位于 {0,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240} 中。快速修复就是替换一系列
cmp bl,?
指令:
exit:
mov bl, 240
and bl, cl
cmp bl, 0
je printzero2
cmp bl, 16
je printone2
cmp bl, 32
je printtwo2
...
exit2:
mov bl, 15
and bl, cl
cmp bl, 0
je printzero
cmp bl, 1
je printone
cmp bl, 2
je printtwo
...
目前您的程序包含大量重复指令。存在更好的解决方案,我确信 @PeterCordes 提供的链接将揭示这些。
尽管如此,除了我自己完成整个任务之外,我建议您研究下面的代码,您自己会发现这已经大大简化了程序,并且它演示了如何编写可读的代码。请注意,我不会将其视为“最佳”解决方案:
mov bl, 8
input:
mov ah, 07h ; DOS.DirectSTDINInput
int 21h ; -> AL
sub al, 30h ; Convert from character to number [0,9]
cmp al, 1 ; Everything other than [0,1] is ABOVE 1 ...
ja input ; and so `JA input` will go repeat the input
shl cl, 1 ; Make room in CL
add cl, al ; Add the new digit
dec bl ; `DEC` already sets the flags
jnz input ; Repeating 8 times means we jump back 7 times
; ---------------
mov bl, 240 ; High Nibble mask
and bl, cl ; BL = {0, 16, 32, 48, ... , 208, 224, 240}
mov dl, '0'
cmp bl, 0
je printHigh
mov dl, '1'
cmp bl, 16
je printHigh
...
mov dl, 'E'
cmp bl, 224
je printHigh
mov dl, 'F' ; No need for `CMP BL, 240`. It's 240 for sure
printHigh:
mov ah, 02h
int 21h
; ---------------
mov bl, 15 ; Low Nibble mask
and bl, cl ; BL = {0, 1, 2, 3, ... , 13, 14, 15}
mov dl, '0'
cmp bl, 0
je printLow
mov dl, '1'
cmp bl, 1
je printLow
...
mov dl, 'E'
cmp bl, 14
je printLow
mov dl, 'F' ; No need for `CMP BL, 15`. It's 15 for sure
printLow:
mov ah, 02h
int 21h
; ---------------
mov ax, 4C00h
int 21h