assemblyx86dosx86-16video-memory

Copy from VRAM using movsb?


In x86 asm, what is the right, fast way to copy from VRAM to an array variable in VGA mode 13? I can copy to VRAM no issue using movsb, but copying from VRAM using movsb produces weird results, or can crash my program.

I have a test program to create a line in VRAM, copy that line from VRAM to a variable, then copy that variable to another location in VRAM. The program doesn't work as it is -- strangely changing count dw 320 to count equ 320 makes it work. Any idea what I'm doing wrong? I don't believe changing the count variable is a viable fix.

; assemble with A86
jmp main

vdata db 320 dup 14
vdata_backup db 320 dup 0

video_memory equ 0a000h
count dw 320

wait_for_key:
        mov ax, 0h
        int 016h
        ret

main:
        ; set up mode 13
        mov ax, 013h
        int 10h

        ; copy some data to VRAM
        ; create a line on the screen
        mov si, offset vdata
        mov es, video_memory
        mov di, 640
        mov cx, count
        rep movsb

        ; copy from VRAM to vdata_backup
        push ds
        mov ds, video_memory
        mov si, 640
        mov es, code
        mov di, offset vdata_backup
        mov cx, count
        rep movsb
        pop ds

        ; copy vdata_backup to different part of VRAM
        ; create a new line on the screen
        mov si, offset vdata_backup
        mov es, video_memory
        mov di, 3200
        mov cx, count
        rep movsb

        call wait_for_key

        ; set back to text mode
        mov ah, 0
        mov al, 3
        int 10h

        ; exit to dos
        mov ah, 4ch
        int 21h

Solution

  • In the section of code copy from VRAM to vdata_backup you do:

    push ds
    mov ds, video_memory 
    [snip]
    mov cx, count
    

    You have altered DS so it points to the video graphics segment A000. That is not the segment where count resides. mov cx, count implicitly uses the DS segment and is similar to doing mov cx, [ds:count]. You have retrieved the count from the wrong place in memory. The simple fix is to retrieve count before you modify DS. The code could look like:

    push ds
    mov cx, count
    mov ds, video_memory 
    [snip]