如何在裸机16位x86组件中睡觉?

Kim*_*ürs 5 assembly sleep 16-bit

无论CPU的时钟速度如何,我都希望暂停执行大约0.1秒.代码应该直接从引导设备运行,因此不应该使用DOS中断.

我正在使用int 15h,但这似乎与我用PIT的通道2进行调制的嘟嘟声相冲突.我听说过频道0,但我不清楚如何设置它.

准确性并不重要,但它应该以相同的速度在旧的和现代的计算机上运行.因此,循环指令不是一种选择.

哔声代码和睡眠只是一堆用于改变频率和打开和关闭扬声器的宏.如果我之前打电话给睡觉,嘟嘟似乎不会停止beepoff.

以下是蜂鸣声宏:

%macro beepinit 0
    mov al, 182
    out 43h, al
%endmacro

%macro beepfreq 0
    out 42h, al
    mov al, ah
    out 42h, al
%endmacro

%macro beepon 0
    in al, 61h
    or al, 00000011b
    out 61h, al
%endmacro

%macro beepoff 0
    in al, 61h
    and al, 11111100b
    out 61h, al
%endmacro
Run Code Online (Sandbox Code Playgroud)

和睡眠一:

%macro sleep 2
    push dx
    mov ah, 86h
    mov cx, %1
    mov dx, %2
    int 15h
    pop dx
%endmacro
Run Code Online (Sandbox Code Playgroud)

我正在使用NASM汇编程序.

这不是重复如何在16位MASM Assembly x86中创建睡眠功能?,因为这个是用于Windows或DOS之外的裸机组装.

Dav*_*zer 4

可编程间隔定时器是最佳选择。如果您只处理较新的系统,请考虑 HPET。对于 PIT,有一些事情需要了解。首先,要进行设置,您需要使用端口 0x43 作为控制/命令端口来配置通道零定时器。我们要发送的字节有一个位映射字段:

  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0 
+----------------------------------------------+
| Channel  |  RW Mode  |   Channel Mode  | BCD?|
+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

通道将被清除以选择通道零。

RW 模型可以是 1-LSB、2-MSB 或 3-LSB 后跟 MSB。我们希望这两个位都打开(位模式为 3, 011),因为我们需要发送 16 位值(LSB 然后 MSB)

对于通道模式,我们需要方波。这是 3 (011) 的位模式

我们想要发送计数器的 16 位除数,而不是 BCD 值,因此最低位被清除。

这给了我们:二进制的 000110110 或十六进制的 0x36。现在我们进行设置:

mov al, 0x36    ; 0x36 from our work above
out 0x43, al    ; Send that byte to the control port

mov ax, 11931   ; The timer ticks at  1193182. 100hz would be 1193182/11931
out 0x40, al    ; send low byte
out 0x40, ah    ; send high byte
Run Code Online (Sandbox Code Playgroud)

此时,您需要决定是否要对中断 (IRQ 0) 做出反应,或者只是想读取计时器。我将向您推荐关于 OSDev 的这篇优秀参考资料,其中对两者都有精彩的文章和示例代码。