Obligement - L'Amiga au maximum

Samedi 20 avril 2024 - 00:19  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in english


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Assembleur - Ouverture d'un écran
(Article écrit par Philippe Rivaillon et extrait d'Amiga News Tech - avril 1992)


C'est dans le domaine de la vidéo que l'Amiga terrasse la plupart des autres machines de même catégorie, avec ses 4096 couleurs qu'il peut à l'occasion afficher simultanément...

Les derniers modèles, l'A3000 et l'A500 Plus, disposent encore de nouveaux modes : le Super-Hires avec 1280 pixels horizontaux sur un moniteur standard et quatre couleurs parmi 64, et le mode Productivity sur écran multisynchro, qui affiche une résolution de 640x480 en 4 couleurs. Ces deux modes peuvent être utilisés en entrelacé, ce qui multiplie par deux la résolution verticale (respectivement 1280x400 et 640x960). Enfin, un dernier mode nommé A2024 10 ou 15 Hz permet d'afficher 1008x800 points en 4 niveaux de gris, mais uniquement sur un moniteur monochrome type A2024 ou Viking.

C'est bien d'avoir beaucoup de modes graphiques à disposition, mais encore faudrait-il savoir les utiliser... C'est pourquoi, dans cette première partie, nous allons nous intéresser à tout ce qui concerne l'écran graphique. Let's go...

C'est quoi, un plan de bits ?

Cette partie est bien entendu réservée aux débutants : les autres, allez voir au prochain paragraphe si j'y suis...

Le spot (le faisceau d'électrons qui "dessine" continuellement l'image) de votre moniteur ou téléviseur parcourt l'écran de gauche à droite et de haut en bas. De ce fait, l'écran à afficher (contenu en mémoire) sera décomposé en lignes débutant par les données à afficher les plus à gauche. La résolution verticale décrit le nombre de lignes visibles à l'écran : 200 en mode normal et 400 en mode entrelacé. En vous approchant de votre écran, vous apercevrez nettement que celui-ci est décomposé en une multitude de points lumineux, appelés "pixels" (contraction de l'anglais "picture" et de "element", soit littéralement "élément d'image"). Le nombre de pixels sur une ligne représente la résolution horizontale : 320 en basse résolution et 640 en haute résolution.

Dans le cas d'un écran monochrome (deux couleurs), chaque pixel est représenté en mémoire par un bit : si le bit est à 1, le pixel est "allumé", et s'il est à 0, le pixel est "éteint". On a bien deux possibilités, donc deux couleurs. Une ligne de 320 pixels de large sera donc représentée en mémoire par 40 octets de données (40 octets fois 8 bits=320 bits=320 pixels). Pour un écran de 200 lignes, il faudra donc 40 fois 200, c'est-à-dire 8000 octets. L'ensemble de tous ces bits représente ce que l'on appelle un "plan de bits", ou plus simplement "bitplan" (de l'anglais bit plane).

Et pour la couleur, me demanderez-vous ? C'est aussi simple : au lieu d'utiliser un seul plan de bits, on en utilise plusieurs en observant la règle suivante : nombre de couleurs = 2^nombre de plan de bits.

Suivez sur la figure suivante : en prenant le premier bit de chaque plan de bits, on obtiendra le numéro de la couleur du premier pixel de l'écran, et ainsi de suite pour tous les autres pixels.

Assembleur

Maintenant, on va pouvoir passer aux choses sérieuses.

Écran, ouvre-toi !

Pour simplifier les choses, nous n'évoquerons ici que le mode basse résolution non entrelacée (320x200) et haute résolution non entrelacée (640x200). Les autres modes seront traités plus tard. Notons que la procédure d'ouverture d'un écran est exactement la même pour les modes graphiques.

Pour ouvrir un écran, il faut d'abord choisir la résolution en connaissance de cause :
  • LoRes : 320 pixels par ligne, 32 couleurs maximum.
  • HiRes : 640 pixels par ligne, 16 couleurs maximum.
Ensuite, il faut définir le nombre de couleurs voulues, en fixant le nombre de plans de bits selon la formule vue plus haut. Notons que l'Amiga n'autorise que cinq plans de bits au maximum (2^5=32 couleurs), mais que certains modes particuliers (HAM et Extra Halfbrite) requièrent un sixième plan de bits.

Pour rendre ces choix effectifs, il suffit d'initialiser correctement le registre suivant :

BPLCON0 $DFF100 Premier registre de contrôle des plans de bits

Bit Nom Fonction
15 HIRES Si ce bit est mis, l'affichage se
fait en haute résolution (640 colonnes)
14-12 BPU2-0 Forment un nombre 3 bits indiquant
le nombre de plans de bits utilisés. Avec 0
plan de bits, seule la couleur de fond est affichée

