|
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
a un rafrachissement 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 connatre 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 multitache (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 ( son site : http://chl.tuxfamily.org/hp/ )
Downloader
la doc
|