8086 汇编中更快的键盘扫描代码检测

2023-12-09

是否有可能比仅从硬件端口 60h 读取数据更快地检测和收集键盘的通断和制动?

每当我按下一个键,比如说“W”键,然后快速按下另一个键,“W”键的中断代码仍然由端口 60h 返回。

在我正在编写的游戏中,当用户尝试快速改变方向时,这会产生将玩家精灵锁定到位的效果。

我尝试过使用 int 16h 函数 01h 和 int 16h 函数 00,但与端口 60h 相比,它非常不稳定且缓慢。

这是我使用端口 60h 的输入代码。我只是将扫描码传递给 bp。我所有需要用户输入的程序都会检查 bp 中的扫描码。

HANDLE_INPUT PROC

;CLEARS THE KEYBOARD TYPEHEAD BUFFER AND COLLECTS A SCANCODE 

;ALTERS BP

    push ax
    push es

    mov ax, 40h                
    mov es, ax                  ;access keyboard data area via segment 40h
    mov WORD PTR es:[1ah], 1eh  ;set the kbd buff head to start of buff
    mov WORD PTR es:[1ch], 1eh  ;set the kbd buff tail to same as buff head
                                ;the keyboard typehead buffer is now cleared
    xor ah, ah
    in al, 60h                  ;al -> scancode
    mov bp, ax                  ;bp -> scancode, accessible globally   

    pop es
    pop ax
    ret


HANDLE_INPUT ENDP

这是使用 int 16h 的替代版本,其工作效果几乎不如上面使用端口 60h 的版本。

HANDLE_INPUT PROC

;COLLECTS A SCANCODE 

;ALTERS BP

    push ax

    xor bp, bp    ;clear out bp
    mov ah, 1     ;Function 1, check key status.
    int 16h       ;Is a key ready? 
    jz NO_KEY     ;If zf cleared, then no.
    xor ah, ah    ;Otherwise, a key is waiting.
    int 16h       ;ah -> scancode
    xor al, al    
    xchg al, ah   ;ax -> scancode
    mov bp, ax    ;bp -> scancode, accessible globally


NO_KEY:

    pop ax
    ret


HANDLE_INPUT ENDP

为了回答我自己的问题,通过端口 60h 提供的扫描码实际上并不是太慢,而是太快了。

在我的问题中给出的以下示例中:“每当我按下一个键,比如说‘W’键,然后快速按下另一个键,‘W’键的中断代码仍然由端口 60h 返回。”

我认为端口 60h 仍然返回“W”的中断代码的原因是键盘控制器没有足够的时间来记录我敲击了新键的事实。

实际上,我先按下了另一个键,并且确实返回了该键的 make 代码。然后,一瞬间,我的手指从“W”键上移开,用“W”中断代码覆盖了端口 60h 返回的字节。

解决方案:仅在中断代码与已存储在 bp 中的 make 代码相对应时才采用中断代码。

新的 HANDLE_INPUT 过程,现在工作得更好:

HANDLE_INPUT PROC

;CLEARS THE KEYBOARD TYPEHEAD BUFFER AND COLLECTS A SCANCODE 

;ALTERS BP

    push ax
    push bx
    push es

    mov ax, 40h                
    mov es, ax                  ;access keyboard data area via segment 40h
    mov WORD PTR es:[1ah], 1eh  ;set the kbd buff head to start of buff
    mov WORD PTR es:[1ch], 1eh  ;set the kbd buff tail to same as buff head
                                ;the keyboard typehead buffer is now cleared
    xor ah, ah
    in al, 60h                  ;al -> scancode
    test al, 80h                ;Is a break code in al?
    jz ACCEPT_KEY               ;If not, accept it. 
                                ;If so, check to see if it's the break code
                                ;that corresponds with the make code in bp.
    mov bx, bp                  ;bx -> make code   
    or bl, 80h                  ;change make code into it's break code  
    cmp bl, al                  ;Do the new and old break codes match?
    je ACCEPT_KEY               ;If so, accept the break code.
    pop es                      ;If not, bp retains old make code.
    pop bx
    pop ax
    ret

ACCEPT_KEY: 
    mov bp, ax                  ;bp -> scancode, accessible globally

    pop es
    pop bx
    pop ax
    ret


HANDLE_INPUT ENDP
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

