以下代码包含一个十六进制数字(与 ASCII 代码相关,假设它是从键盘获得的),我想将此十六进制数字打印到屏幕上,但使用 DOS 中断以“二进制”形式打印。NUMLOCK 是 45 小时。
[org 0x0100]
mov AL, 45 ;moving NUMLOCK hexadecimal(ASCII code) to AX
~~How to display its binary relevant to screen using DOS Interrupt?
以下代码包含一个十六进制数字(与 ASCII 代码相关,假设它是从键盘获得的),我想将此十六进制数字打印到屏幕上,但使用 DOS 中断以“二进制”形式打印。NUMLOCK 是 45 小时。
[org 0x0100]
mov AL, 45 ;moving NUMLOCK hexadecimal(ASCII code) to AX
~~How to display its binary relevant to screen using DOS Interrupt?
DOS 中断只有这些服务输出到屏幕:
AH = 02h - 将字符写入标准输出
AH = 06h - 直接控制台输出
AH = 09h - 将字符串写入标准输出
AH = 40h - “写入” - 写入文件或设备(使用 STDOUT 或 STDERR 文件句柄调用时)
所有这些仅将值从输入复制到输出,没有任何转换或格式化,因此通常您的输入应该是 ASCII 字符或字符串,或二进制字节数组。
但是您应该明白,计算机以二进制工作(低电流/高电流,通常被解释为 0 或 1)。它不理解任何其他值。
因此,当您69
在 CPU 寄存器中有值时al
,它al
是由 CPU 芯片上的 8 位单元创建的,这些单元设置为“0 1 0 0 0 1 0 1”。这些单元称为位。因此,当您使用 Assembly source 编写代码mov al,45h
时,编译器会在编译期间为您创建这种二进制形式,并将其作为单字节存储到机器代码中,因为mov al,imm8
指令就是这样期望编码的值。
因此,对于“二进制字符串”,您所要做的就是从左到右逐位运行 8 次,然后输出字符'0'
或输出'1'
到屏幕,具体取决于特定位是清除还是设置。
如果您的任务是以任何其他基数显示数字(例如基数 10 = 十进制),则必须进行复杂的计算以找出特定数字'6'
并'9'
形成十进制格式“69”。
任何 2 的幂的基数都更简单一些,因为您只需要提取一组位(例如,在十六进制 16 中,每个数字都是值的 4 位,请注意45h
二进制0100
(4) 和0101
(5) . 但是你仍然要计算比特组。
只有二进制基数 2 输出基本上可以打印,因为这是计算机在寄存器和内存中存储数字整数值的本机方式。
al
了解什么是位,以及8 位寄存器、ax
16 位寄存器、ah
高 8 位等是什么意思是绝对至关重要的ax
...如果您不了解二进制数学的工作原理,以及如何这些值以位编码,您将很难完成非常简单的组装任务,比如这个。
这就是为什么我什至不在这里添加任何代码的原因,因为您需要首先计算出您的数学,以完全理解值的“base N”编码意味着什么。
在您了解计算机的工作原理后,您很可能能够快速检查一些按位指令,如移位或测试,并执行位检查 + 输出 0/1 到屏幕循环。当您理解它时,这是非常简单的任务。
编辑:我决定给你一些更直观的东西,我在“简单的 8 位汇编器”中写了“显示二进制 8 位值”。
它不是 8086,而是:
将下一个代码放入页面:http ://schweigi.github.io/assembler-simulator/
并使用“Step”慢慢地逐条指令,并观看右边的“内存”和“寄存器”视图,看看指令做了什么(你可以使用x86指令参考指南阅读指令应该做什么,我想都是描述也适合这个简单的汇编器(虽然有些标志不是 100% 正确,但你不会注意到并更好地从一开始就学习 8086 指令)。
; init input values
MOV A, 0x45 ; A = 45h (this ASM needs "0x" for hexa)
MOV D, 240 ; point to output display after last digit
MOV C, 8 ; 8 chars (representing bits) to output
print_loop:
; convert lowest bit of A into ASCII digit '0' or '1'
MOV B, A ; copy of A (to preserve A value)
AND B, 1 ; extract lowest bit of A (B = 0 or 1)
ADD B, '0' ; turn the value 0/1 into ASCII '0'/'1'
; display '0' or '1' to "Output" window
MOV [D], B ; write the digit to output
DEC D ; update output pointer
; shift all bits in A to right by 1 position
SHR A, 1
; create space after 4 bits displayed
CMP C, 5 ; 8-3 = 5, fourth DEC is below (in future)
JNE .no_space
DEC D ; skip one position in output
.no_space:
; loop until 8 bits are displayed
DEC C ; counter of bits
JNZ print_loop ; repeat until C becomes 0
; stop simulator
HLT
然后你可以想你怎么能把它变成8086版本。
我建议将循环逻辑从最高位开始,使用 8086 会更容易,因为您可以使用更多指令,例如adc
(例如,您可以尝试找出......的结果是什么mov dl,24
adc dl,dl
......它可能是之后很有趣shl
)。然后您可以直接输出数字int 21h,2
(如果您反转逻辑以从左到右测试位)。
或者您可以保持相同的逻辑,并将 ASCII 数字从末尾存储到内存缓冲区(确保您有足够大的缓冲区),然后使用 single 打印它int 21h, 9
。
或者......还有数百万种其他方法可以计算相同的结果(从原始值输出到屏幕“0100 0101”ASCII 数字45h
)。它只是关于在正确的地点和时间输出正确的数字,你如何计算它并不重要,只要你的结果是正确的。