我有一个 16 位汇编程序 (NASM),它会更改为 VGA 图形模式并尝试用纯色填充整个屏幕,但我只能填充最多 32767 (0x7fff) 像素(而不是完整的 320x200 显示屏,是 64000 (0xfa00) 像素),如果再多,所有白色像素都会因某种原因消失。我假设它是某种带符号的增量,但我不太确定,因为我还在学习一点。否则,像素可以显示并绘制到屏幕上(我使用 QEMU)
init.asm:
org 0h
bits 16
%define ENDL 0dh, 0ah
jmp _entry
_entry:
push msg_hello
call puts
jmp entry
entry:
call toggle_vga
push 0fh
push 07fffh
call fill_screen
jmp endp
toggle_vga:
push ax
mov ah, 0fh
mov al, 0h
int 10h
cmp al, 13h
je .toggle_vga_off
jne .toggle_vga_on
.toggle_vga_on:
mov ah, 00h
mov al, 13h
int 10h
jmp .toggle_vga_end
.toggle_vga_off:
mov ah, 00h
mov al, 03h
int 10h
jmp .toggle_vga_end
.toggle_vga_end:
pop ax
ret
fill_screen:
push bp
mov bp, sp
push es
push ax
push dx
push cx
push di
mov ax, 0a000h
mov es, ax
mov dl, [bp + 6]
mov cx, [bp + 4]
mov di, 0
.fill_screen_loop:
cmp di, cx
jge .fill_screen_done
mov [es:di], dx
inc di
jmp .fill_screen_loop
.fill_screen_done:
pop di
pop cx
pop dx
pop ax
pop es
pop bp
ret
puts:
push bp
mov bp, sp
push bx
push ax
mov bx, [bp + 4]
.puts_loop:
cmp byte [bx], 0
je .puts_done
mov ah, 0eh
mov al, [bx]
int 10h
inc bx
jmp .puts_loop
.puts_done:
pop ax
pop bx
pop bp
ret
endp:
cli
hlt
msg_hello: db 'init: loaded successfully.', ENDL, 0
jge .fill_screen_done
根据 signed 值之间的不等式跳转。对于有符号补码算术,0xfa00
是数字 -1536。值 0 到 0x7fff 都是正数,因此当 di
在此范围内时,我们确实有 di >= cx
,因此循环继续。但随后您递增到 0x8000
,在有符号算术中为 -32768,并且条件不再为真。
您想使用
jae .fill_screen_done
,它根据 unsigned 值之间的不等式进行跳转。 (这个答案中有更多信息;我似乎记得在某个地方有一个更好的答案,但现在找不到了。)或者甚至只是je .fill_screen_done
;每一步将 di
加一,因此在相等之前不可能变为“上方”。
另一个小bug是
mov [es:di], dx
;由于 dx
是一个 16 位寄存器,因此它存储一个字(两个字节)。但您只想存储 dl
中的一个字节(您已将 dh
保留为未初始化),所以将其设为 mov [es:di], dl
。
您可以通过将字节复制到
dx
的两半 (mov dh, dl
) 来提高效率,然后一次存储一个单词 (mov [es:di], dx
) 并将 di
加 2(add di, 2
,或 ) inc di
两次)。确保 cx
始终为偶数。
更好的是使用
rep stosw
,我会让你自己研究。