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

What is causing text to be displayed in a random place?

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

在做一些研究时,我发现 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:

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

看看你的操作数大小。 xpos 只有 1 个字节,但你用 add ax, [xpos] 读取了 2 个字节。此外,mul bl 执行 ax = al * bl,因此您丢弃了 80 倍乘法结果的高半部分。

set_cursor_pos returns 和

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 乘以 2 是零点,除非您打算使用 mul bx 并在 dx:ax 中使用完整的 32 位结果。但即便如此,对于 2 你应该只使用 add di,di / setc al 因为进位只能是 1 位。

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

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

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