Notes : ce registre n'est accessible qu'en écriture. Seuls les 4 derniers bits nous intéressent pour l'instant ; les autres doivent impérativement rester à 0.

Après avoir choisi la résolution et le nombre de plans de bits, il faut définir les couleurs. Leur codage est du type RVB (Rouge, Vert, Bleu) : pour obtenir la couleur voulue, il faut effectuer des mélanges de teintes rouges, vertes et bleues. Chaque composante est codée sur 4 bits, ce qui autorise 16 intensités par composante (de $0 à $1), donc 16x16x16=4096 couleurs, du noir complet ($000) au blanc le plus pimpant ($fff).

Les couleurs définies seront rangées dans les registres suivants :

COLORx $DFF180+2*x Registre de couleur numéro x

Bit Nom Fonction
15-12 - Inutilisés (mettre à 0)
11-8 R3-R0 Composante rouge
7-4 G3-G0 Composante verte
3-0 B3-B0 Composante bleue

Notes : ces registres ne sont accessibles qu'en écriture. Il y a 32 registres de couleurs, de $DFF180 (COLOR00) à $DFF1BE (COLOR31). La couleur 0 représente la couleur du fond de l'écran.

Écran, ouvre-toi ! (bis)

Les choix effectués jusqu'ici étaient purement esthétiques. Il faudrait maintenant peut-être penser à s'occuper de l'affichage, non ? La prochaine étape consiste donc à définir la largeur, la hauteur et la position de notre écran. Attention, cela n'a rien à voir avec la résolution : on peut très bien avoir un écran de 256 points de large sur 123 lignes, avec une résolution de 640x200. Il s'agit simplement de fixer les limites de l'écran visible sur le moniteur (en dehors de cette limite, seule la couleur de fond sera affichée. J'insiste sur ce fait : n'espérez pas afficher un sprite en dehors de l'écran visible !).

DIWSTRT $DFF08E Position du coin haut gauche de l'écran

Bit Nom Fonction
15-8 VSTART(7-0) Position verticale de départ
7-0 HSTART(7-0) Position horizontale de départ

Remarque : le fait que chaque coordonnée soit exprimée sur 8 bits limite la position du coin supérieur gauche de l'écran visible à l'intérieur des 256 lignes de balayage supérieures et des 256 points de résolution les plus à gauche.

DIWSTOP $DFF090 Position du coin bas droit de l'écran

Bit Nom Fonction
15-8 VSTOP(7-0) Position verticale de fin
7-0 HSTOP(7-0) Position horizontale de fin

Pour mieux comprendre le fonctionnement de ce registre, nous allons faire apparaître un neuvième bit imaginaire pour chaque coordonnée, que nous appellerons VSTOP8 et HSTOP8 : la valeur de HSTOP est toujours ajoutée à $100 (HSTOP8 toujours à 1) ; son minimum est donc de 256 et son maximum, de 511. Pour VSTOP, les choses se compliquent un petit peu : VSTOP8 est toujours égal au complément de VSTOP7. Pour fixer VSTOP, il suffit donc de choisir un Y compris entre 128 et 383 (exprimé sur 9 bits) et de mettre les 8 bits inférieurs dans VSTOP (en effet, à cette fourchette de valeurs correspond des bits 8 et 9 différents. L'un est donc le complément de l'autre).

Notes : ces registres ne sont accessibles qu'en écriture. Les positions sont toujours spécifiées en basse résolution non entrelacée, quelle que soit la résolution effectivement choisie avec BPLCON0.

Attention, la première ligne de balayage visible n'est pas la numéro 0. Il faut en effet tenir compte de la zone dite "Vertical Blank" (temps mort vertical). De même pour la première colonne, car le spot a besoin d'un court temps de répit après l'affichage de chaque ligne. Ainsi, les valeurs normales pour centrer un écran de 320x200 pixels sont DIWSTRT=$2C81 et DIWSTOP=$F4C1.

De plus, si vous voulez faire du suraffichage (overscan), il est inutile de mettre des valeurs dépassant l'écran physique : vous ne verriez rien de plus et utiliseriez plus de temps machine (sans compter que le spot n'aura peut-être plus le temps de satisfaire vos demandes...). Des valeurs de $2069 pour DIWSTRT et $29C9 pour DIWSTOP centrent un écran en suraffichage de 352x265 pixels.

DDFSTRT $DFF092 Dèbut chercher plan de bits (horizontalement)
DDFSTOP $DFF094 Fin chercher plan de bits (horizontalement)

