двойной буфер видео в ассемблере - PullRequest
2 голосов
/ 03 июля 2011

Я пытаюсь сделать видео с двойным буфером в ассемблере, но в этом случае у меня проблема, я не знаю, как ее решить, она не может закрыться после нажатия клавиши.Видимо проблема в inc di :

(я пытаюсь закрасить все 320 * 200 пикселей белым цветом с буфером)

.model small
.386
.stack 400h
.data

modovideo db ?
vram dw 0

xVal dw ?
yVal dw ?

.code
main proc
   mov ax,@data
   mov ds,ax

  mov ah,0fh
  int 10h
  mov modovideo,al

  mov ah,0
  mov al,13h
  int 10h

  ; Segmento de memoria =====================================

  mov ah,48h
  mov bx,4000 ; 64000/16
  int 21h
  mov vram,ax

  ; Escribir en el segmento de memoria =======================================

mov es,vram

;offset = 320*y + x
    ;mov xVal,160
    ;mov yVal,100
    ;mov ax,320
    ;mul yVal
    ;add ax,xVal


mov di,0
mov al,7

mov cx,640
paso1:
    mov es:[di],al
    inc di ; <-----------
    loop paso1

; Volcar sobre pantalla ======================================================

mov ds,vram
xor si,si
mov dx,0A000h
mov es,dx
xor di,di
mov cx,64000
rep movsb   

mov ah,1
int 21h

salir:
mov al,modovideo
mov ah,0
int 10h

mov ah,4ch
int 21h

    main endp

1 Ответ

2 голосов
/ 03 июля 2011

Несколько вещей:

  • Проверьте возвращаемое значение при выделении памяти (перенос установлен на ошибку, 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, '$'
...