问题描述
我正在尝试在 NASM 中制作一个 DOS 程序,该程序使用中断 10h 来显示在左上角的 16 种可用颜色中循环的像素。我还使用中断 21h 使程序每 1/100 秒(100 fps)运行一次。
segment .data
pixelcolor: db 0
pixelx: dw 100
pixely: dw 100
timeaux: db 0 ; used later on to force the program to run at 100fps
segment .text
global _start
_start:
mov ah,00h
mov al,0dh
int 10h
mov ah,0bh
mov bh,00h
mov bl,00h
int 10h
.infinite:
mov ah,2ch
int 21h ; get system time
cmp dl,timeaux ; if 1/100 seconds haven't passed yet...
je .infinite ; ...skip current frame
; else,continue normally
mov byte[timeaux],dl
mov ah,00h
mov al,0dh
int 10h
mov ah,0bh
mov bh,00h
mov bl,00h
int 10h
mov ah,0ch
mov al,pixelcolor
mov cx,pixelx
mov dx,pixely
int 10h
inc byte[pixelcolor]
jmp .infinite
然而,当我在 DOSBox 中实际运行程序时,像素只是保持红色。有谁知道为什么我的无限循环不起作用? (注意:我对 NASM 很陌生,所以老实说,我什至不惊讶我的程序只能在 15% 的时间内运行。)
解决方法
问题实际上不在于循环本身。循环在每次迭代中所做的事情就是问题所在。我的一些问题和观察是:
-
由于这是一个 DOS COM 程序,您将需要在顶部添加一个
org 100h
,因为 DOS 加载程序加载了一个 COM 程序以偏移当前程序段的 100h。否则,您的数据偏移量将不正确,从而导致从错误的内存位置读取/写入数据。 -
您的
mov al,pixelcolor
有问题。它必须是mov al,[pixelcolor]
。如果没有方括号1,pixelcolor
的偏移量将移动到 AL,而不是存储在pixelcolor
偏移量处的内容。pixelx
和pixely
也是如此。您的代码将相同的像素颜色(在您的情况下为红色)重复打印到屏幕上错误的位置2。这段代码:mov ah,0ch mov al,pixelcolor mov cx,pixelx mov dx,pixely int 10h inc byte[pixelcolor]
应该是:
mov ah,[pixelcolor] mov cx,[pixelx] mov dx,[pixely] int 10h inc byte[pixelcolor]
-
需要注意的是,定时器的分辨率默认仅为每秒 18.2 次(~55ms)。这比您要达到的 1/100 秒分辨率还低。
-
某些版本的 DOS 可能总是为 1/100 的第二个值返回 0。
-
使用 BIOS 将像素写入屏幕可能会使编码更简单(它抽象出视频模式中的差异),但与将像素直接写入内存相比,速度会相当慢。
-
我会推荐 Borland 的 Turbo Debugger (TD) 来调试 DOS 软件。 Turbo Debugger 包含在许多 Borland's DOS C/C++ compiler suites 中。
脚注
-
1在 NASM 中括号
[]
的使用与 MASM/TASM/JWASM 不同。 - 2虽然您的问题说您想写到屏幕的左上角,但代码表明您确实打算在坐标 100,100 处写入像素。