我得到了一些代码进行分析。此代码启用键盘上的numLock和scrollLock LED。我了解这段代码的大部分内容,但是不了解循环部分(0104)。我知道这是等待输入缓冲区为空。但是有必要吗?没有这部分,代码可以很好地工作。
0100: MOV AL, ED
0102: OUT 60, AL
0104: IN AL, 64
0106: TEST AL, 02
0108: JNZ 0104
010A: MOV AL, 03
010C: OUT 60, AL
答案 0 :(得分:2)
关于AT键盘控制器here,有很好的信息。您可能最感兴趣的状态寄存器(端口0x64)(端口0x60)中的位是:
位1:输入缓冲区状态
0:输入缓冲区为空,可以写入。 1:输入缓冲区已满,不要 写吧。
位0:输出缓冲区状态
0:输出缓冲区为空,尚未读取。 1:输出缓冲区已满,可以 读。 (在PS / 2情况下,第5位表明可用数据是否为 通过键盘或鼠标。)读取端口0x60时,将清除此位。
在写入端口0x60之前,您必须等到输入缓冲区状态位被清除。等待失败可能会导致发送到控制器的数据丢失。从端口0x60读取数据之前,应等待 Output Buffer Status Bit 设置,因为这意味着有数据需要读取。读取不可用的数据将导致从端口读取的所有内容全部变为无数据时被视为数据。
乍一看,状态寄存器中的术语 Input 和 Output 似乎违反直觉。这些位是从键盘控制器而不是PC的角度来命名的。控制器上的输出缓冲区是PC上的输入缓冲区,反之亦然。
仿真器和虚拟机似乎要宽容得多。如果您希望代码有最大的机会在各种实际硬件和仿真器上工作,则需要插入等待适当状态的循环,然后再继续操作。
代码的第一部分将0xED命令 1 发送到键盘:
0100: MOV AL, ED
0102: OUT 60, AL
此命令的documented为:
命令0xED:写入LED
此命令后跟一个字节,指示所需的LED 设置。位7-3:未使用,0。位2:1:CapsLock LED点亮。位1:1: NumLock LED点亮。位0:1:ScrollLock LED点亮。确定后,两个字节均为 已确认。如果第二个字节被识别为命令,则该命令为 确认并完成。否则,将返回NACK(和键盘) 可能需要启用)。
这部分代码正在等待位1(输出缓冲区状态)变为0:
0104 IN AL, 64
0106: TEST AL, 02
0108: JNZ 0104
当键盘控制器准备好接收数据时,PC可以将数据自由写入端口0x60,这是此代码的作用:
010A: MOV AL, 03
010C: OUT 60, AL
这是与命令0xED相关的LED数据。值03 = 00000011。位1设置为启用NumLock,位1设置为启用ScrollLock。