Home > Mobile >  BIOS read-character macro only works once in x86-16 MBR bootloader
BIOS read-character macro only works once in x86-16 MBR bootloader

Time:08-05

org 0x7c00  
jmp _main

; _data:
playerPosition dw 0
; %1 == coluna (x)
; %2 == linha (y)
%macro drawRacket 2
    
    mov ah, 0ch ; print pixels mode
    mov dx, %2

    for1:
        mov bx, 32 ;racket height 
        add bx, %2
        cmp dx, bx  ; racket end (row)
        je .fim1
        mov cx, %1  ; racket beggining (column)
        jmp .for2
        jmp for1

        .fim1:
        jmp mainLoop

        ; loop to draw each line
        .for2:
        mov bx, 8 ;racket width
        add bx, %1
        cmp cx, bx   ;
        je .fim2
        mov al, 0x0f
        mov ah, 0ch
        int 10h
        inc cx
        jmp .for2

        .fim2:
        inc dx
        jmp for1

%endmacro


_main:
    ; 
    xor ax, ax
    mov ds, ax
    mov cx, ax
    mov dx, ax

    call setVideoMode

    ;racket initial position
    mov word[playerPosition], 10

    mainLoop:

        mov ah, 01h
        int 16h

        cmp al, 115
        je moveDown
        jmp mainLoop
    


jmp $

; 
setVideoMode: 
    mov ah, 0       ; 
    mov al, 13h     ;
    int 10h
ret

 moveDown:
     drawRacket 10, word[playerPosition]
     mov ax, word[playerPosition]
     inc ax
     mov word[playerPosition], ax
 jmp mainLoop


times 510-($-$$) db 0
dw 0xaa55

That's the assembly code. I am trying to make a "Pong game", and I am at the very beggining. I was trying to draw the 1st player's racket, but it is not working. When I press "s" (mainLoop function) on the keyboard, it actually works and jumps to the macro drawRacket and draws it. But, if I press "s" again nothing works.. I already tried to change a lot of things on the mainLoop function but nothing works, what makes me think that I have some problems with the macro drawRacket. I would appreciate any hints or answers.

CodePudding user response:

But, if I press "s" again nothing works..

Regardless of the keyboard issue about using function 01h instead of function 00h, your macro does get its second invokation and draws the racket a second time, but it does so exactly where the first racket was drawn. You don't see anything moved, that way! (For the sensation of true movement you would have to remove the first racket (partially) before drawing the second racket (partially)).

The reason is that the macro's execution stops with a jmp mainLoop. This bypasses your code that increments the playerPosition variable. The quick solution is to place the .fim1 label near the bottom of the macro.

%macro drawRacket 2
        mov     ah, 0Ch
        mov     dx, %2

        ...

    .fim2:
        inc     dx
        jmp     .for1

    .fim1:                            ; New position!
%endmacro

Now the macro code will fall through in the code that increments Y. This happens because of how macro's work. In your program the line drawRacket 10, word[playerPosition] gets replaced by all the code you have between the tags %macro drawRacket 2 and %endmacro. This process is called macro expansion.
The expanded version looks like this:

moveDown:
        mov     ah, 0Ch              ; \
        mov     dx, [playerPosition] ;  \
                                     ;   \
        ...                          ;    \
                                     ;      The expanded macro code   
    drawRacket.fim2:                 ;    /
        inc     dx                   ;   /
        jmp     drawRacket.for1      ;  /
    drawRacket.fim1:                 ; /
        mov     ax, [playerPosition]
        inc     ax
        mov     [playerPosition], ax
        jmp     mainLoop

The keyboard function 01h checks to see if a key is available and reports about the fact. You receive a preview of the key in AX, and the key is not removed from the keybuffer. Next time your code uses this keyboard function 01h, you still get the preview of that same key, even if you pushed another key on the keyboard.
Your program just needs to wait for a key and act upon it. Use the keyboard function 00h that does exactly that.

mov     ah, 00h   ; BIOS.GetKeyboardKey
int     16h       ; -> AL is ASCII, AH is scancode
  • Related