Suivez-nous sur X

|
|
|
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
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Assembleur - défilement par interruptions
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - avril 1995)
|
|
Ce mois-ci, on va créer un petit programme original qui permet de faire défiler un texte dans un écran Intuition, en multitâche bien
sûr, grâce à un serveur d'interruption.
Principe
Le but étant de faire défiler un message dans un écran, la méthode la plus simple est bien sûr, après toutes les initialisations
préalables, de confier l'affichage du texte à la tâche en cours. Ceci présente énormément d'inconvénients : le système se trouve
ralenti de façon sensible, et l'affichage est saccadé en cas de surcharge du multitâche. De plus, c'est du travail supplémentaire
pour le programmeur, qui doit gérer les délais pour le décalage. Pas question, en effet, alors que les vitesses des différentes
machines peuvent varier presque du simple au décuple, de faire une bête boucle d'attente comme on le faisait sur C64, ce qui
au demeurant pénalise fortement le système. Enfin, le résultat est disgrâcieux si le défilement se produit au moment où le "spot"
est en train d'afficher l'écran concerné.
La méthode retenue ici consiste à installer un serveur d'interruption qui est appelé lors du rafraîchissement vertical, c'est-à-dire
chaque fois que le "spot" arrive en bas de l'écran, ce qui arrive 50 fois par seconde pour le moniteur PAL, 60 fois par seconde
pour le moniteur NTSC, ces valeurs étant différentes pour d'autres moniteurs (DblNTSC, EURO72...).
Réalisation
On ne peut pas avoir le beurre et l'argent du beurre, et on perd par cette méthode certains avantages offerts par l'exécution
d'un programme par une tâche. Par exemple, il n'est pas question d'appeler une routine de la graphics.library pendant le programme
d'interruption ! Il faut tout faire avec le processeur. On pourrait aussi utiliser le Blitter pour le défilement et l'affichage
de caractères, mais cela obligerait à quelques jongleries avec les blitnodes et la fonction QBSBlit(), pour un gain relativement
faible et une complexité accrue.
Pour résoudre le problème du défilement des caractères, on fait juste une série de ROXL (ROtate Left with eXtend bit : rotation
vers la gauche avec le bit d'extension) : pour chaque ligne de l'affichage, en partant de la droite avec X=0, on décale les octets
un par un d'un bit vers la gauche, le bit X servant à "transporter" le bit de gauche de l'octet de droite dans le bit de droite
de l'octet de gauche, et, chaque fois qu'on a décalé de la largeur d'un caractère, on en imprime un nouveau à l'extrême droite.
Le problème, c'est l'impression de ce caractère : on ne peut pas appeler la fonction Text() dans la routine d'interruption et
la structure TextFont est inexploitable directement car mal documentée. Pour résoudre ce problème, lors de l'initialisation, on
se construit une bitmap en mémoire (qui n'est jamais affichée) destinée à contenir tous les caractères de la police de caractère.
On les imprime dans cette bitmap grâce à la fonction Text(), en ayant pris soin d'utiliser un rastport temporaire, alloué
directement sur la pile. La routine d'interruption ira alors recopier le caractère voulu, octet par octet, dans la zone
d'affichage, constituée d'un écran Intuition de 640x8x1.
L'interruption
L'utilisation des interruptions sur Amiga est très simple et très performante. Dans le cas de l'interruption VERTB qui nous
intéresse, Exec aiguille le programme sur un gestionnaire de liste. Chaque routine dans cette liste, déclarée grâce à une
structure Interrupt passée à la fonction AddIntServer() d'Exec, sera appelée tour à tour par ordre de priorité.
Le seul paramètre d'entrée intéressant est dans le registre A1 : le contenu du champ IS_DATA de la structure Interrupt, que nous
utilisons ici pour pointer la zone d'affichage de l'écran Intuition (obtenu par le rastport de l'écran, car il ne faut plus
utiliser le champ sc_BitMap de la structure screen, voir la note dans le fichier intuition/screens.i). Tous les registres
doivent être sauvegardés, à l'exception éventuelle de D0-D1/A0-A1/A5-A6. En sortie, on doit mettre le drapeau Z à 1 (par exemple
en mettant D0 à 0) pour indiquer que les autres serveurs de la liste doivent être appelés, ou 0 dans le cas contraire. Les
routines de la liste VERTB doivent toujours remettre ce drapeau à 1, sous peine d'empêcher des opérations indispensables au système.
De plus, tous les serveurs VERTB de priorité supérieure à 10 doivent absolument mettre A0 à $DFF000, pour corriger un léger bogue
du serveur de la graphics.library qui se trouve à la priorité 10.
L'exécution de la routine d'interruption se fait bien sûr en mode superviseur, et le retour se fait par un RTS et non un RTE.
Ici, la priorité utilisée dans l'exemple est de -10, ce qui fonctionne sans problèmes sur mon système. Un essai avec une priorité
de 9 ralentissait (le mot est faible !) le pointeur de la souris, sans doute en interférant avec un serveur, celui du
gameport.device je présume.
Bien que ce programme ne requière aucune des particularités du système 2.0, un essai sous 1.3 s'est lamentablement planté, la
graphics.library se plaignant avec un gourou 82010000 d'un manque de mémoire Chip. Une seule solution : achetez la ROM 3.1 !
Plans futurs
Il est tout à fait envisageable de beaucoup améliorer cet algorithme (le modeste programme que je vous propose fait exactement
1024 octets !), notamment par la prise en compte de polices de caractères de taille différentes, voire de polices
proportionnelles ou en couleurs (là, c'est déjà beaucoup plus dur), et aussi, des variations de vitesse.
J'étudie actuellement la possibilité d'inclure ce type de routine dans un périphérique logique Exec, et de lui adjoindre une interface
AmigaDOS pour disposer d'un défileur de fichier facile. Ce sera peut-être dans un prochain article...
Dernière chose : j'utilise pour l'assemblage des programmes le fichier préassemblé system.gs fourni avec Devpac 3. Dans le cas
où un programme refuserait de s'assembler par manque de certaines déclarations, essayez de rajouter certains fichiers
includes que je pourrais avoir oubliés. Si vous utilisez un autre assembleur que Devpac 3, il vous faudra remplacer le fragment
de code entre REPT et ENDR par huit fois lui-même si votre assembleur ne reconnaît pas la directive REPeaT.
include exec/exec.i
include exec/exec_lib.i
include graphics/gfx.i
include graphics/graphics_lib.i
include intuition/intuition.i
include intuition/intuition_lib.i
include hardware/intbits.i
move.l 4.w,a6
lea Graphics.Name(pc),a1
moveq #34,d0
jsr _LVOOpenLibrary(a6)
move.l d0,GfxBase
beq exit
move.l d0,a6
lea Topaz8.TextAttr(pc),a0
jsr _LVOOpenFont(a6)
move.l d0,Topaz8.Font
move.l d0,a2
beq clgfx
lea Intuition.Name(pc),a1
moveq #34,d0
move.l 4.w,a6
jsr _LVOOpenLibrary(a6)
move.l d0,IntBase
beq clfont
move.l d0,a6
lea NScreen(pc),a0
jsr _LVOOpenScreen(a6)
move.l d0,Scr
beq clint
move.l d0,a1
move.l sc_RastPort+rp_BitMap(a1),a1
move.l bm_Planes(a1),IntServer+IS_DATA
move.l GfxBase(pc),a6
moveq #0,d0
move.b tf_LoChar(a2),d1
move.b d1,FirstChar
move.b tf_HiChar(a2),d0
sub.b d1,d0
addq.l #1,d0
lsl.l #3,d0 ; largeur=cars*8
move.l d0,CharWidth
moveq #8,d1 ; hauteur=8
jsr _LVOAllocRaster(a6)
move.l d0,Characters
beq clscr
sub.l #rp_SIZEOF,sp ; rastport sur la pile
move.l sp,a1
jsr _LVOInitRastPort(a6)
lea Chars.BitMap(pc),a0
move.l a0,rp_BitMap(sp)
moveq #1,d0 ; profondeur
move.l CharWidth(pc),d1 ; largeur
moveq #8,d2 ; hauteur
jsr _LVOInitBitMap(a6)
move.l sp,a1
move.l a2,a0
jsr _LVOSetFont(a6)
move.w tf_Baseline(a2),d1
moveq #0,d0
move.l sp,a1
jsr _LVOMove(a6) ; premier caractère
move.b FirstChar(pc),CharBuf
move.l Topaz8.Font(pc),a1
moveq #0,d2
move.b tf_HiChar(a2),d2
sub.b tf_LoChar(a2),d2
PrintChars
lea CharBuf(pc),a0
moveq #1,d0
move.l sp,a1
jsr _LVOText(a6)
add.b #1,CharBuf
dbra d2,PrintChars
add.l #rp_SIZEOF,sp ; libère rastport
move.l 4.w,a6
moveq #INTB_VERTB,d0
lea IntServer(pc),a1
jsr _LVOAddIntServer(a6)
move.l #SIGBREAKF_CTRL_C,d0
jsr _LVOWait(a6)
move.l #INTB_VERTB,d0
lea IntServer(pc),a1
jsr _LVORemIntServer(a6)
freech move.l CharWidth(pc),d0
moveq #8,d1
move.l Characters(pc),a0
move.l GfxBase(pc),a6
jsr _LVOFreeRaster(a6)
clscr move.l Scr(pc),a0
move.l IntBase(pc),a6
jsr _LVOCloseScreen(a6)
clint move.l a6,a1
move.l 4.w,a6
jsr _LVOCloseLibrary(a6)
clfont move.l Topaz8.Font(pc),a1
move.l GfxBase(pc),a6
jsr _LVOCloseFont(a6)
clgfx move.l a6,a1
move.l 4.w,a6
jsr _LVOCloseLibrary(a6)
exit moveq #0,d0
rts
Scroll move.l d2,-(sp)
moveq #7,d0 ; lignes
.Line move.l #640/16-1,d1 ; mots
andi #~(1<<4),CCR ; efface X
.Byte move.l d1,d2
mulu #2,d2 ; X doit être préservé: pas de lsl
roxl.w 0(a1,d2.w)
dbra d1,.Byte
add.l #640/8,a1 ; ligne suivante
dbra d0,.Line
subq.b #1,Scroll.Count
bgt.s .Ret
; afficher un caractère
move.b #8,Scroll.Count
.LoopScroll
move.l ScrollText(pc),a0
moveq #0,d0
move.b (a0)+,d0
bne.s .NotEnd
move.l #MessageText,ScrollText
bra.s .LoopScroll
.NotEnd move.l a0,ScrollText
sub.b FirstChar(pc),d0
move.l Characters(pc),a1
lea 0(a1,d0),a0
move.l IntServer+IS_DATA(pc),a1
add.l #640/8-1,a1
move.l CharWidth(pc),d1
lsr.l #3,d1
REPT 8
move.b (a0),(a1)
add.l d1,a0
add.l #640/8,a1
ENDR
.Ret move.l (sp)+,d2
moveq #0,d0
lea $DFF000,a0 ; pour la graphics.library
rts ; (léger bogue inoffensif)
GfxBase dc.l 0
Topaz8.Font dc.l 0
IntBase dc.l 0
Scr dc.l 0
ScrollText dc.l MessageText
Topaz8.TextAttr
dc.l Topaz.Name
dc.w 8
dc.b 0,0
NScreen dc.w 0,248,640,8,1,-1
dc.w V_HIRES,CUSTOMSCREEN!SCREENQUIET
dc.l Topaz8.TextAttr,0,0,0
IntServer
dc.l 0,0
dc.b NT_INTERRUPT,-10
dc.l Scroll.Name
dc.l 0,Scroll
Chars.BitMap dc.w 0,0,0,0
Characters dc.l 0
CharWidth dc.l 0
Scroll.Count dc.b 1
FirstChar dc.b 1
CharBuf dc.b 0
Scroll.Name dc.b 'AmigaNews scroller',0
Topaz.Name dc.b 'topaz.font',0
Intuition.Name dc.b 'intuition.library',0
Graphics.Name dc.b 'graphics.library',0
MessageText dc.b 'défilement fluide en multitâche sur amiga...'
dc.b ' Vous pouvez déplacer ce message comme'
dc.b ' n''importe quel écran intuition: à la souris...'
dc.b ' CTRL-C dans la fenêtre du CLI pour sortir. '
dc.b ' ',0
|
Téléchargement de l'exécutable : scrolling-system.lha.
|