用内联汇编替换movemem(),用于VGA图形处理

编程语言 2026-07-11

我在Turbo C中写一个简单的动画(用于VGA,在NuXT 2上,一个IBM PC/XT的克隆机上)。我把图形写入一个缓冲区,然后每一帧清空缓冲区、写入更新后的对象,然后把缓冲区拷贝到VGA内存。效果不错,但需要优化。目前我把缓冲区拷贝到VGA时使用的是 movedata(SEG_buffer, OFF_buffer, SEG_vga, OFF_vga, SIZE);

当我尝试把对 movedata() 的调用替换成内联汇编时,混乱就会随之而来,通常会让电脑卡死。下面是我正在尝试的代码。 (出于无奈我把所有寄存器的push/pop都加上了,但没有用);请注意 SIZE2 = 32000SIZE = 64000

asm {
        push ds          
        push si
        push di
        push cx
        push es

        mov ax, SEG_buffer
        mov ds, ax
        mov si, OFF_buffer

        mov ax, SEG_vga
        mov es, ax
        mov di, OFF_vga

        mov cx, SIZE2
        cld
        rep movsw

        pop es
        pop cx
        pop di
        pop si
        pop ds     
    }

解决方案

SEG_bufferOFF_bufferSEG_vgaOFF_vgaSIZE 这些变量,还是它们只是立即数?

如果这些是基于内存的变量,那么由于 汇编操作的顺序,你将陷入混乱。一旦 mov ds, ax 完成其工作,剩余的取数将来自错误的段。只需最后加载DS。 (在 movedata(SEG_buffer, OFF_buffer, SEG_vga, OFF_vga, SIZE); 中,是Turbo C来完成解引用。) 如果这些标识符确实只是立即数,那么TASM就必须拒绝 mov ds, SEG_buffer,但如果它们是变量,那么直接加载段寄存器一直都是可能的!

这显然是VGA的老式13h模式,分辨率为320x200、256色。还能在哪儿一次性写入64000字节呢?于是问题就来了,为什么这个操作要这样那么多参数?显存入口固定在ES:DI=A000:0000,长度固定在CX=64000,你的64000字节私有缓冲区将占据它自己的内存段,因此可以预期SI=0的偏移量。

push ds
push es
push cx
push si
push di
mov  cx, 0A000h
mov  es, cx
xor  di, di
mov  ds, SEG_buffer   ; (*)
xor  si, si
mov  cx, 64000/2
rep  movsw            ; (**)
pop  di
pop  si
pop  cx
pop  es
pop  ds

(*) 将其设为变量才最有意义。通常,你并不知道应用程序被加载到哪里,因此你会计算出私有缓冲区的位置,并把结果存储在基于内存的变量中。 (**) 你可以相信Turbo C已经会把方向标志位清除了。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章