我正在尝试编写一些代码,以在屏幕上的给定位置显示一些文本。
进行一些研究时,我发现this page显示了公式position = (y_position * characters_per_line) + x_position;
。
以下是用于计算和设置位置的代码片段:
set_cursor_pos:
push ax
push bx
mov al, [ypos]
mov bl, 80
mul bl
add ax, [xpos]
mov bl, 2
mul bl
mov di, ax
pop bx
pop ax
ret
此方法有效,直到ypos = 3
和xpos = 15
之后,它似乎重新开始。听到一些例子:
y = 2,x = 30:
y = 0,x = 60:
y = 3,x = 15:
y = 4,x = 0:
如您所见,我的算法在y=3, x-15
之前有效。之后,它会环绕。
这是因为没有足够的内存吗?我需要启用A20线吗?这是另一个问题吗?如果是这样,请您说明原因和原因。
最后,这就是全部。我的代码:
org 0x7c00
mov ax, 0xB800
mov es, ax
xor di, di
cli
mov ah, 0Fh
mov si, msg
call set_cursor_pos
call print
hlt
print:
cli
lodsb
stosw
cmp al, 0
jne print
ret
set_cursor_pos:
push ax
push bx
mov al, [ypos]
mov bl, 80
mul bl
add ax, [xpos]
mov bl, 2
mul bl
mov di, ax
pop bx
pop ax
ret
msg db 'Hello, World', 0
xpos db 0
ypos db 4
times 510-($-$$) db 0
dw 0xaa55
答案 0 :(得分:2)
查看您的操作数大小。 xpos
只有1个字节,但是您正在使用add ax, [xpos]
读取2个字节。另外,mul bl
会ax = al * bl
,因此您将丢弃80乘以mul的高一半结果。
即set_cursor_pos
返回
di = (( (80*ypos) & 0xff) + (xpos + (ypos<<8)) ) & 0xFF) * 2
从先前的问题中,您将目标定为与386兼容,因此可以使用
movzx di, byte [ypos]
imul di, di, 80
movzx ax, byte [xpos]
add di, ax
add di, di ; di *= 2. equivalent to shl di, 1 but more efficient.
(80 = 16 * 5,所以您也可以避免使用imul
/ lea di, [edi + edi*4]
/ shl di, 4
。或者使用任何与8086兼容的技巧,乘以这么少的数字位。)
除非您要使用mul
并在mul bx
中使用完整的32位结果,否则使用dx:ax
乘以2是零点。但是即使那样,对于2,您也应该只使用add di,di
/ setc al
,因为结转值只能是1位。
如果xpos
和ypos
是16位的,则可以将它们用作内存操作数:
imul di, [ypos], 80
add di, [xpos]
add di, di ; di *= 2
或者当然可以先将它们保存在寄存器中。