Les interruptions



Remarque preliminaire : cet article ne vise pas a decrire ce que sont les interruptions mais plutot a expliquer a quoi elles peuvent servir pour le programmeur que vous etes ! Pour plus d'informations sur les interruptions je vous conseilles fortement de vous reporter aux deux fichiers HPREGINT et HPMJSINT (disponibles sur PULSAR bien entendu).

I. Presentation generale des interruptions

Une interruption a lieu lorsque l'un des evenements suivants se produit :
-Horloges 1 ou 2 passant a zero.
-Carte memoire retiree.
-Batteries faibles.
-RAM corrompue.
-Reception d'un octet sur le port infrarouge/RS232.
-Touche du clavier enfoncee.

Lorsque l'un de ces evenements a lieu, le SATURN va automatiquement aller en #0000Fh, ou se trouve la routine de gestion des interruptions.
On peut masquer certaines interruptions, de trois manieres differentes :

Grace a l'instruction INTOFF, l'appui sur une touche ne provoquera plus d'interruptions, sauf pour la touche ON qui provoque TOUJOURS une interruption !
On peut aussi interdire toutes les interruptions par l'intermediaire de l'instruction ST=0 15. En effet il ne peut pas y avoir deux interruptions en meme temps. Avec le flag 15, la routine de gestion des interruptions annule le traitement de l'interruption en cours et au lieu de retourner au programme en cours par un RTI, la routine revient par un RTN. Or le RTI permet justement a une autre interruption d'avoir lieu, contrairement au RTN qui empeche une autre interruption d'avoir lieu.
On peut aussi, par l'intermediaire de la RAM I/O, autoriser ou non le declenchement d'une interruption venant des horloges et du port serie (cf. Voyage au centre de la HP pour plus de details).

II. Interets des interruptions