Bit Fonction
15-8 Inutilisées (mettre à 0)
7-2 Codage de début ou de fin de transfert
1-0 Spécial : mettre à 0 (voir ci-dessous)

Pourquoi les bits 0 et 1 doivent-ils rester nuls ? Tout simplement parce que la précision de ces registres est de 4 unités (tout comme pour un Wait Copper, mais contrairement à celui-ci, les deux derniers bits de codage existent tout de même... et doivent rester à 0. Peut-être les constructeurs avaient-ils envisagé une amélioration ultérieure du matériel amenant à une précision supérieure). La comparaison avec un Wait Copper s'arrête ici, car ces registres décrivent un intervalle de temps en termes de cycles DMA, ils indiquent respectivement quand l'Amiga doit commencer et interrompre le transfert des données vidéos vers l'écran.

Initialisons le premier registre. Pour cela, il faut utiliser VSTART (initialisé dans le registre DIWSTRT) que l'on transformera en nombre de cycles. Notons qu'il faut multiplier VSTART par 2 si l'on travaille en haute résolution, car il est toujours décrit en basse résolution.

En basse résolution, le matériel a besoin de 8 cycles DMA pour transférer un mot de données (16 points) depuis la mémoire vers l'écran, alors qu'il ne lui en faut que 4 en haute résolution. Un rapide calcul nous permet donc de dire qu'il suffit de diviser VSTART par deux pour avoir le nombre de cycles, quelle que soit la résolution. De plus, il faut un peu de temps à l'Amiga avant d'afficher chaque ligne (il prend son élan !). En conséquence, il faut retrancher à DDFSTRT, 4,5 points en basse résolution et 8,5 points en haute résolution pour tenir compte de ce temps de repos (ça va, la digestion ?). Évidemment, le matériel ne travaillant qu'avec des nombres entiers, le résultat sera arrondi. Allez, ne crisez pas, je vous envoie la formule.
  • Basse résolution : DDFSTRT=(VSTART/2-8.5)
  • Haute résolution : DDFSTRT=(VSTART/2-4.5)
DDFSTOP se déduit tout bêtement de ce résultat :
  • Basse résolution : DDFSToP=DDFSTRT+(8*(mots par ligne -1))
  • Haute résolution : DDFSTOP=DDFSTRT+(4*(mots par ligne -2))
Ici, 8 et 4 représentent bien entendu les nombres de cycles nécessités pour transférer un mot. L'utilité des décalages (-1 et -2) est restée pour moi très mystérieuse (ce doit être inhérent au travail interne de l'Amiga). Quelques exemples finiront d'éclaircir tout ça. Par exemple pour un écran de 320x200 (DIWSTRT=$2C81, DIWSTOP=$F4C1) :
  • Basse résolution : DDFSTRT=$0038, DDFSTOP=$00D0
  • Haute résolution : DDFSTRT=$003C, DDFSTOP=$00D4
(les deux derniers bits sont nuls)

Notes : ces registres ne sont accessibles qu'en écriture. Pour ces deux registres, il faut noter qu'il y a des valeurs extrêmes à ne pas dépasser, sous peine d'avoir quelques mauvaises surprises à l'affichage. Évitez de mettre des valeurs inférieures à $28 pour DDFSTRT et supérieures à $D8 pour DDFSTOP. Mais cela suffit amplement pour faire du plein écran, comme vous le verrez dans l'exemple.

Écran... ouvre-toi ! (ter)

