54Fermer56
chickendudeLe 04/12/2012 à 15:37
Voilà du code qui marche grin Quant au VBLANK, j'ai fait une petite routine waitVBlank pour faire juste ça, mais je crois qu'il serait mieux de réorganiser le code un peu pour qu'il y ait une partie seulement qui affiche à l'écran. J'aimerais bien pouvoir tester ces programmes sur une vraie GBA, parfois j'ai l'impression que l'émulation n'est pas parfaite... A propos, il fallait deux vélocités (une X et une Y), et j'ai trouvé que les drapeaux avec les soustractions sont un peu confus, le drapeau carry est armé quand le résultat ne prend pas un "borrow" (je suppose que ça veux dire, si le résultat > 0) et désarmé quand il y'en a (le résultat <= 0), mais j'en suis pas sûr.
.arm
.include "gba.inc"
SCREEN_W	=	240
SCREEN_H	=	160
PADDLE_X	=	SCREEN_W/2-(3*8)/2
PADDLE_Y	=	SCREEN_H-8
BALL_X	=	0
BALL_Y	=	0
.text
.global main

main:
	ldr r0,=OAM	@ on reset les sprites (je ne sais pas si ça a vraiment de l'importance)
	ldr r1,=128	@ il y a 128 emplacements de 8 octets chacuns (l'OAM fait 1ko)
	ldr r2,=(300<<16)	@ le 3ème octet suivit du prochain bit définit la coordonnée X (2^9=512 valeurs) du sprite,
	@ on la met donc à 300 pour être hors de l'écran (il fait 240*160)
	@ (pour les attributs de l'OAM, cf  http://gfx.developpez.com/prog-gba/touches/#L8  )
reset_sprites_loop:
	str r2,[r0],#8	@ on colle la valeur de r2 à l'adresse de r0, puis incrémente de 8 octets l'adresse de r0
	subs r1,r1,#1	@ la boucle fait 128 tours
	bne reset_sprites_loop

	ldr r1,=REG_DISPCNT
	ldr r2,=(MODE_0|BG2_ENABLE|OBJ_ENABLE|OBJ_MAP_1D)
	str r2,[r1]

	ldr r0,=OAM	@ on va s'occuper de charger nos sprites
	ldr r1,=(SQUARE|COLOR_16|PADDLE_Y)|((SIZE_8|PADDLE_X)<<16)	@ cf l'organisation des attributs des sprites (là on règle les deux premiers)
	mov r2,#0	@ premier tile de 8*8 pixels du sprite (index du sprite dans le CHARMEM quoi)
	str r1,[r0],#4	@ on charge les deux premiers attributs, puis on les "saute"
	str r2,[r0],#4	@ on charge le troisième attribut
	ldr r1,=(SQUARE|COLOR_16|PADDLE_Y)|((SIZE_8|PADDLE_X+8)<<16)
	mov r2,#1
	str r1,[r0],#4
	str r2,[r0],#4
	ldr r1,=(SQUARE|COLOR_16|PADDLE_Y)|((SIZE_8|PADDLE_X+16)<<16)
	mov r2,#2
	str r1,[r0],#4
	str r2,[r0],#4
	ldr r1,=(SQUARE|COLOR_16|BALL_Y)|((SIZE_8|BALL_X)<<16)
	mov r2,#3	@ quatrième tile
	str r1,[r0],#4
	str r2,[r0],#4

	ldr r1,=OBJPAL	@ on s'occupe de la palette maintenant
	ldr r2,=5	@ nombre de couleurs de la palette à copier
	ldr r3,=palette

palette_loop:
	ldr r7,[r3],#4	@ on charge la valeur à l'adresse de r3 dans r7, puis on incrémente de 4 octets (16 bits = 1 couleur) l'adresse de r3
	str r7,[r1],#4	@ on colle le tout dans r1 puis incrémente de même r1
	subs r2,r2,#1	@ on fait 5 tours
	bne palette_loop

	ldr r1,=CHARMEM	@ au tour des sprites
	ldr r2,=8*8*4	@ tailles des sprites et nombre
	ldr r3,=paddle_left

sprite_loop:
	ldr r7,[r3],#4	@ la même qu'au dessus
	str r7,[r1],#4
	subs r2,r2,#1
	bne sprite_loop

main_loop:
	mov r3,#KEYS_HIGH	@ MSB
	orr r3,r3,#KEYS_LOW	@ ajouter LSB de l'adresse (plus rapide que ldr r3,#KEYS)
	mov r2,#0x300
	orr r2,#0xFF	@ r2 = $3FF (10 touches codés sur 10 bits)
	ldr r4,[r3]	@ r4 = touche pressée

	ldr r0,=player_x
	tst r4, #KEY_LEFT
	bleq left
	tst r4, #KEY_RIGHT
	bleq right

	ldr r6,=REG_VCOUNT
waitVBlank:
	ldrb r7,[r6]
	cmp r7,#161
	bne waitVBlank

	ldrb r0,[r0]	@ on charge un octet de l'adresse r0 dans r0
	ldr r3,=OAM+2	@ deuxième attribut (=OAM+2 octets), X=1er octet+1er bit suivant
	ldrh r4,[r3]
	and r4,r4,#0xFE00	@ on récupère donc les 9 premiers bits
	add r4,r0
	strh r4,[r3]
	add r4,#8	@ on s'occupe de la deuxième partie de la raquette (centre)
	strh r4,[r3, #8]	@ on colle le tout dans l'emplacement suivant (8 octets après)
	add r4,#8	@ idem avec la troisième partie
	strh r4,[r3, #16]

	bl handle_ball	@ on s'occupe de la balle

	mov r0,#0x100	@ pour ralentir le programme
delay_loop:
	subs r0,r0,#1
	bne delay_loop
 	b main_loop

left:
	ldrb r2,[r0]
	subs r2,r2,#1
	bxcc lr	@ on quitte si le carry flag est set (donc le résultat du dessus inférieur à 0)
	strb r2,[r0]	@ sauver les nouvelles coordonnées (1 octet)
	bx lr	@ quitter la routine

right:
	ldrb r2,[r0]
	add r2,r2,#1
	cmp r2,#SCREEN_W-(8*3)	@ on test voir si ça sort de l'écran
	bxcs lr	@ on quitte si le sign flag est mis
	strb r2,[r0]
	bx lr

handle_ball:	@ le code suivant doit incrémenter ou décrementer X et Y en fonction de la direction de la balle (gère les rebonds), mais ça bug :/
@ r0 = nouveau valeur de ball_x
@ r2 = ball_x (ptr)
@ r3 = ball_vel_x (ptr)
@ r4 = ball_vel_x (valeur)
	ldr r2,=ball_x
	ldrb r0,[r2]
	ldr r3,=ball_velocity_x
	ldrb r4,[r3]
	add r0,r0,r4			@ ball_x + ball_vel
	and r0,r0,#0xFF			@ si le résultat est plus de 8 bits
	stmfd sp!,{lr}			@ pour faire des appels imbriqués
@		blcc change_ball_velocity
		cmp r0,#SCREEN_W-8
		blcs change_ball_velocity
	ldmfd sp!,{lr}
	strb r0,[r2]
	ldr r2,=ball_y
	ldrb r1,[r2]
	ldr r3,=ball_velocity_y
	ldr r4,[r3]
	add r1,r1,r4
	and r1,r1,#0xFF
	stmfd sp!,{lr}
@		blcc change_ball_velocity
		cmp r1,#SCREEN_H-8
		blcs change_ball_velocity
	ldmfd sp!,{lr}
	strb r1,[r2]	
	ldr r3,=OAM+3*8
	ldrh r4,[r3]
	ldrh r5,[r3,#2]
	and r4,r4,#0xFF00
	add r4,r1
	strh r4,[r3],#2
	and r5,r5,#0xFE00
	add r5,r0
	strh r5,[r3]
	bx lr

change_ball_velocity:
	eor r4,#0xFF
	add r4,#1
	strb r4,[r3]
	bx lr

.ltorg

palette:
	.hword 0x0000,0x001F,0x56B5,0x7FFF

.align 4	@ peut être inutile maintenant ?

paddle_left:
	.word 0x00000000
	.word 0x22011000
	.word 0x22011130
	.word 0x33033133
	.word 0x22011333
	.word 0x22011133
	.word 0x22011130
	.word 0x22011000

paddle_center:
	.word 0x00000000
	.word 0x22222222
	.word 0x22222222
	.word 0x33333333
	.word 0x22222222
	.word 0x22222222
	.word 0x22222222
	.word 0x22222222

paddle_right:
	.word 0x00000000
	.word 0x00011022
	.word 0x03111022
	.word 0x33133033
	.word 0x33311022
	.word 0x33111022
	.word 0x03111022
	.word 0x00011022

ball:
	.word 0x00003330
	.word 0x00033333
	.word 0x00033333
	.word 0x00033333
	.word 0x00003330
	.word 0x00000000
	.word 0x00000000
	.word 0x00000000

.data	@ ne faudrait-il pas que je le mette avant les sprites ?

player_x:
	.byte PADDLE_X

ball_x:
	.byte BALL_X

ball_y:
	.byte BALL_Y

ball_velocity_x:
	.byte 1
ball_velocity_y:
	.byte 1

EDIT : En effet, le carry agit différemment pour les instructions add et sub/cmp. Pour les add c'est normal, pour les sub/cmp, z80 c = cc (carry clear) et nc = cs (carry set), c'est le contraire de ce que l'on penserait... c'est bizarre.