Search code examples
assemblyx86-16tasm

Extra segment won't register color data in assembly


I am programming a game similar to breakout in assembly (tools:DosBOX, notepad++, tasm), and whilst creating the borders and platform in Graphics mode, I've stumbled upon 2 problems:

  1. It seems as if the extra segment won't register the color information, as I can't get it right and when I try to pull it gives me a 0 which is black, as opposed to white which is 0Fh.
  2. It's a slight problem which I tried to resolve, but for some reason, when when I try to paint the second and third border, a part of the 1st border turns black, you'll see it if you run the code. I wasn't able to determine why it happens and the debugger didn't show anything odd.

This is my current code, the main procedures that are involved in the creating of the borders, platform and movement of the platform are BorderPaint, PlatBuild and PlatMove

    IDEAL
    MODEL small
    STACK 100h
    DATASEG
    platLoc dw 63806
    speed1 dw 10
    speed2 dw 0FFFFh
    CODESEG
    ;procedure to paint borders-6 px white pixels
    proc BorderPaint
        push ax
        push bx
        push di
        push cx

    mov ax,0A000h ;accesses graphics mode video memory
    mov es,ax
    xor di,di

    ;first line-left vertical
    ;sets color white

    mov ax,0Fh
    mov cx,200 ;enters nested loop
    FirstLoop1:
    push cx
    mov cx,6
    SecondLoop1:
    mov [es:di],ax
    inc di
    loop SecondLoop1
    sub di,6
    add di,320
    pop cx
    loop FirstLoop1
    ;second line- up horizontal
    mov di,7
    mov cx,313
    FirstLoop2:
    push cx
    mov cx,6
    SecondLoop2:
    mov [es:di],ax
    add di,320
    loop SecondLoop2
    sub di,1920
    inc di
    pop cx
    loop FirstLoop2

    mov di,314
    mov cx,200
    FirstLoop3:
    push cx
    mov cx,6
    SecondLoop3:
    mov [es:di],ax
    inc di
    loop SecondLoop3
    sub di,6
    add di,320
    pop cx
    loop FirstLoop3

    ; xor di,di
    ; mov ax,0Fh
    ; mov cx,200
    ; FirstLoop4:
    ; push cx
    ; mov cx,6
    ; SecondLoop4:
    ; mov [es:di],ax
    ; inc di
    ; loop SecondLoop4
    ; sub di,6
    ; add di,320
    ; pop cx
    ; loop FirstLoop4

        pop cx
        pop di
        pop bx
        pop ax
    ret
    endp BorderPaint 

    proc PlatBuild
    push di
    push cx
    push ax
        mov di,[platLoc]
        mov ax,5
        mov cx,40
        LoopPaint2:
        push cx
        mov cx,10
        LoopPaint1:
        mov [es:di],ax
        sub di,320
        loop LoopPaint1
        add di,320*10
        inc di
        pop cx
        loop LoopPaint2
    pop ax
    pop cx
    pop di
    ret
    endp PlatBuild

    Proc PlatErase
    push di 
    push cx 
    push ax
        mov di,[platLoc]
        mov ax,0
        mov cx,40
        LoopPaint4:
        push cx
        mov cx,10
        LoopPaint3:
        mov [es:di],ax
        sub di,320
        loop LoopPaint3
        add di,320*10
        inc di
        pop cx
        loop LoopPaint4
    pop ax
    pop cx
    pop di
    ret
    endp PlatErase

    Proc PlatMove
    push ax
    push cx
    push dx
    push di
        mov ax,0A000h
        mov es,ax
        call BorderPaint
        ;Input
        CheckPress1:
        mov ah,0h
        int 16h


        cmp al,'a'
        jne nxt11
        jmp MoveLeft1
         Nxt11:
        cmp al,'d'
        jne nxt12
        jmp MoveRight1
        Nxt12:
        cmp al,'q'
        jne CheckPress1
        jmp endproc1

        MoveLeft1:
        call Delay
        mov dx,[platLoc]
        add dx,8*320
        sub dx,1d
        mov di,dx
        mov ax,[es:di]
        cmp ax,0Fh
        jne move1
        jmp CheckPress1
        move1:
        call PlatErase
        dec [platLoc]
        call PlatBuild
        mov ah,1h
        int 16h
        je MoveLeft1
        jmp CheckPress1

        MoveRight1:
        call Delay
        mov dx,[platLoc]
        add dx,41

        mov di,dx
        mov ax,[es:di]
        cmp ax,0Fh
        jne move2
        jmp CheckPress1
        move2:
        call PlatErase
        inc [platLoc]
        call PlatBuild
        mov ah,1h
        int 16h
        je MoveRight1
        jmp CheckPress1
        EndProc1:
    pop di
    pop dx
    pop cx
    pop ax
        ret
        endp PlatMove
        proc Delay
    push cx
        mov cx, [speed2]    
    LoopLong:                                    
    push cx                  
        mov cx, [speed1]        
      LoopShort:                               
        loop LoopShort    
    pop cx                    
        loop LoopLong
    pop cx
    ret
    Endp Delay
    start:
        mov ax,@data
        mov ds,ax
        mov ax,13h
        int 10h
        call BorderPaint
        call PlatBuild
        mov ax, [es:63680]
        call PlatMove

    exit:
        mov ax,4c00h
        int 21h
    END startenter code here

Solution

    1. mov [es:di],ax writes WORD (two bytes) into VRAM, ax = 0x000F, so you write at [es:di] value 0x0F, and at [es:di+1] value 0x00 (black).

        sub di,6
        add di,320
    

    This is blasphemy :/ ... add di,320-6 remains the intent visible on source level, but also shows less ignorance toward the machine, minimizing the amount of instructions used.

    BTW, if you want to store 6 bytes with 0x0F value, you can also store three words of 0x0F0F value, saving half of VRAM accesses (which are expensive). So then

        mov di,<some VRAM address>
        mov cx,<number of lines>
        mov ax,0F0Fh  ; <color><color> (two pixels at same time)
    Draw6PixelsLoop:
        mov [es:di],ax
        mov [es:di+2],ax
        mov [es:di+4],ax
        add di,320
        dec cx
        jnz Draw6PixelsLoop
    

    is more optimal hard-coded way how to draw 6 pixels (with only 3 VRAM writes) and move 1 line below.


    1. not sure, what you mean, but probably one problem may be reading word (two pixels) from VRAM in PlatMove and then comparing them with 0Fh cmp ax,0Fh, i.e. two pixels "white + black" = 000Fh. So on the left side this will probably work well, but on the right side it will find such two pixels only at the end of the border (keep in mind after the last pixel on the right side the next byte is the first left pixel on next line, so if you have borders 6 pixels strong, the first white+black pixel is at next line where the left border ends).