Revenir au plan du site

Un programme "Télécran", source complet et correction de l'affichage ;)

Voici le source complet de nos assemblages (spoiler : il manque encore quelque chose mais c'est fonctionnel)
BUILDSNA : BANKSET 0
ORG #100 : RUN #100

;======================================
EffaceEcran
;======================================
ld hl,#C000
xor a ; A=0
.loop
ld (hl),a ; écrire #00 à l'adresse pointée par HL
inc l ; incrémenter seulement L positionne le flag Z une fois revenu à zéro
jr nz,.loop ; on boucle donc tant que L est différent de zéro
inc h ; même chose pour H, sauf que nous savons ici que L vaut zéro
jr nz,.loop ; tant que H ne vaut pas zéro on reboucle
; ici nous avons HL=#0000 nous sommes revenus au début de la mémoire, l'écran est effacer, on s'arrête

; initialiser les coordonnées de notre point
ld hl,160 : ld (positionx),hl
ld hl,100 : ld (positiony),hl

;======================================
AfficherPoint
;======================================
ld bc,(positionx)
ld hl,(positiony)
call CalculeAdressePixel
ld (hl),c ; écrire le pixel à l'écran

;======================================
LireLeClavier
;======================================
call lectureMatriceClavier

OCTET_CURSEUR_HAUT equ matriceClavier : BIT_CURSEUR_HAUT equ 1
OCTET_CURSEUR_DROITE equ matriceClavier : BIT_CURSEUR_DROITE equ 2
OCTET_CURSEUR_BAS equ matriceClavier : BIT_CURSEUR_BAS equ 4
OCTET_CURSEUR_GAUCHE equ matriceClavier+1 : BIT_CURSEUR_GAUCHE equ 1
OCTET_TOUCHE_ESPACE equ matriceClavier+5 : BIT_TOUCHE_ESPACE equ 128

; si on appuie sur Espace, on revient à l'effacement de l'écran
ld a,(OCTET_TOUCHE_ESPACE) : and BIT_TOUCHE_ESPACE : jp z,EffaceEcran

; touches du curseur
ld a,(OCTET_CURSEUR_HAUT) : and BIT_CURSEUR_HAUT : jp z,gererHaut
ld a,(OCTET_CURSEUR_BAS) : and BIT_CURSEUR_BAS : jp z,gererBas
ld a,(OCTET_CURSEUR_DROITE) : and BIT_CURSEUR_DROITE : jp z,gererDroite
ld a,(OCTET_CURSEUR_GAUCHE) : and BIT_CURSEUR_GAUCHE : jp z,gererGauche
;
jp LireLeClavier ; ni espace, ni curseur, on continue de lire le clavier
;======================================
; sous-routines de gestion des touches
;======================================
gererHaut
ld hl,(positiony)
ld a,h : or l : jp z,LireLeClavier ; si le Y vaut zéro on est déjà en haut de l'écran
dec hl ; on n'est pas en haut alors on décrémente
ld (positiony),hl ; et on valide la nouvelle coordonnée
jp AfficherPoint ; on remonte afficher le point
;
gererGauche
ld hl,(positionx)
ld a,h : or l : jp z,LireLeClavier
dec hl
ld (positionx),hl
jp AfficherPoint
;
gererBas
ld hl,(positiony)
ld a,l : cp 199 : jp z,LireLeClavier ; si le Y vaut 199 on est déjà en bas de l'écran
inc hl ; on peut incrémenter
ld (positiony),hl ; et on valide la nouvelle coordonnée
jp AfficherPoint ; on remonte afficher le point
gererDroite
ld hl,(positionx)
ld a,l : cp lo(319) : jr nz,.okDroite
ld a,h : cp hi(319) : jp z,LireLeClavier
.okDroite
inc hl
ld (positionx),hl
jp AfficherPoint
;======================================
CalculeAdressePixel
;======================================
; BC=coordonnée X (0-319)
; HL=coordonnée Y (0-199)
ld de,tableau
add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2
add hl,de
ld a,(hl) : inc hl
ld h,(hl) : ld l,a
; HL=adresse de la ligne
ld a,c ; on sauvegarde le X avant de diviser par 4
srl bc : srl bc ; diviser le X par 4 pour avoir l'octet en mode 1
add hl,bc
ld c,%10000000 ; encre 1 pour le pixel mode 1 le plus à gauche dans l'octet
and 3 ; avec le modulo 4 on va savoir quel est le pixel en partant de la gauche
jr z,.noShift
.Shift
srl c
dec a
jr nz,.Shift
.noShift
ret ; HL=adresse écran aux coordonnées X/Y données et C est le pixel d'encre 1
;-------------------
adresse_ecran=#C000
largeur_ecran=80
tableau
repeat 25
repeat 8
defw adresse_ecran
adresse_ecran+=#800
rend
adresse_ecran+=largeur_ecran
adresse_ecran-=#4000
rend
;======================================
lectureMatriceClavier
;======================================
ld hl,matriceClavier
ld bc,#f782
out (c),c
ld bc,#f40e
ld e,b
out (c),c
ld bc,#f6c0
ld d,b
out (c),c
out (c),0
ld bc,#f792
out (c),c
ld a,#40
ld c,d
.loop ld b,d
out (c),a ; sélectionner la ligne
ld b,e
ini ; lire et stocker dans notre tableau
inc a
inc c
jr nz,.loop
ret

matriceClavier defs 10,#FF
;=================================================
; en fin du programme, nos coordonnées sur 16 bits
;=================================================
positionx defw 0
positiony defw 0


Vous lancez le programme et là, deux problèmes majeurs : 1/ Ça va trop vite, vous programmez trop bien.
2/ Comme il y a 4 points par octet, afficher un point en efface jusqu'à 3 autres.

Ralentir le programme, on sait faire, on va ajouter deux ou trois attentes de VBL.

Pour le masquage écran, nous allons lire la valeur à l'adresse destination pointée par HL, la fusionner à notre point avec un OR et enfin l'écrire.

; au lieu de
ld (hl),c
; il faudra faire
ld a,(hl) ; copier l'octet de l'écran dans A
or c ; fusionner avec le nouveau pixel
ld (hl),a ; écrire le nouvel octet

Et voici le source complet ET corrigé ^_^
BUILDSNA : BANKSET 0
ORG #100 : RUN #100

;======================================
EffaceEcran
;======================================
ld hl,#C000
xor a ; A=0
.loop
ld (hl),a ; écrire #00 à l'adresse pointée par HL
inc l ; incrémenter seulement L positionne le flag Z une fois revenu à zéro
jr nz,.loop ; on boucle donc tant que L est différent de zéro
inc h ; même chose pour H, sauf que nous savons ici que L vaut zéro
jr nz,.loop ; tant que H ne vaut pas zéro on reboucle
; ici nous avons HL=#0000 nous sommes revenus au début de la mémoire, l'écran est effacer, on s'arrête

; initialiser les coordonnées de notre point
ld hl,160 : ld (positionx),hl
ld hl,100 : ld (positiony),hl

;======================================
AfficherPoint
;======================================
ld bc,(positionx)
ld hl,(positiony)
call CalculeAdressePixel
ld a,(hl) : or c : ld (hl),a ; fusionner le pixel à l'écran

call waitVBLstart ; 50Hz
call waitVBLstart ; 25Hz
call waitVBLstart ; 17Hz
call waitVBLstart ; 12Hz nous afficherons 12 pixels par seconde

;======================================
LireLeClavier
;======================================
call lectureMatriceClavier

OCTET_CURSEUR_HAUT equ matriceClavier : BIT_CURSEUR_HAUT equ 1
OCTET_CURSEUR_DROITE equ matriceClavier : BIT_CURSEUR_DROITE equ 2
OCTET_CURSEUR_BAS equ matriceClavier : BIT_CURSEUR_BAS equ 4
OCTET_CURSEUR_GAUCHE equ matriceClavier+1 : BIT_CURSEUR_GAUCHE equ 1
OCTET_TOUCHE_ESPACE equ matriceClavier+5 : BIT_TOUCHE_ESPACE equ 128

; si on appuie sur Espace, on revient à l'effacement de l'écran
ld a,(OCTET_TOUCHE_ESPACE) : and BIT_TOUCHE_ESPACE : jp z,EffaceEcran

; touches du curseur
ld a,(OCTET_CURSEUR_HAUT) : and BIT_CURSEUR_HAUT : jp z,gererHaut
ld a,(OCTET_CURSEUR_BAS) : and BIT_CURSEUR_BAS : jp z,gererBas
ld a,(OCTET_CURSEUR_DROITE) : and BIT_CURSEUR_DROITE : jp z,gererDroite
ld a,(OCTET_CURSEUR_GAUCHE) : and BIT_CURSEUR_GAUCHE : jp z,gererGauche
;
jp LireLeClavier ; ni espace, ni curseur, on continue de lire le clavier
;======================================
; sous-routines de gestion des touches
;======================================
gererHaut
ld hl,(positiony)
ld a,h : or l : jp z,LireLeClavier ; si le Y vaut zéro on est déjà en haut de l'écran
dec hl ; on n'est pas en haut alors on décrémente
ld (positiony),hl ; et on valide la nouvelle coordonnée
jp AfficherPoint ; on remonte afficher le point
;
gererGauche
ld hl,(positionx)
ld a,h : or l : jp z,LireLeClavier
dec hl
ld (positionx),hl
jp AfficherPoint
;
gererBas
ld hl,(positiony)
ld a,l : cp 199 : jp z,LireLeClavier ; si le Y vaut 199 on est déjà en bas de l'écran
inc hl ; on peut incrémenter
ld (positiony),hl ; et on valide la nouvelle coordonnée
jp AfficherPoint ; on remonte afficher le point
gererDroite
ld hl,(positionx)
ld a,l : cp lo(319) : jr nz,.okDroite
ld a,h : cp hi(319) : jp z,LireLeClavier
.okDroite
inc hl
ld (positionx),hl
jp AfficherPoint
;======================================
CalculeAdressePixel
;======================================
; BC=coordonnée X (0-319)
; HL=coordonnée Y (0-199)
ld de,tableau
add hl,hl ; adresses 16 bits, il faut indexer de 2 en 2
add hl,de
ld a,(hl) : inc hl
ld h,(hl) : ld l,a
; HL=adresse de la ligne
ld a,c ; on sauvegarde le X avant de diviser par 4
srl bc : srl bc ; diviser le X par 4 pour avoir l'octet en mode 1
add hl,bc
ld c,%10000000 ; encre 1 pour le pixel mode 1 le plus à gauche dans l'octet
and 3 ; avec le modulo 4 on va savoir quel est le pixel en partant de la gauche
jr z,.noShift
.Shift
srl c
dec a
jr nz,.Shift
.noShift
ret ; HL=adresse écran aux coordonnées X/Y données et C est le pixel d'encre 1
;-------------------
adresse_ecran=#C000
largeur_ecran=80
tableau
repeat 25
repeat 8
defw adresse_ecran
adresse_ecran+=#800
rend
adresse_ecran+=largeur_ecran
adresse_ecran-=#4000
rend
;==============
waitVBLstart
;==============
ld b,#F5
.loop in a,(c) : rra : jr c,.loop ; attendre l'absence de VBL
;==============
waitVBL
;==============
ld b,#F5
.loop in a,(c) : rra : jr nc,.loop ; attendre la VBL
ret
;======================================
lectureMatriceClavier
;======================================
ld hl,matriceClavier
ld bc,#f782
out (c),c
ld bc,#f40e
ld e,b
out (c),c
ld bc,#f6c0
ld d,b
out (c),c
out (c),0
ld bc,#f792
out (c),c
ld a,#40
ld c,d
.loop ld b,d
out (c),a ; sélectionner la ligne
ld b,e
ini ; lire et stocker dans notre tableau
inc a
inc c
jr nz,.loop
ret

matriceClavier defs 10,#FF
;=================================================
; en fin du programme, nos coordonnées sur 16 bits
;=================================================
positionx defw 0
positiony defw 0