8086 汇编中更快的键盘扫描代码检测 的相关文章

  • 设置 IRQ 映射

    我正在遵循一些教程和参考文献来尝试设置我的内核 我在教程中遇到了一些不熟悉的代码 但根本没有解释它 这是我被告知映射的代码16 IRQs 0 15 到 ISR 地点32 47 void irq remap void outportb 0x2
  • X86 预取优化:“计算 goto”线程代码

    我有一个相当重要的问题 我的计算图有循环和多个 计算路径 我没有制作一个调度程序循环 其中每个顶点将被一一调用 而是将所有预先分配的 框架对象 放置在堆中 代码 数据 这有点类似于线程代码 甚至更好 CPS 只是在堆中跳转 执行代码 每个代
  • 如何在程序中将自己缝合到自己的尾部,无限循环地封装 64KB 代码段?

    如果指令的顺序执行经过偏移量 65535 则8086将从同一代码段中的偏移量 0 处获取下一个指令字节 接下来的 COM 程序利用这一事实 不断将其整个代码 总共 32 个字节 缝合到自己的尾部 环绕在 64KB 代码段中 你可以称之为二元
  • 如何编译GCC生成的asm?

    我正在玩一些汇编代码 有些事情困扰着我 我编译这个 include
  • 如何仅使用单个数组在 JavaScript 中模拟调用堆栈

    我正在看维基百科页面 https en wikipedia org wiki Call stack在调用堆栈上 并尝试理解这个图像 据我所知 哈哈 const memory memory 0 3 top of stack pointer m
  • 在 x86 汇编中将 64 位常量移至内存

    我正在使用 Intel x64 程序集 NASM 编译器 尝试将 0x4000000000000000 常量移至内存 该常量在 ieee 754 标准双精度中应等于 2 0 我正在使用的代码是 define two 0x4000000000
  • 无法识别的仿真模式:MinGW32 上的 elf_i386

    我正在尝试制作内核 但无法链接C与程序集一起输出 这ld 我收到错误 无法识别的仿真模式 elf i386 我正在使用 Windows 10 专业版以及 MinGW32 和 MSYS 我正在使用的代码 link ld link ld OUT
  • 将字段中的位扩展到掩码中所有(重叠+相邻)集位的最快方法?

    假设我有 2 个名为 IN 和 MASK 的二进制输入 实际字段大小可能是 32 到 256 位 具体取决于用于完成任务的指令集 每次调用时两个输入都会改变 Inputs IN 1100010010010100 MASK 000111101
  • IDA pro asm 指令更改

    我只是想知道我怎样才能 更改IDA视图A中的asm指令 如何编辑指令 对于 实例 jnz 到 jmp 如何插入新指令 call func1 调用 func2 插入到现有的 代码 我知道如何制作 diff 文件 我知道如何在我的 DLL 上应
  • 无法在 64 位 Linux 上从汇编 (yasm) 代码调用 C 标准库函数

    我有一个函数foo以汇编语言编写 并在 Linux Ubuntu 64 位上使用 yasm 和 GCC 编译 它只是使用以下命令将消息打印到标准输出puts 如下所示 bits 64 extern puts global foo secti
  • 难以理解汇编命令“加载有效地址”[重复]

    这个问题在这里已经有答案了 可能的重复 LEA 指令的目的是什么 https stackoverflow com questions 1658294 whats the purpose of the lea instruction LEA指
  • 16 位模式下的操作数大小前缀

    我试图理解 GAS 的行为 code16 从手册上看 在16位部分 对于32位操作数或指令 会产生66H操作数覆盖前缀用于指令编码 这是否意味着 code16 movw eax ebx 这种模式合法吗 那么代码不能在16位处理器上运行吗 这
  • intfmt: db "%d", 10, 0 在汇编中的含义

    我最近在我的一个汇编文件的顶部看到了这个 并意识到我在打印整数的过程中花了很长时间使用它 而没有真正意识到它最初来自哪里 在我的基本汇编模板中使用 或 10 0 是什么结尾的意思是 section data intfmt db d 10 0
  • 汇编语言程序中连续两次相乘

    我正在使用 8086 模拟器以及 DOSBOX 和 MASM 我知道当我们将 8 位与 8 位相乘时 答案将是 16 位 al 8 bit ax 当我们将 16 位与 16 位相乘时 答案将是 32 位 ax 16 bit dx ax 但如
  • 错误:无法识别的指令 [ORG]

    我试图编写一个引导加载程序以在 dos box 中使用 我写了下面的代码 BITS 16 tell the assembler that its a 16 bit code ORG 0x7C00 Origin tell the assemb
  • 将以下机器语言代码(0x2237FFF1)翻译成MIPS汇编

    到目前为止我已经翻译了这段代码 但我不明白的是如何计算 计算 16 位立即地址的数量 0x2237FFF1 转为二进制 0010 0010 0011 0111 1111 1111 1111 0001 现在我正在读取操作码 001000 并知
  • movsbl指令的作用是什么? [复制]

    这个问题在这里已经有答案了 我在网上搜索过 但找不到明确的示例来理解该指令的作用 因此 如果有人可以举一个例子 这对我来说将会非常有帮助 用符号从字节扩展到长字移动 在Intel语法中 该指令的助记符是MOVSX 当变量类型为 C 时 C
  • 如何恢复 x86-64 寄存器保存约定

    fibonacci cmpq 1 rdi ja recursive movl 1 eax ret recursive push rbp push r10 movq rdi r10 leaq 2 rdi rdi call fibonacci
  • 处理器在操作码​​和数据之间有何不同? [复制]

    这个问题在这里已经有答案了 我正在尝试编写一个反汇编程序 我想知道处理器如何区分操作码和数据字节 例如 这是 Hello World 的字节表示 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x57 0x6f 0x72 0x
  • 在微控制器中将数据从内存移至内存

    为什么我们不能直接将数据从一个内存位置移动到另一个内存位置 如果我问了一个愚蠢的问题 请原谅我 但我认为这是真实的情况 至少对于我遇到的情况而言 8085 8086 n 80386 我并不是真正在寻找移动数据的解决方案 例如 使用 movs

随机推荐