Search code examples
assemblygraphicsdosx86-16vga

Mode X in Assembly x86-16, Why is plane 1 not printing and all the other planes are not in the correct order?


I am writing in TASM 3.0 on DosBox 0.74 and I am trying to write in Mode x (Tweaked 13h, unchained mode 13), but here you can see in the image, it's not quite right. It seems that plane 1 (second plane) is not printing at all, and all the others are not in the right order. I know that the code here is inefficient, but I want to make it work and then clean it up.

Output

proc showBMP
    push cx
    mov ax, 0A000h
    mov es, ax
    mov cx, [BMPHeight]
    mov ax, [BMPWidth]
    xor dx, dx
    mov si, 4
    div si
    mov bp, dx
    mov dx, [BMPX]
    showBMP_nextLine:
        call VGAPlaneStartBMP
        push cx
        push dx
        mov di, cx
        add di, [BMPY]
        mov cx, di
        shl cx, 6
        shl di, 8
        add di, cx
        add di, dx
        mov ah, 3fh
        mov cx, [BMPWidth]
        add cx, bp
        mov dx, offset BMPMaxLine
        int 21h
        cld
        mov cx, [BMPWidth]
        mov si, offset BMPMaxLine
        showBMP_nextLine_movsbLoop:
            push cx
            push di
            shr di, 2
            mov cl, [ds:si]
            mov [es:di], cl
            inc [VGAPlane]
            inc si
            pop di
            inc di
            pop cx
            call VGAPlaneSelect
        loop showBMP_nextLine_movsbLoop
        pop dx
        pop cx
    loop showBMP_nextLine
    pop cx
    ret
endp showBMP

Here you can see a procedure for printing a bitmap file, which worked perfectly on chain-4 mode 13.

  • BMPHeight - as name suggest is the height of the picture
  • BMPWidth - same
  • BMPX - where the picture starts on the screen (x coordinate)
  • BMPY - same but Y coordinate
  • BMPMaxLine - array of 320 works as a buffer
  • VGAPlane - 0/1/2/3 one of the planes
  proc VGAPlaneStartBMP
       push ax
       push bx
       mov ax, [BMPX]
       mov bx, offset PlaneByX
       add bx, ax
       mov al, [bx]
       mov [VGAPlane], al
       pop bx
       pop ax
       call VGAPlaneSelect
       ret
   endp VGAPlaneStartBMP

This procedure, for each line of printing, chooses the plane by the starting x of a line:

  • PlaneByX - MAX_WIDTH / NUMBER_OF_PLANES dup (PLANES), RESET

  • MAX_WIDTH is 320, NUMBER_OF_PLANES is 4, PLANES is 0, 1, 2, 3,

proc VGAPlaneSelect
        push ax
        push dx
        mov al, 02h
        mov dx, 03C4h
        out dx, al
        VGAPlaneSelect_start:
        cmp [VGAPlane], 0
        jne VGAPlaneSelect_0
            mov al, 0h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_0:
        cmp [VGAPlane], 1
        jne VGAPlaneSelect_1
            mov al, 1h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_1:
        cmp [VGAPlane], 2
        jne VGAPlaneSelect_2
            mov al, 4h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_2:
        cmp [VGAPlane], 3
        jne VGAPlaneSelect_3
            mov al, 8h
            jmp VGAPlaneSelect_end
        VGAPlaneSelect_3:
            mov [VGAPlane], 0
            jmp VGAPlaneSelect_start
        VGAPlaneSelect_end:
        inc dx
        out dx, al
        pop dx
        pop ax
        ret
    endp VGAPlaneSelect

And lastly this code is when selecting a plane.


Solution

  • Thanks to Fuz for finding an answer and Jonathon Reinhart for making my question clearer. in the VGAPlaneSelect procedure, the al values, which are outputs for the 0x3c5 VGA address, should be 2^(the plane that you want to choose), and for plane 0 2^0 it should be 1, and I wrote 0

    so:

            cmp [VGAPlane], 0
            jne VGAPlaneSelect_0
                mov al, 1h
                jmp VGAPlaneSelect_end
            VGAPlaneSelect_0:
    

    a better way to do the VGAPlaneSelect procedure is:

        proc VGAPlaneSelect
            push ax
            push dx
            push cx
            mov al, 02h
            mov dx, 03C4h
            out dx, al
            VGAPlaneSelect_start:
            mov ax, 1
            mov cl, [VGAPlane]
            shl ax, cl
            cmp [VGAPlane], 4
            jne VGAPlaneSelect_end
                mov [VGAPlane], 0
                jmp VGAPlaneSelect_start
            VGAPlaneSelect_end:
            mov dx, 03C5h
            out dx, al
            pop cx
            pop dx
            pop ax
            ret
        endp VGAPlaneSelect