Le principal interet des interruptions c'est qu'on peut detecter des evenements sans les tester sans arret ! Par exemple la HP ne s'occupe presque jamais de tester le clavier puisque a chaque fois qu'on appuie sur une touche, une interruption a lieu et la touche est stockee dans le buffer clavier ! Pour les programmes en niveaux de gris par exemple, il est tres lourd de tester a chaque operation du jeu de savoir s'il est temps de change d'ecran. Avec le detournement d'interruptions, il vous suffit de mettre une valeur, dans l'horloge 2, correspondant à un rafraichissement ecran (ou 2 suivant l'ecran a afficher). Ainsi, a chaque interruption de celle-ci, on echange les ecrans et on recharge une nouvelle valeur dans l'horloge 2 ! Ainsi plus rien ne vous empeche d'effectuer des operations sur plusieurs VBL puisqu'a chaque fois qu'il sera temps d'afficher un nouvel ecran cela se passera automatiquement sans que vous vous en rendiez compte !

III. Comment detourner les interruptions de la HP ?

Le principal probleme pour detourner les interruptions est que le gestionnaire est en #0000Fh, or a cette adresse il y a la ROM. Le moyen le plus pratique est de deplacer la RAM en #00000h, puis de coder un GOVLNG vers votre gestionnaire d'interruptions. Il faut tout d'abord interdire les interruptions (pour pouvoir deplacer la RAM) et autoriser les interruptions de l'horloge 2 puis on met une valeur dans celle-ci pour que les interruptions s'initialisent toutes seules.

GOSBVL 0679B
GOSBVL 01115

% On enleve les menus
D1= 00128
LC F
DAT1=C 1

% Recuperation d'une adresse paire (ecran oblige) dans la zone memoire libre, dans
% notre exemple c'est cette zone memoire qui va etre affichee
A=B A
A=A+1 A
ABIT=0 0

% Adresse qu'utilisera votre gestionnaire
% pour connaître l'adresse de l'ecran a afficher
D0= 80153
LC 80000
A=A-C A
DAT0=A A

% On pointe sur le deuxieme ecran
D0=D0+ 5
LC 00880
A=A+C A
DAT0=A A

% Initialisation de l'horloge 2
D0= 0012E
LC 30
DAT0=C B

% On va mettre une valeur dans l'horloge
% pour qu'elle s'initialise toute seule
D0= 38
C=0 W
C=C+1 A
DAT0=C 8

% On pointe sur notre routine de gestion d'interruptions.
A=PC
GOINC MYINT
A=A+C A

% Puis on teste si elle est en RAM ou non
LC C0000
?A>C A
GOYES PAS.EN.RAM
LC 80000
A=A-C A
*PAS.EN.RAM

% Puis on sauvegarde l'adresse pour une utilisation future
D0= 800A2
DAT0=A A

% On appelle la routine qui va se charger de deplacer la RAM
GOSUBL INIT.INT
% On attend une touche
*WAIT.KEY
LC 1FF
GOSBVL 00017
?C=0 X
GOYES WAIT.KEY

% On appelle la routine qui va se charger de replacer la RAM
GOSUBL STOP.INT
% On remet les pointeurs ecrans, menus
GOSBVL 01C7F
% On re-autorise les interruptions
GOSBVL 010E5
% On vide le buffer clavier
GOSBVL 00D57
% On sort
GOVLNG 05143
% On link le source qui deplace la RAM
'RAMINT
% et celui qui contient votre gestionnaire d'interruptions
'MYINT
@"

Pour deplacer la RAM il ne faut pas que le programme qui la deplace soit lui-meme en RAM. Il faut en effet que tous les CONFIG/UNCNFG soient a une adresse fixe ! La seule solution est de charger la pile RSTK d'adresses en ROM qui vont s'appeler tour a tour, grace aux RTN, pour revenir au programme apres le deplacement de la RAM. La RAM va donc recouvrir la ROM et les routines de tests de touches qui sont indispensables. Il faut donc recoder l'instruction C=IN a une adresse paire, ce qui va etre fait en meme temps que le codage du GOVLNG en #0000Fh car tout tient dans un champ W comme le montre le tableau :
# F # 10 # 11 # 12 # 13 # 14 # 15 # 16 # 17 # 18 # 19 # 1A # 1B # 1C # 1D # 1E
8 D ? ? ? ? ? 0 8 0 1 8 0 3 0 1
Codage du GOVLNG vers votre gestionnaire (*) OUT=C C=IN RTN

(*) Sert uniquement pour que l'instruction C=IN soit a une adresse paire.

Au lieu de faire habituellement un GOSBVL 01EEC, on fera un GOSBVL 00017.

"*INIT.INT
% On sauvegarde les 16 quartets que l'on va utiliser en # 8000Fh, en # 80092h
D0= 8000F
A=DAT0 16
D1= 80092
DAT1=A 16

% On se prepare a poker le GOVLNG vers
% votre gestionnaire et le nouveau OUT=C
% C=IN RTN en # 00017h
P= 6
LC 10308108 % OUT=C C=IN RTN
P= 0
D1= A2
C=DAT1 A
% Adresse de votre gestionnaire
D=C A
CSL W
CSL W
LC D8
% Codage du GOVLNG
DAT0=C 16
% On teste si le gestionnaire est en RAM ou
% pas, pour savoir si on doit revenir apres le deplacement de la RAM
D=D+D A
GOC NOT.IN.RAM
C=RSTK
LA 80000
C=C-A A
RSTK=C
*NOT.IN.RAM
D0= 05
C=DAT0 A
% Taille de la RAM
B=C A
LC 40154
% RTI
RSTK=C
LC 41535
% CONFIG RTN
RSTK=C
LC 40004
% C=0 A RTN
RSTK=C
LC 41535
% CONFIG RTN
RSTK=C
LC 66B75
% BCEX RTN
RSTK=C
LC 80000
GOVLNG 4049B
% UNCNFG RTN
% Recapitulons : cet empilage va realiser
% (avec B contenant la taille de la RAM en
% complement a 2 pour etre utilise par l'instruction CONFIG)
% LC 80000
% UNCNFG
% BCEX
% CONFIG
% C=0 A
% CONFIG
% RTI (on reinitialise les interruptions,
% en revenant au programme principal)
*STOP.INT
C=0 X
OUT=C

% On remet l'horloge 2 dans son etat
% initial
LC 10
D0= 0012E
DAT0=C B

% On teste si le gestionnaire est en RAM ou
% pas, pour savoir si on doit revenir apres
% le deplacement de la RAM
D0= 000A2
C=DAT0 A
C=C+C A
GOC NOT.IN.RAM2
C=RSTK
LA 80000
C=C+A A
RSTK=C
*NOT.IN.RAM2

% Restauration des 16 quartets utilises
D0= 92
A=DAT0 16
D1= 0000F
DAT1=A 16

% Remise en place de la RAM
% Adresse de la routine s'occupant de
% replacer la RAM apres un ON-C :
LC 0224F
RSTK=C
C=0 A
GOVLNG 4049B % UNCNFG
@"


IV. Comment ecrire le nouveau gestionnaire d'interruptions ?

La routine de gestion d'interruptions va s'occuper de swapper les 2 ecrans pour former l'image en niveaux de gris. Comme vous vous en doutez cette routine doit ABSOLUMENT sauvegarder les registres qu'elle pourrait modifier car elle peut etre appelee n'importe ou dans votre code! La routine sauvegarde les registres suivants :

La CARRY (ST=0 15 : pas de CARRY, ST=1 15 : CARRY)
C(A) (Sauvegarde dans RSTK)
C(5-15) et D0.
SB, P et le mode hexadecimal/decimal.

Recapitulons toutes les occupations memoire necessaire au fonctionnement de notre gestionnaire :

Adresse Contenu
# 00092h Sauvegarde des 16 quartets utilises en # 8000F
# 000A2h Sauvegarde de l'adresse de notre gestionnaire
# 00140h Sauvegarde de C(5-15) et D0
# 00150h Sauvegarde de SB, P et le mode hexadecimal/decimal
# 00153h Adresse du premier ecran a afficher
# 00158h Adresse du deuxieme ecran a afficher



Si vous devez utiliser plus de registres dans votre nouveau gestionnaire d'interruptions il vous faudra changer cette routine pour pouvoir sauvegarder ces registres. Le flag 14 permet de savoir quel ecran est a afficher, il ne faut donc pas le modifier dans votre code principal mais il peut etre teste pour savoir si l'image a fini d'etre affichee.

"*MYINT
% Debut de la sauvegarde des registres
ST=0 15
GONC NO.CARRY
ST=1 15
*NO.CARRY
RSTK=C
CD0EX
D0= 00140
DAT0=C 16
C=0 A
?SB=0
GOYES NO.SB
C=C+1 A
*NO.SB
CPEX 1
P= 2
C=C-1 P
P= 0
SETHEX
D0= 50
DAT0=C 3

% Fin de la sauvegarde des registres
% On teste si c'est bien l'horloge 2 qui a provoque une interruption
D0= 2F
C=DAT0 B
?CBIT=0 3
GOYES FIN.INT

% On se synchronise avec le balayage ecran
D0= 28
*WAIT.VBL
C=DAT0 B
C=C+C B
C=C+C B
?C(0 B

GOYES WAIT.VBL
% On cherche le bon ecran a poker en
% # 00120h en fonction du flag 14
D0= 53
?ST=0 14
GOYES 1ER.ECRAN
D0= 58
*1ER.ECRAN

% Recuperation de l'adresse de l'ecran a afficher
C=DAT0 A
% On le poke
D0= 20
DAT0=C A

% On recharge l'horloge 2 avec la valeur
% qui convient en fonction de ecran a afficher :
% # 80h (qui correspond a 1/64eme de
% seconde soit 1 VBL) pour le premier ecran et
% # 100h (qui correspond a 2/64eme de
% seconde soit 2 VBL) pour le deuxieme ecran
% Mais on prefere mettre moins pour pouvoir
% se synchroniser parfaitement et avoir des
% niveaux de gris parfaits
D0= 38
C=0 W
LC 7D
?ST=0 14
GOYES PREMIER.ECRAN
LC FD
ST=0 14
GONC ECRIRE.HORLOGE
*PREMIER.ECRAN
ST=1 14
*ECRIRE.HORLOGE
DAT0=C 8
*FIN.INT

% Restauration des registres
D0= 50
C=DAT0 3
P= 2
C=C+1 P
GOC HEX
SETDEC
*HEX
P=C 1
CSRB B
D0= 40
C=DAT0 16
D0=C
C=RSTK
?ST=1 15
GOYES CARRY
*CARRY
RTI
@"

Cette routine est donnee a titre d'exemple, on pourrait rajouter d'autres fonctionnalites :
-Gestion du port IR pour jeux a 2.
-Gestion des touches par bufferisation.
-Faire jouer de la musique en tache de fond.
-Emuler du multitâche (enfin avec les limitations de la HP bien entendu).

Note : Il ne faut pas oublier de tester si on n'est pas en face d'une carte mergee car dans ce cas il se pourrait qu'une partie du programme soit deplacee et pas l'autre d'ou apparition d'un probleme...

CHL


last modified: Tue February 24 2004 21:32:54
Valid XHTML 1.0! Valid CSS!