Search code examples
pointersassemblyx86tasmsegment

ASM x86 How to get the pointer from an array properly? (16-bit TASM / DOS)


Allright folks, let's hope this is an easy one: I need to access an array to achieve double-buffering (I use mode 13h) in 16-bit TASM. BUT: No matter if I use "OFFSET", "BYTE PTR [Array]", "BYTE PTR Array", or whatever I have tried already, the program reads/writes to the incorrect memory block, which is partly behind the actual start of the array.

Heres my (for now not really optimised and very messy) code:

.MODEL  MEDIUM
.STACK
.DATA
        XPos    DW      0
        YPos    DB      0
        Color   DB      0

        BoxX1   DW      0
        BoxY1   DB      0
        BoxX2   DW      0
        BoxY2   DB      0

        VPage   DB      64010   DUP(0)  ;TODO: Size *might* be incorrect.
        PageSeg DW      0
.CODE

SetVGA13 PROC
        MOV     AX,     0013h   ;Screen mode 13.
        INT     10h             ;Set screen mode to AX.
        MOV     AX,     0A000h  ;Screen segment.
        MOV     ES,     AX      ;You can't affect segment registers
        RET
ENDP

;-------DrawPixel---------------
; WORD XPos  = x
; WORD YPos  = y
; BYTE Color = colour
;-------------------------------
DrawPixel PROC
        XOR     AH,     AH
        MOV     AL,     [YPos]
        MOV     DX,     320
        MUL     DX
        ADD     AX,     [XPos]
        MOV     DI,     AX
        MOV     AL,     [Color]
        MOV     ES,     [PageSeg]  
        ;ADD     ES,     DI
        MOV     ES:[DI],AL
        ;MOV     ES:[DI],AL
        RET
ENDP

DrawBox PROC
        MOV CL, [BoxY1]
        YLoop:
        MOV     BL,     CL
        PUSH    CX
        MOV     CX,     [BoxX1]
        XLoop:
        MOV     [XPos], CX
        MOV     [YPos], BL
        MOV     [Color],CL
        CALL    DrawPixel
        INC     CX
        CMP     CX,     [BoxX2]
        JNZ     XLoop
        POP     CX
        INC     CL
        CMP     CL,     [BoxY2]
        JNZ     YLoop
        RET
ENDP

WaitFrame PROC
        PUSH    DX
        ; Port #03DA contains VGA status
        MOV     DX,     03DAh
        IN      AL,     DX
        WaitRetrace:
        ; Bit 3 will be on if we're in retrace
        TEST    AL,     08h
        JNZ     WaitRetrace
        EndRefresh:
        IN      AL,     DX
        TEST    AL,     08h
        JZ      EndRefresh
        POP     DX
        RET
ENDP

RestoreVideo PROC
        ; Return to text mode
        MOV     AX,     03h
        INT     10h
        RET
ENDP

ClearScreen PROC
        XOR     CX,     CX
        ;MOV     ES,     [PageSeg] 

        ClearLoop:
        MOV     DI,     CX  
        ;MOV     ES,     [PageSeg]
        MOV     BX,     OFFSET VPage
        ADD     BX,     CX
        MOV     AL,     [BX];VPage[DI];ES:[DI] 
        MOV     [Color],AL 

        MOV     AX,     0A000h
        MOV     ES,     AX
        MOV     AL,     [Color]
        MOV     ES:[DI],AL

        INC     CX
        CMP     CX,     64000
        JNZ     ClearLoop
        RET
ENDP

Main:
        ;INITIALISE
        MOV     BX,     OFFSET VPage
        MOV     [PageSeg],BX


        CALL    SetVGA13
        ;CALL    MakePalette       

        MOV     [BoxX1],33
        MOV     [BoxY1],33
        MOV     [BoxX2],99
        MOV     [BoxY2],99

        ;LOOP
        GameLoop:
        ;DRAW
        ;CALL    DrawBox
        CALL    ClearScreen
        ;CALL    WaitFrame

        ;INPUT
        MOV     DX,     60h
        IN      AL,     DX

        CMP     AL,     75
        JNZ     NotLeft
        SUB     [BoxX1],1
        SUB     [BoxX2],1
        NotLeft:

        IN      AL, DX
        CMP     AL, 77
        JNZ     NotRight
        ADD     [BoxX1],1
        ADD     [BoxX2],1
        NotRight:


        CMP     AL,     1
        JNZ     GameLoop



        ;END PROGRAM
        Error:

        ;CALL    ClearScreen
        CALL    RestoreVideo
        MOV     AH,     4Ch
        INT     21h
        END     Main

This code shows a rainbow coloured box that you can move around with the left and right arrow keys,

;INITIALISE
        MOV     BX,     OFFSET VPage
        MOV     [PageSeg],BX

That is my sad attempt to getbthe pointer to my buffer, but doesnt return the correct one

Sorry that my question was not done, i realised that when i got out of bed immediately for some reason.


Solution

  • Although this is not how I would code things, I'll offer up a couple of suggestions that may get you closer to resolving your problems.

    When your executable loads the DS and ES registers originally point to the DOS PSP for your program. In your case you need to at least point DS to your DATA segment. The DATA segment that is filled in at run time by the DOS EXE loader can be referenced in your code by prefixing the segment name with an @ (AT) symbol. So you can replace this code:

    ;INITIALISE
    MOV     BX,     OFFSET VPage
    MOV     [PageSeg],BX
    

    With this:

    ;INITIALISE
    MOV BX, @DATA           ; Set up DS with our program's DATA segment
    MOV DS, BX              
    MOV     [PageSeg],BX    ; VPage is in DATA segment, move segment to PageSeg
    

    In your DrawPixel code you'll need to add the VPage offset to DI. Replace this code:

    XOR     AH,     AH
    MOV     AL,     [YPos]
    MOV     DX,     320
    MUL     DX
    ADD     AX,     [XPos]
    MOV     DI,     AX
    MOV     AL,     [Color]
    MOV     ES,     [PageSeg]  
    MOV     ES:[DI],AL
    

    with:

    XOR     AH,     AH
    MOV     AL,     [YPos]
    MOV     DX,     320
    MUL     DX
    ADD     AX,     [XPos]
    MOV     DI,     AX
    MOV     AL,     [Color]
    MOV     ES,     [PageSeg]  
    ADD     DI,     OFFSET VPage    ; We need to add VPage's offset 
                                    ; from beginning of PageSeg
    MOV     ES:[DI],AL
    

    Video mode 13h is 320x200x256 colors. The amount of video ram that is needed would be 320*200*1 = 64000. This could be changed from:

    VPage   DB      64010   DUP(0)  ;TODO: Size *might* be incorrect. 
    

    to:

    VPage   DB      64000   DUP(0)
    

    With these changes the program seems to display a rainbow box and moves left and right on the screen with the arrow keys.

    There may be other bugs but I don't know what you were trying to achieve. This code could be simplified greatly. My changes were the minimal ones to work with the way you coded your program and make it somewhat functional.