-4

以下代码包含一个十六进制数字(与 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?
4

1 回答 1

4

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 位寄存器、ax16 位寄存器、ah高 8 位等是什么意思是绝对至关重要的ax...如果您不了解二进制数学的工作原理,以及如何这些值以位编码,您将很难完成非常简单的组装任务,比如这个。

这就是为什么我什至不在这里添加任何代码的原因,因为您需要首先计算出您的数学,以完全理解值的“base N”编码意味着什么。

在您了解计算机的工作原理后,您很可能能够快速检查一些按位指令,如移位或测试,并执行位检查 + 输出 0/1 到屏幕循环。当您理解它时,这是非常简单的任务。


编辑:我决定给你一些更直观的东西,我在“简单的 8 位汇编器”中写了“显示二进制 8 位值”。

它不是 8086,而是:

  • 说明是“相同的”(只是非常有限的设置,不是完整的 8086)
  • 完全不同的寄存器(四个 8 位通用 A、B、C、D 和两个专用 PC 和 SP 指针)
  • 内存布局完全不同(总内存只有 256 个字节,最后 24 个字节用于“输出”显示)
  • 原理是一样的,如果你理解这一点,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)。它只是关于在正确的地点和时间输出正确的数字,你如何计算它并不重要,只要你的结果是正确的。

于 2017-01-16T18:39:27.327 回答