Что заставляет текст отображаться в случайном месте? - PullRequest
0 голосов
/ 06 октября 2018

Я пытаюсь написать код, который отображает некоторый текст в заданной позиции на экране.

При проведении исследования я нашел эту страницу , которая показывает формулу 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:

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 голосов
/ 06 октября 2018

Посмотрите на ваши размеры операндов.xpos только 1 байт, но вы читаете 2 байта с add ax, [xpos].Кроме того, mul bl делает ax = al * bl, так что вы отбрасываете верхнюю половину результата с кратностью 80.

т.е. 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 для умножения на 2, если только вы не собираетесь использовать mul bx и использовать полный 32-битный результат в dx:ax.Но даже тогда, для 2 вы должны просто использовать add di,di / setc al, потому что вынос может быть только 1 бит.

Если xpos и ypos были 16-битными, вы могли бы использоватьони как операнды памяти:

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

Или, конечно, вы могли бы сначала хранить их в регистрах.

...