是什么导致文本在随机位置显示?

时间:2018-10-06 15:32:55

标签: assembly nasm x86-16 bootloader vga

我正在尝试编写一些代码,以在屏幕上的给定位置显示一些文本。

进行一些研究时,我发现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 = 3xpos = 15之后,它似乎重新开始。听到一些例子:

y = 2,x = 30:

enter image description here

y = 0,x = 60:

enter image description here

y = 3,x = 15:

enter image description here

y = 4,x = 0:

enter image description here




如您所见,我的算法在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

1 个答案:

答案 0 :(得分:2)

查看您的操作数大小。 xpos只有1个字节,但是您正在使用add ax, [xpos]读取2个字节。另外,mul blax = 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位。

如果xposypos是16位的,则可以将它们用作内存操作数:

imul   di, [ypos], 80
add    di, [xpos]
add    di, di       ; di *= 2

或者当然可以先将它们保存在寄存器中。