汇编程序中的双缓冲视频

时间:2011-07-03 00:25:18

标签: video buffer assembly tasm

我正在尝试在汇编程序中执行双缓冲视频,但在这种情况下我有一个问题,我不知道如何解决它,按下一个键后它无法关闭。显然问题出在 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 个答案:

答案 0 :(得分:2)

一些事情:

  • 检查分配内存时的返回值(进位设置为错误,ax包含错误代码,8表示内存不足)[注意,如果您使用的是COM文件,大部分可用内存已经分配给你的程序,因此分配将失败]
  • 您需要在使用字符串说明之前清除/设置方向标记(在这种情况下为cld,请参阅例如here
  • 在复制中删除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, '$'