Il va maintenant falloir s'occuper des plans de bits en mémoire. Nous avons deux choses à préciser à l'Amiga : l'adresse de chaque plan de bits et la valeur à ajouter à la fin de chaque lecture de ligne au pointeur d'écran concerné (ce qu'on appelle le modulo).

BPLxPTH $DFF0yy Adresse du plan de bits x (poids fort)
BPLxPTL $DFF0zz Adresse du plan de bits x (poids faible)

(avec x, numéro du plan de bits (de 1 à 6), yy=$E0+((x-1)*4) et zz=yy+2)

Le plan de bits numéro 6 ne sera initialisé que dans des conditions bien particulières, qui seront vues plus tard. Notons que les plans de bits, comme toutes les données utilisées par le DMA, doivent se trouver en mémoire Chip. En conséquence, l'adresse des plans de bits est codée sur 19, 20 ou 21 bits suivant le modèle d'Amiga.

Attention au contenu de ces registres, il est incrémenté en permanence (ce sont des pointeurs, au sens propre du terme). Toute modification "en cours de route" sera directement visible à l'écran. De plus, il ne faudra pas oublier de les réinitialiser à chaque retour du spot ("blanking") car Agnus ne s'en charge pas toute seule. Généralement, cette tâche incombe au Copper, car il est toujours synchronisé avec l'écran (c'est d'ailleurs plus pratique).

Notes : ces registres ne sont accessibles qu'en écriture. Les transferts mémoire -> écran s'effectuent mot par mot. De ce fait, les pointeurs doivent toujours contenir une adresse paire.

BPL1MOD $DFF108 Modulo des plans impairs
BPL2MOD $DFF10A Modulo des plans pairs

Lorsque le matériel a fini de transmettre une ligne de données, il ajoute ces valeurs, exprimées en octets, aux pointeurs de plans de bits décrits ci-dessus. Cela permet, entre autres, de gérer des plans de bits plus larges que la partie effectivement visible sur le moniteur et de les faire défiler très facilement (à la Kick Off, par exemple).

Notes : ces registres ne sont accessibles qu'en écriture. Ils doivent contenir des nombres pairs, puisqu'ils sont ajoutés aux pointeurs plans de bits, qui doivent eux-mêmes être pairs.

Il ne reste maintenant plus qu'à réserver la mémoire suffisante (nb_plans_de_bits*largeur en octets*nb_lignes) et à organiser les plans de bits de la manière que vous voulez :
  • type "normal" : les plans de bits se situent les uns après les autres en mémoire, et sont chacun en un seul bloc (pointeur au début de chaque plan de bits, modulo initialisé comme décrit plus haut).

  • type iff : ceci fait bien entendu référence au format des fichiers graphiques du même nom. Les plans de bits s'enchevêtrent les uns dans les autres en mémoire ; on trouve d'abord la première ligne du premier plan de bits, puis la première du second, puis du troisième, etc., et on recommence de la même manière pour chacune de autres lignes. L'avantage d'un tel format, qui peut paraître rébarbatif au premier abord, est de permettre d'agir sur tous les plans de bits en un seul transfert Blitter.
Prenons l'exemple d'un BOB : dans le premier cas (type "normal"), il faudra autant de transferts que de plans de bits alors que dans le second cas (type iff), un seul transfert Blitter suffira, puisque les lignes des différents plans de bits se suivent. Bien entendu, il faut que les BOB soient stockés en mémoire dans le même format. On peut faire plus de choses en attendant la fin de cet unique transfert et ça va plus vite de toute manière (il n'y a pas à réinitialiser plusieurs fois le Blitter).

Pour utiliser ce mode, il faut initialiser chaque pointeur plan de bits sur sa première ligne, calculer les modulos comme décrit plus haut et y ajouter (nb_plans_de_bits-1)*(largeur plan de bits en octets).

Bon, allez on a presque fini, il ne reste plus qu'à lancer l'affichage. Pour cela, il suffit d'initialiser DMACON convenablement (bits 9 et 8 au minimum, bit 7 pour utiliser le Copper, bit 5 pour les sprites).

Et voilà, il ne me reste plus qu'à vous proposer un petit exemple. Notez que je mets la plupart des informations dans la liste Copper : ce n'est pas nécessaire, mais simplement plus pratique. Seuls les pointeurs d'adresses doivent obligatoirement y figurer, pour les raisons citées plus haut.

*****************************
* Exemple tiré de l'article *
*  l'Amiga artiste peintre  *
*                           *
* Par Rivaillon Philippe    *
* Programme sur SEKA V3.2   *
*****************************
*
* Appuyez sur le bouton gauche puis le droit
*

START:
	bsr	SAVE_ALL
; TYPE BITMAP
; Initialisation des pointeurs de plans de bits dans la liste Copper

	move.l	#ECRAN,d1
	move.w	d1,PLAN1+6	; 16 bits bas
	swap	d1
	move.w	d1,PLAN1+2	; 3 bits hauts
	swap	d1

	add.l	#1024*265/8,d1	; Pointe sur 2ème plan de bits

	move.w	d1,PLAN2+6
	swap	d1
	move.w	d1,PLAN2+2

	move.w	#%0000000000100000,$dff096	; vire sprites
; Autorisation copper et affichage
	move.w	#%1000001110000000,$dff096

; On lance la liste Copper
	move.l	#COPPERLIST,$DFF080	; adresse
	move.w	#$0,$DFF088		; redémarrage du Copper

wait1:
	btst	#6,$bfe001
	bne.s	wait1

; TYPE IFF
; Initialisation des pointeurs de plans de bits dans la liste Copper

	move.l	#ECRAN,d1
	move.w	d1,PLAN1_2+6	; 16 bits bas
	swap	d1
	move.w	d1,PLAN1_2+2	; 3 bits hauts
	swap	d1

	add.l	#1024/8,d1	; Pointe sur 2ème plan de bits

	move.w	d1,PLAN2_2+6
	swap	d1
	move.w	d1,PLAN2_2+2

	move.w	#%0000000000100000,$dff096	; vire sprites
; Autorisation copper et affichage
	move.w	#%1000001110000000,$dff096

; On lance la liste Copper
	move.l	#COPPERLIST2,$DFF080	; adresse
	move.w	#$0,$DFF088		; redémarrage du Copper

wait2:
	btst	#2,$dff016
	bne.s	wait2

	bsr	RESTORE_ALL
	rts

save_all:
	move.b	#%10000111,$bfd100
	move.l	4,a6
	jsr	-132(a6)

	move.l	$6c,save_vecteur_irq
	move.w	$dff01c,save_intena
	or.w	#$c000,save_intena
	move.w	$dff002,save_dmacon
	or.w	#$8100,save_dmacon
	move.w	#$7fff,$dff096
	move.w	#$7fff,$dff09a
	move.w	#%1000011111000000,$dff096
	move.w	#%1100000000100000,$dff09a
	rts

restore_all:
	move.l	save_vecteur_irq,$6c
	move.w	#$7fff,$dff09a
	move.w	save_intena,$dff09a
	move.w	#$7fff,$dff096
	move.w	save_dmacon,$dff096
	move.l	4,a6
	lea	name_glib,a1
	moveq	#0,d0
	jsr	-552(a6)
	move.l	d0,a0
	move.l	38(a0),$dff080
	clr.w	$dff088
	move.l	d0,a1
	jsr	-414(a6)
	jsr	-138(a6)
	rts
save_intena:dc.w 0
save_dmacon:dc.w 0
save_vecteur_irq:dc.l 0
name_glib:dc.b 'graphics.library',0
even

COPPERLIST:
	dc.w	$0100,$A200	; résolution, nb plan de bits
	dc.w	$0180,$0000	; couleur 0
	dc.w	$0182,$0f00	; couleur 1
	dc.w	$0184,$00f0	; couleur 2
	dc.w	$0186,$000f	; couleur 3

	dc.w	$008e,$2069	; DIWSTRT
	dc.w	$0090,$29c9	; DIWSTOP
	dc.w	$0092,$0030	; DDFSTRT
	dc.w	$0094,$00D8	; DDFSTOP

	dc.w	$0108,$0028	; modulo plans impaires
	dc.w	$010a,$0028	; modulo plans paires

PLAN1:
	dc.w	$00e0,$0000	; plan de bits 1
	dc.w	$00e2,$0000
PLAN2:
	dc.w	$00e4,$0000	; plan de bits 2
	dc.w	$00e6,$0000
	dc.w	$ffff,$fffe	; FIN COPPERLIST

COPPERLIST2:
	dc.w	$0100,$A200	; résolution, nb plan de bits
	dc.w	$0180,$0000	; couleur 0
	dc.w	$0182,$0f00	; couleur 1
	dc.w	$0184,$00f0	; couleur 2
	dc.w	$0186,$000f	; couleur 3

	dc.w	$008e,$2069	; DIWSTRT
	dc.w	$0090,$29c9	; DIWSTOP
	dc.w	$0092,$0030	; DDFSTRT
	dc.w	$0094,$00D8	; DDFSTOP

	dc.w	$0108,$0028+$0080 ; modulo plans impaires
	dc.w	$010a,$0028+$0080 ; modulo plans paires

PLAN1_2:
	dc.w	$00e0,$0000	; plan de bits 1
	dc.w	$00e2,$0000
PLAN2_2:
	dc.w	$00e4,$0000	; plan de bits 2
	dc.w	$00e6,$0000
	dc.w	$ffff,$fffe	; FIN COPPERLIST

ECRAN: ;(doit être en mémoire CHIP)
	blk.b	33920,$f0	;1024/265 -> rayures
	blk.b	33920,$0f	;1024/265 -> rayures inversées

Quelques notes sur cet exemple : il affiche un écran de 352x265 en mode haute résolution (640x200), 4 couleurs. Les plans de bits font 1024x265 pixels chacun. En organisation Bitmap, on peut voir des rayures verticales, alternativement rouges et vertes. En organisation IFF, on peut voir des rayures verticales bleues et noires qui s'inversent au milieu de l'écran, en passant par une ligne pointillée transitoire rouge et verte.

Nous verrons les différents modes d'écran (HAM, Extra Halfbrite...) dès le mois prochain. D'ici là, amusez-vous bien !


[Retour en haut] / [Retour aux articles] [Article suivant]