Obligement - L'Amiga au maximum

Lundi 20 novembre 2017 - 19:46  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

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

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


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


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


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


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 "vertical blanking", 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 device 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


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]