J'apprends la programmation avec l'assembleur x86, partie 8
en développement !
Le code source de invaders.asm
; ========
; invaders
; ========
;
; C:\nasm -fbin invaders.asm -o invaders.com
org 0x100
global main
VGA_MEMORY_SEGMENT equ 0xa000 ; segment mémoire de la carte VGA
VGA_WIDTH equ 320 ; nombre de pixels horizontaux en VGA
VGA_HEIGHT equ 200 ; nombre de pixels verticaux en VGA
section .text
main:
call enter_vga ; on entre dans le mode VGA
call render ; on dessine un truc
call wait_key ; on attend une touche au clavier
call quit_vga ; on quitte le mode VGA
mov ax, 0x4c00 ; on quitte sans erreur
int 0x21
enter_vga:
mov ah, 0x0f ; on récupère le mode vidéo en cours
int 0x10 ; dans al
mov [old_mode], al ; on conserve cette valeur dans old_mode
mov ah, 0x00 ; on change le mode vidéo
mov al, 0x13 ; AL = 0x13 soit VGA 320x200x256 couleurs
int 0x10
ret
quit_vga:
mov ah, 0x00 ; on restaure le mode vidéo
mov al, [old_mode] ; conservé dans old_mode
int 0x10
ret
wait_key:
mov ah, 0x01 ; on vérifie si une touche a été appuyée
int 0x16
jz wait_key ; si ZF est activé, aucune touche n'a été appuyée
ret
render:
mov ax, VGA_MEMORY_SEGMENT
mov es, ax
xor dx, dx ; dx est l'index du sprite, soit 0
mov [sprite_id], dx
mov ax, 146 ; x = 146
mov [x], ax
mov ax, 92 ; y = 92
mov [y], ax
mov al, 4 ; clr = rouge
mov [clr], al
call draw_sprite ; on dessine le premier sprite
inc dx ; dx est l'index du second sprite
mov [sprite_id], dx
mov ax, [x] ; x = x + 16
add ax, 16
mov [x], ax
mov al, 2 ; clr vert
mov [clr], al
call draw_sprite ; on dessine le second sprite
ret
put_pixel:
push ax
push dx
push di
mov ax, VGA_WIDTH ; ax = 320
mov dx, [y] ; dx = y
mul dx ; dx:ax = 320 * y
mov di, ax ; di = 320 * y
add di, [x] ; di = 320 * y + x
mov al, [clr] ; al = clr
stosb ; [es:di] = clr
pop di
pop dx
pop ax
ret
draw_sprite:
pusha ; on sauve tous les registres courants
mov ax, [y] ; on sauve y
push ax
mov ax, [x] ; on sauve x
push ax
mov [prevx], ax
mov ax, [sprite_id] ; ax = sprite_id
shl ax, 4 ; ax = sprite_id * 16: il y a 16 bytes par sprites
mov si, sprite1 ; si est l'offset du premier sprite
add si, ax ; on ajoute à si l'offset du sprite choisi par sprite_id
mov cl, 8 ; compteur ligne : 8 lignes par sprites
draw_sprite_line:
lodsw ; ax = [ds:si] = ligne du sprite
mov dx, [x] ; dx = x
mov bx, 0x8000 ; notre masque
mov ch, 16 ; compteur bit : 16 bits par lignes
draw_sprite_bit:
test bx, ax ; test bit & masque
jz draw_sprite_no_pixel ; si 0 on ne dessine rien, sinon...
call put_pixel ; ... on dessine le pixel
draw_sprite_no_pixel:
shr bx, 1 ; masque pour le bit suivant
inc dx ; x = x + 1
mov [x], dx
dec ch ; on passe au bit suivant
jnz draw_sprite_bit
push ax ; on conserve ax qui va nous servir pour affecter les variables
mov ax, [y] ; y = y + 1
inc ax
mov [y], ax
mov ax, [prevx] ; on recupère la valeur de x
mov [x], ax
pop ax ; on récupère ax
dec cl ; on passe à la ligne suivante
jnz draw_sprite_line
pop ax ; on restaure x
mov [x], ax
pop ax ; on restaure y
mov [y], ax
popa ; on restaure tous les registres courants
ret
section .data
old_mode: db 0 ; variable pour conserver le mode vidéo précédent
x: dw 0 ; x du pixel
prevx: dw 0 ; prevx pour conserver x dans notre boucle
y: dw 0 ; y du pixel
clr: db 0 ; couleur du pixel
sprite_id: dw 0 ; index du sprite (0 ou 1)
; ci dessous les lignes des deux sprites :
sprite1: dw 0x0820, 0x0440, 0x0fe0, 0x1bb0, 0x3ff8, 0x2fe8, 0x2828, 0x06c0
sprite2: dw 0x0300, 0x0780, 0x0fc0, 0x1b60, 0x1fe0, 0x0480, 0x0b40, 0x14a0