Несколько вещей:
- Проверьте возвращаемое значение при выделении памяти (перенос установлен на ошибку,
ax
содержит код ошибки, 8 означает нехватку памяти) [Обратите внимание, что есливы используете COM-файл, большая часть доступной памяти уже будет выделена вашей программе, и, таким образом, выделение не удастся] - Перед использованием строковых инструкций необходимо очистить / установить флаг направления (
cld
в этом случае см., например, здесь ) - После удаления
ds
при копировании необходимо восстановить его, прежде чем получить доступ к modovideo
(неявно используется ds
).
С этими изменениями (и некоторыми дополнительными, чтобы он работал в COM-файле), он должен работать.Я использовал nasm (скомпилировать с nasm -f bin -o gfx.com gfx.asm
) и DOSBox, чтобы проверить это.Обратите внимание, что метод, который я использую для выделения памяти, возможно, содержит ошибки, так как я давно программировал для DOS.
org 0x100
start:
; Allocate back buffer
%if 0
; Use 21h call to allocate memory (for EXE files)
mov ah, 0x48
mov bx, 64000/16
int 0x21
jc error ; carry set on error
mov [vscr_seg], ax
%else
; COM files get (most/all) available memory, grab some of it
mov bx, word [0x0002] ; Get last paragraph from PSP
sub bx, 64000/16 ; Make room for back buffer
mov [vscr_seg], bx
mov ax, ds
add ax, 0x1000 ; Program start paragraph + 64K (max of COM file)
cmp ax, bx ; Did it fit?
jae error
%endif
; Clear back buffer
mov es, [vscr_seg]
xor di, di
xor ax, ax
mov cx, 32000
cld
rep stosw
; Get previous video mode
mov ah, 0x0f
int 0x10
mov [previous_video_mode], al
; Set mode 13h (320x200 256 colors)
mov ax, 0x0013
int 0x10
; Fill half the back buffer with color 15
mov es, [vscr_seg]
xor di, di
mov ax, 0x0f0f
mov cx, 16000
cld
rep stosw
; And fill in all pixel colors at bottom row
mov di, 199 * 320
mov cx, 255
xor al, al
.fill:
; the below two instructions are equal to stosb when the direction flag is cleared
mov [es:di], al
inc di
inc al
loop .fill
; Copy from back buffer to the screen
push ds ; Remember to save DS!
mov ds, [vscr_seg]
mov ax, 0xa000
mov es, ax
xor di, di
xor si, si
mov cx, 32000
cld
rep movsw
pop ds ; ... And restore it again
; Wait for keypress
mov ah, 0x01
int 0x21
; Restore video mode
mov ah, 0x00
mov al, [previous_video_mode]
int 0x10
; Skip error block
jmp exit
error:
; Print bx and ax to facilitate debugging
push ax
call print_hex_word
pop ax
mov bx, ax
call print_hex_word
mov ah, 0x09
mov dx, error_string
int 0x21
exit:
; Exit
mov ax, 0x4c00
int 0x21
; Print 16-bit word in BX, trashes AX and DX (at least)
print_hex_word:
mov dx, bx
shr dx, 12
call print_hex_digit
mov dl, bh
call print_hex_digit
mov dl, bl
shr dl, 4
call print_hex_digit
mov dl, bl
call print_hex_digit
; New line
mov ah, 0x02
mov dl, 13
int 0x21
mov dl, 10
int 0x21
ret
print_hex_digit:
push bx
and dl, 0x0f
add dl, '0'
cmp dl, '9'
jle .print
add dl, 'A' - '0' - 10
.print:
mov ah, 0x02
int 0x21
pop bx
ret
previous_video_mode db 0
vscr_seg dw 0
error_string db 'Error occurred!', 13, 10, 7, '$'