Assembleur: Les Maxi-Caractères (Dernière partie)
Hello,
Un projet se termine, un autre prend forme. Depuis que je me suis remis à la programmation (Basic ou Assembleur), une grande partie de mes projets que j'avais dans les années peek et poke, me reviennent en mémoire.
Il faut avouer que l' Amstrad à joué un grand rôle dans ma jeunesse. Son language 'Basic' et 'Binaire' m'a ouvert des portes qui ne se refermeront plus. Je ne sais pas le nombre d'heures que j'ai passé à recopier des listing ou à essayer des routines, mais tous les jours, en rentrant du taf, ma priorité était consacré à l'Amstrad.
Revenons-en a nos Maxi Caractères et MaxiCHR. C'est à dire en MAI 2019 😃
Vous trouverez tous les détails de chaque routines (RSX) et ma méthode de programmation. Si vous avez des questions, des suggestions ou des critiques, n'hésitez pas, j'en serais ravi !
En bas de la page vous aurez le lien de téléchargement du fichier 'ZIP' qui comprend la disquette et les listings 'ASM'
ROUTINE RSXENCRE et RSXPAPIER: ; ########## - ########## - ########## - ########## - ########## - ########## - ########## - ##########
; # RSX ENCRE et RSX PAPIER C'est deux RSX font le meme topo, seul le registre 'HL' du depart change
RSXENCRE ; ENCRE, Coul1 [, Coul2] [, Coul3] [, Coul4]
; PAPIER, Coul1 [, Coul2] [, Coul3] [, Coul4]
; CE> Les parametres [optionnels] gardent leurs anciennes valeurs
LD HL, Couleur - 1 ; 'HL' est positionne sur l' emplacement des encres - 1
JR PourLePapier ; On saute pour la suite du programme
RSXPAPIER
LD HL, Couleur + 3 ; 'HL' pointe sur l'emplacement du papiers - 1
PourLePapier ; A ce stade, 'HL' pointe soit sur les encres soit sur les papiers
CP 5 ; On regarde si on ne depasse pas les 4 parametres
RET NC ; Sinon on sort sans bouder vers le basic
OR A ; Et si il n'y a pas de parametre
RET Z ; On quitte le navire aussi
LD B, 0 ; On va ajouter a 'HL' le nombre de parametres
LD C, A ; 'C' = nombre de parametre
ADD HL, BC ; 'HL' pointe sur la derniere couleur a traiter
LD B, A ; 'B' contient le nombres de parametre
Couleur_Encre
LD A, (IX + 0) ; 'A' = valeur du parametre
CP 16 ; Si >= 16, il n'y a que 16 couleurs en MODE 0
RET NC ; On ne reste pas, Faut pas pousser non plus
; Les couleurs sont codees et il faut chercher la correspondance avec les couleurs du MODE 0
LD DE, CouleurCodee ; 'DE' pointe sur la table des couleurs codees
ADD A, E ; 'A' Contient le numero de la couleur demandee
LD E, A ; 'DE' Pointe sur la correspondance de la couleur demandee
LD A, (DE) ; 'A' est charge avec le code de la couleur codee de MODE 0
LD (HL), A ; On l'incrit simplement dans 'HL'
DEC HL ; Et on passe a la couleur suivant
INC IX
INC IX ; Et aussi au parametre suivant
DJNZ Couleur_Encre ; On recommence tant qu'il y a des parametres
RET
Vous remarquerez que j'ai programmé deux routines en une. Les deux routines sont identiques, seul le positionnement sur la variable 'Couleur' change.
Au début je déclare la variable qui servira d'adresse de départ pour les RSX, mais ici deux variables seront déclarées (RSXENCRE et RSXPAPIER). Lors de la création des RSX, chacun sera ou commencer le code à executer.
- RSXENCRE, Coul1 [,Coul2] [,Coul3] [,Coul4]
Cet RSX sera chargé de décoder et d'inscrire les couleurs correspondants de vos encres à partir de la variables (Couleur)
- RSXPAPIER, Coul1 [,Coul2] [,Coul3] [,Coul4]
Et ce RSX fera la même chose mais à partir de la variable (Couleur + 4)
Au départ des deux RSX, on charge le registre 'HL' avec la valeur appropriée -1.
Pourquoi ce -1 ?, Tout simplement parce que lorsque l'on appelle un RSX, le dernier paramètre transmis se trouve en début du registre (IX). Il nous faut ajouter le nombre de paramètre transmis avec le registre 'HL' pour que celui-ci point sur sur la bonne couleurs. Si je n'avais pas opté pour des paramètres optionnels, on aurait pu simplifier la programmation, mais de cette façon, je vous montre comment mettre en option certains des paramètres.
Voici mon principe simplifié pour créer un RSX avec des paramètres optionnels:
En 1:On appelle le RSX 'ENCRE' avec 3 paramètres
'HL' pointe sur la variable 'Couleur' - 1
En 2: On addition le nombre de paramètres avec 'HL'
Celui-ci pointe sur la variable 'Couleur' + 2 (Couleur-1) + (3paramètres)
On y inscrit le paramètre pointé par 'IX' (Couleur + 2) = 4
En 3: On décrémente 'HL' (Couleur+1) et on passe au paramètre-1 en incrémentent 'IX' deux fois
La valeur du paramètre est inscrite dans 'HL' (Couleur + 1) = 8
En 4 On procède de même en décrémentant 'HL' (Couleur) et et remontant au premier paramètre
On inscrit la valeur du premier paramètre dans 'HL' (Couleur) = 2
Conclusion: On a bien inscrit depuis la variable (Couleur) tous les paramètres transmis tout en gardant les valeurs optionnels dans leurs états. Mais ce n'était qu'un exemple car il faut aussi décoder les fameuses couleurs codées avant de les inscrire. Cela est expliqué ici: Les Maxi-Caractères (Deuxième partie)
Pour le reste, le programme est auto-documenté mais si vous avez des questions, laissez moi un commentaire, merci.
On passe à la routine suivante:
Routine RSXCURSEUR; # RSX CURSEUR
RSXCURSEUR ; Positionne le curseur pour le prochain affichage des maxis caracteres
; CE> CURSEUR, Col, Lig (Comme pour la commande Basic 'LOCATE' du MODE 0)
CP A, 2 ; Si le nombre de parametres envoye est different de 2
RET NZ ; On renvoie au basic
LD A, (IX + 2) ; 'A' = Col
CP A , 21 ; Col (1 a 20) MODE 0
RET NC ; Retour au basic, parametres non valides
CP A, 1
RET C
DEC A ; On reajuste pour les calculs (0 a 19)
ADD A, A ; (x2)
ADD A, A ; (x4)
ADD A, A ; (x8) Par 8 car chaque caractere fait 8 points de largeur
LD H, A ; 'H' Contient la valeur pour les Colonnes
LD A, E ; 'A' = Lig (A l'appel du RSX, 'E' contient le dernier parametre)
CP A, 26 ; Lig (1 a 25) On garde le principe du 'LOCATE'
RET NC ; Retour basic, les parametres ne sont pas valides
CP A, 1
RET C
DEC A ; Mais il faut soustraire 1 car les vrais coordonnes commence a 0
ADD A, A ; (x2) Il faut multiplier sa valeur par 8
ADD A, A ; (x4)
ADD A, A ; (x8) multiplie par 8, 1 caractere=8 lignes
LD L, A ; 'L' contient les lignes en partant du bas
LD A, 199 ; Pour partir du haut a gauche, il faut inverser les lignes
SUB A, L ; Car la position de depart commence en bas a gauche
LD L, A
LD (Curseur), HL ; On inscrit les coordonnees a l'abris des poussiere
RET
En prenant le principe de la commande 'LOCATE' du basic Amstrad, cette routine est plus que simple à mettre en oeuvre. On aurait pu garder la position du curseur de la commande 'LOCATE' mais pour le RSX 'GCURSEUR', il nous fallait une base pour gérer les coordonnées.
Au début, on regarde si les coordonnées de l'axe X (Col) sont compris de (1 à 20), sinon on retourne au basic. Je n'ai pas su comment provoquer une erreur et retourner au basic avec pour effet une sorte de (PRINT "ERREUR:n°": END) donc rien n'indique qu'il y a des erreurs dans les paramètres, mais rien n'est pris en compte si c'est le cas.
Il faut ensuite décrémenter de 1 car l'origine réelle de l'axe X est zéro. Les caractères font 8 pixels de large, donc le résultat doit être multiplié par 8.
Détail: Si vous voulez positionner le curseur sur la deuxième colonne, la valeur calculée sera (2-1)*8=8. De 8 à 15 le caractère sera affiché, et en regardant bien pour la position 1 de l'axe X (1-1)*8=0 de 0 à 7 cela correspond bien à 1 caractère de largeur sur la première colonne.
On procède de la même façon pour l'Axe Y. Après les fameux tests pour être situer de (1 à 25), puis décrémenter de 1 et multiplier aussi par 8 (Les caractères ont une hauteur de 8 pixels).
Mais cette fois, l'origine de l'axe Y démarre du bas, or pour les calculs de l'adresse d'écran, puisque j'ai voulu garder le principe de la commande 'LOCATE', l'origine doit se situer en haut. Il faut donc inverser l'origine des lignes, et comme l' Amstrad affiche 200 lignes (0 à 199), il faut simplement soustraire 199 avec le résultat obtenu de l'axe Y.
En exemple on va partir sur un CURSEUR,x, 14: (14-1)*8=104
104 représente le début de l'affichage d'un caractère sur la 14ème ligne. Le vecteur &BC1D qui calcule l'adresse d'écran, s'appuie sur ces coordonnées. Donc, pour placer le point de départ sur l'écran, c'est plus simple de faire les calculs avant de d'appeler ce vecteur.
Une fois les calculs fait, on l'inscrit dans la variable prévue pour cet effet (Curseur).
Routine RSXGCURSEUR:
; # RSX GCURSEUR
RSXGCURSEUR ; Place le curseur en position graphique (Du bas vers la gauche)
; CE> GCURSEUR, Col, Lig (Col 0-152) et (Lig 7-199)
CP A, 2 ; Si le nombre de parametres envoye est different de 2
RET NZ ; Renvoie au basic
LD A, (IX + 2) ; 'A' = Col
CP A , 153 ; de 152 a 159 On OK pour un autre caractere
RET NC ; Sinon retour au basic, parametres non valides
LD H, A
LD A, E ; 'A' = Lig >>> 'E' = Dernier parametre donc 'A' = Ligne
CP A, 200 ; Lig (7 a 199) 7 pour rester dans l'ecran
RET NC
CP A, 7 ; De 0 a 7 on peut encore afficher un caractere
RET C ; Retour basic, les parametres ne sont pas valides
LD L, A ; Pause cafe
LD (Curseur), HL ; On inscrit les coordonnees dans la variable prevue
RET
Cette routine est plus simple, puisque les coordonnées sont déjà calculées par vous.
On regarde simplement si on pourra afficher un caractère à l'endroit que vous indiquez. Pour cela, les coordonnées de l'axe X ne doivent pas être supérieur à 152 sinon on sortirait de l'écran et on risquerait de faire planter des choux blancs. 🤔
Pour l'axe Y, c'est pareil, on ne doit pas dépasser le 200 et en dessous on est OK, mais on doit aussi contrôler la position du bas de l'écran et regarder si le caractère pourra s'affiche. En dessous de 7 on retourne vers le basic Tchou Tchou car il faut au minimum 8 pixels de hauteur (0 à 7)
ROUTINE RSX AFFICHE
; # RSX AFFICHE ; Routine d'affiche d'une chaine de caractere
RSXAFFICHE
; AFFICHE, A$ Affiche la chaine A$ sans effet de ZOOM
; AFFICHE, Zoom, A$ Pareil que ce dessus et ZOOM en hauteur
; CE> A$ doit contenir au moins un caractere et les 256 caracteres Amstrad sont affichables
; CE> Zoom (1 a 25). Valeur par defaut ou si sortie ecran ZOOM = 1
CP A, 3 ; Si le nombre de parametre envoye est >2... Retour Basic
RET NC
OR A ; Ou si il n'y en a pas >Direction BASIC
RET Z
CP A, 1 ; Si 1 seul parametre, alors ZOOM = 1, Pas de ZOOM
JR Z, AFF_PasDeZoom
LD A, (IX + 2) ; Le ZOOM doit etre verifie pour ne pas sortir de l'ecran
CP A, 26 RET NC ; Le ZOOM ne peut pas depasser 25x en hauteur
LD B, A
LD C, A
SLA B ; Il faut multiplier la hauteur par 8 pour calculer la position du curseur
SLA B
SLA B ; En deplacant les BIT vers la gauche (x2 x4 x8)
LD A, (Curseur) ; On charge dans 'A' les coordonnees des lignes du (Curseur)
DEC B ; NB> pour les coordonnees des colonnes -> LD A, (Curseur + 1)
CP A, B
JR NC, AFF_ZoomOK
LD C, 1 ; ca deborde, on remet la valeur par defaut du ZOOM pour eviter la casse
AFF_ZoomOK
LD A, C
AFF_PasDeZoom
LD (Zoom + 1), A ; On inscrit la hauteur du ZOOM VERTICAL avant d'appeler la routine
LD A, 8 ; On inscrit aussi le nombre de ligne (8=caractere et 16=MaxiCHR)
LD (CarCHR + 1), A
LD A, 170
LD (RotCou + 1), A ; Et la rotation des couleurs, 170="10101010"
LD H, (IX + 1) ; On va recuperer l'adresse de la chaine A$
LD L, (IX + 0)
LD A, (HL)
OR A ; Si la chaine est vide... Retour vers le Basic
RET Z
INC HL ; 'HL' contient l'adresse ou est stocke la chaine A$
LD E, (HL) ; Il faut faire pointer 'DE' pour recuperer les caracteres
INC HL
LD D, (HL) ; 'DE' Pointe sur le 1er Caractere de la chaine
LD B, A ; Et 'B' = Longueur de la chaine
AFF_Total
PUSH BC ; On sauvegarde la longeur de la chaine
PUSH DE ; Ainsi que l'endroit ou elle est stockee
LD A,(DE) ; 'A' contient le code ascii du caractere
AFF_AMSTRAD
LD DE, Caractere ; DE pointe vers notre table reservee pour le travail
CALL #BBA5 ; HL contient l'adresse en ROM du caractere
CALL #B906 ; On Active la ROM Inferieur pour recuperer la matrice du caractere
LD BC, 8 ; 'BC' contient le nombre d'octet a recuperer
LDIR ; Le transfert vers notre table est fini
CALL #B90C ; On restore la ROM utilisee
AFF_CHOIXOK
CALL AfficheCarCHR ; On peut affiche le caractere en appelant la sous routine
LD HL, (Curseur) ; Et modifier la position du curseur pour le prochain caractere
LD A, H ; Cette fois, il faut compter le caractere qui vient d'etre affiche
CP A, 146 ; Et voir si le prochain pourra etre affiche
JR C, AFF_ColPlus ; Alors on ajoutera 8 aux coordonnees des colonnes
LD A, L ; Sinon il faudra verifier si on peux descendre d'une ligne
CP A, 15
JR NC, AFF_LigPlus
LD H,0 ; Si ni l'un ni l'autre est possible
LD L, 199 ; On remet les origine par defaut (Haut Gauche)
JP AFF_ColLigOK
AFF_LigPlus
SUB A, 8 ; On descent d'une ligne donc Col=0
LD L, A
LD H, 0
JP AFF_ColLigOK
AFF_ColPlus
ADD A, 8 ; On se deplace d'une colonne et on garde la ligne
LD H, A AFF_ColLigOK
LD (Curseur), HL ; La variable est remise a jour avec les nouvelles coordonnees
POP DE
POP BC
INC DE ; Puis on passe au caractere suivant
DEC B ; Et on remonte jusqu'a afficher le dernier caractere
JP NZ, AFF_Total
RET
Cette routine affichera une chaîne de caractères avec la possibilité d'y ajouter un effet de zoom.
Les 256 caractères de l'Amstrad CPC peuvent être affichés. Pour avoir accès aux caractères non représentés sur le clavier, il vous faudra les ajouter à votre chaîne de caractère avec la commande 'CHR$(x)' du basic Amstrad.
Après la série de comparaison des paramètres, on regarde si la chaîne de caractères pourra être affiché avec le zoom demandé, sinon on affichera la chaîne sans zoom. Pour le savoir, on multiplie le zoom par 8 car on travaille avec des caractères de 8 pixels de haut. Ensuite on charge la position des lignes du curseur dans le registre 'A'. Une simple comparaison nous dira si le zoom est possible, sinon on met un zoom de 1 ce qui équivaut à pas de zoom.
Il faut initialiser la sous-routine 'AfficheCarLut' avec des valeurs pour afficher les caractères de 8 lignes.
D'abord on inscrit l'effet d'un zoom, puis vient le nombre de ligne à traiter. Avec des caractères, on a 8 lignes à traiter, mais avec les MaxiCHR, c'est 16 lignes à faire. Ici c'est pour des caractères Amstrad de 8 lignes.
Pour le roulement des couleurs en mode caractère de 8 lignes, il faut qu'elles tournent toutes les deux lignes, c'est pourquoi la valeur est 170='10101010' et pour les MaxiCHR la valeur est '10001000' car elles doivent tourner toutes les 4 lignes.
Les détails sont expliqués plus haut, je m'y attarde pas.
Dans un deuxième temps, on va récupérer l'adresse ou est stocké la chaîne à afficher. C'est un peu compliquer, mais une fois que l'on a compris, c'est acquis.
Je dirige le registre 'HL' pour récupérer l'adresse transmise en paramètres au travers de "IX + 0' et 'IX + 1'
A cet adresse, on a déjà le nombre de caractères contenu dans la chaîne.
Un octet plus loin, on obtient le poids faible de l'adresse de la chaîne que l'on place dans le registre 'E'
Et un octet plus loin, on obtient le poids fort que l'on place dans le registre 'D'
Au final: 'A' = Longueur de la chaîne et 'DE' pointe sur le premier caractère
Si c'est acquis, alors on continu, sinon faites donc !
On est fait prêt pour la troisième épreuves. Télécharger la matrice du caractère à afficher depuis la ROM Inférieur de l'Amstrad.
Il faut savoir que toutes les matrices des 256 caractères de l'Amstrad sont stockées dans une mémoire ROM qui n'est qu'en état de lecture uniquement. Pour afficher un caractère, il faut savoir ou il est stocké, un 'A' n'a pas la même adresse que un '3' par exemple mais notre ami 'SUGAR' y a pensé, et grâce aux vecteurs système on peut naviguer dans une partie de cet ROM.
Voici les vecteurs et leurs conditions:
- Vecteur &BBA5 : Ce vecteur recherche l'adresse du caractère dont le code ascii est dans le registre 'A'. Si le caractère n'est pas un caractère redéfini par l'utilisateur, alors 'HL' pointera sur son adresse située dans la ROM inférieur sinon le registre 'HL' pointera sur l'adresse en RAM ou le caractère est redéfini.
On ne s'occupera pas de savoir ou il est, on va simplement recopier les 8 octets qui forment le caractères vers notre variable (Caractere) afin de le travailler.
- Vecteur &B906 : Active la rom inférieur afin de pouvoir la lire
- Vecteur &B90C : Restaure la ROM , parfois j'ai des doutes, mais comme ça marche bien comme ça, je laisse en l'état.
Une fois que l'on a récupéré le code ASCII du caractère à afficher, on recherche l'adresse de sa matrice à l'aide du vecteur &BBA5, et on active la ROM inférieur pour récupérer 8 octets qui composent la matrice du caractère. On remet la ROM dans l'état avant de continuer le programme.
Il ne reste plus qu'à appeler la sous routine pour afficher le caractère situé à l'adresse de la variable (Caractere).
dernière étape. Repositionner le curseur pour le prochain affichage d'un caractère.
On a pas encore modifier la position du Curseur, on s'en est servi, mais sans remplacer les valeurs. Si je le précise, c'est pour bien comprendre la suite.
Tout d'abord, on place dans le registre 'H' les colonnes et dans le registre 'L' les lignes d'un coup avec l'instruction: LD (HL), Curseur.
Il faut se rappeler que l'on travail avec les coordonnées graphiques, de (0 à 159) pour les colonnes et de (0 à 199) pour les lignes.
On teste donc si le caractère suivant pourra s'afficher sur l'axe X, mais comme on a pas encore déplacer le curseur et que l'on vient d'afficher un caractère, il faut contrôler si la position de 2 caractères est possible. Si l'axe X est en dessous de 146 alors on ajoutera 8 à l'axe X pour le déplacer d'un caractère et dire que le prochain emplacement est autorisé sinon l' Axe X sera remis à zéro et on testera si on peut l'afficher en dessous mais la c'est pareil, on doit aussi compter le caractère que l'on vient d'afficher car l'origine se trouve en haut à gauche des caractères. Et si l'Axe Y est supérieur à 14, (de 0 à 15) alors c'est possible et on déduira 8 lignes mais autrement on remet les origines par défaut en haut à gauche de l'écran.
Il ne reste qu' à passer toute la chaîne de caractères, caractère par caractère pour finir cette routine.
ROUTINE RSX DEFMAXICHR
; # RSX DEFMAXICHR RSXDEFMAXICHR
; DEFMAXICHR, Numero, Lig1 [,lig2] [,lig3]... ... [,lig16]
; Definit un MaxiCHR de 8x16 affichable avec le RSX MAXICHR (8=largeur et 16=hauteur)
; Les parametres optionnels sont remplaces par des ZERO
; CE > Numero, (de 0 a 23), indique le numero du MaxiCHR a redefinir
CP 18 ; Si on a trop de parametre > Retour Basic
RET NC
CP 2 ; Si il y a pas assez de parametres > BASIC
RET C
LD B, 0 ; Il faut trouver le numero du MaxiCHR qui est dans le premier parametre
DEC A ; A l'appelle d'un RSX, 'A' Contient le nombre de parametre transmis
LD C, A ; 'C' = nombre de parametre moins 1
SLA C ; 'C' est multiplie par 2 car les parametres font 2 octets
ADD IX, BC ; IX pointe sur le premier parametre (L'Adresse)
LD C, A ; On remet dans 'C' le nombre de parametre moins 1 (Celui du numero)
LD A, (IX + 0) ; Et dans 'A', on inscrit le numero du MaxiCHR du premier parametre
LD HL, TableMaxiChr ; 'HL' pointe sur le MaxiCHR numero 0
OR A ; Si on veut redefinir le MaxiCHR 0, alors on a pas besoin de chercher l'adresse
JR Z, DEFMAXICHR_NUMERO
CP A, 23 ; Ne pas depasser le numero 22 pour ne pas ecraser les donnees
RET NC
LD DE, 16 ; Il faut recherche l'adresse qui correspond au numero du MaxiCHR
DEFMAXICHR_TABLE
ADD HL, DE ; Un MaxiCHR fait 16 octets, donc on ajoute 16 a 'HL' pour chaque MaxiCHR
DEC A ; Jusqu'a obtenir le MaxiCHR que l'on a indique en premier parametre
JR NZ, DEFMAXICHR_TABLE
DEFMAXICHR_NUMERO
LD A, C ; 'A' contient le nombre de parametre moins 1
LD B, 16 ; On a 16 chiffre a inscrire.
DEF_MAXICHR_Lig
LD D, 0 ; Valeur par defaut si le nombre de parametre est plus petit que 16
OR A ; 'A' sert de compteur, si 'A'=0 alors il n'y en a plus de parametre
JR Z, DEF_MAXICHR_Param
DEC IX ; On fait pointer 'IX' sur le parametre
DEC IX
DEC A ; Et on decremente le compteur de parametre 'A'
LD D, (IX + 0) ; 'D' est charge avec la valeur du parametre
DEF_MAXICHR_Param
LD (HL), D ; On inscrit soit le parametre, soit ZERO
INC HL ; et on passe au suivant
DJNZ, DEF_MAXICHR_Lig ; Jusqu' inscrire 16 valeurs au total
RET
Je ne sais pas comment ils ont programmé la commande 'SYMBOL' du basic Amstrad, j'aimerais bien le savoir afin de comparer ma routine qui se base exactement sur le même principe.
Cette routine permet de redéfinir un caractère de 8*16 dans les mêmes conditions que la routine 'SYMBOL'
Les paramètres omis sont remplacés par des zéro.
Il est peut être intéressant de comprendre comment compenser des paramètres optionnels pour leurs attribuer une valeur par défaut.
Au début on regarde si in n'y a pas trop ou pas assez de paramètres. Il faut 2 paramètres au minimum: Le numéro du MaxiCHR suivit d'au moins de la première ligne de définition. Tout de suite après, on va remonter au premier paramètre (Celui du Numéro) afin de savoir quel MaxiCHR redéfinir et aussi pour le comparer au maximum autorisé.
Pour cette opération, il faut additionner le nombre de paramètre - 1 avec le registre pointeur (IX). On sait que à l'appelle d'une fonction par un CALL ou un RSX, le registre (IX) pointe sur le dernier paramètre, mais que les paramètres qui précédent sont enregistrés en aval du registre (IX)
Par exemple: |DEFMAXICHR, 4, 255, 127, 63, 31, 15, 8, 19
Chaque paramètre est enregistré sur l' adresse que pointe le registre 'IX' - (Nombre de paramètre - 1) * 2
Il ne faut pas oublier que chacun des paramètres sont enregistrés sur deux octets (le poids fort et le poids faible), c'est le pourquoi qu'il faut multiplier par 2 pour retrouver les bonnes valeurs.
Avec l'image ci-dessous, les choses prennent sens:
Ici on a 8 paramètres, et pour retrouver le paramètre qui contient le numéro des MaxiCHR, il faut faire le calcul suivant:
'IX' = 'IX' + (Nombre de paramètre - 1) * 2, soit: 'BC' = (8 - 1) * 2 = 14: 'IX' = 'IX' + 'BC'
Maintenant que 'IX' pointe sur le premier paramètre, on n'a plus qu'à comparer que son contenu ne dépasse pas le nombre de MaxiCHR autorisé.
Si le numéro du MaxiCHR est correcte, on poursuit pour rechercher l'emplacement ou stocker ce caractère.
On connais l'adresse de départ du MaxiCHR numéro 0 qui correspond à la variable 'Caractere', alors pour savoir quelle est l'adresse des autres MaxiCHR, il faut faire un simple calcul en multipliant par 16 le numéro du caractère. Le MaxiCHR 1 sera donc stocké à l'adresse 'Caractère' + 16 et le MaxiCHR 2 sera stocké à l'adresse 'Caractere' + 32... etc... etc
Le programme se poursuit pour simplement écrire les valeurs des paramètres dans les emplacements et de continuer en remplaçant les paramètres manquants par la valeur zéro.
Routine RSX MAXICHR
; # RSX MAXICHR
RSXMAXICHR
; MAXICHR, [EFFET], Numero
; Affiche le MaxiCHR de 8x16 prealablement definit avec le RSX DEFMAXICHR
; Numero (0 a 22) designe le MaxiCHR a afficher
; EFFET de (1 a 4) 1=(Pas d'effet) 2=(Retournement horizontal) 3=(Retournement vertical) ; 4=(Pivotement de 90 degree)
CP A, 3 ; Maximum 2 parametres
RET NC
OR A ; Minimum 1 parametre
RET Z
LD C, A ; 'C' Contient le nombre de parametre (1 ou 2)
LD HL, TableMaxiChr ; 'HL' pointe sur le MaxiCHR numero 0
LD A, E ; EQUIVALENT LD A, (IX + 0) car 'D' contient le dernier parametre
OR A
JR Z, MAXICHR_NUMERO ; Si c'est le Numero zero, on reajuste pas la table
CP A, 23 ; Sortir car le numero est trop fort (0 - 22)
RET NC
LD DE, 16 ; 'DE' contient le nombre d'octets qui forme un MaxiCHR
MAXICHR_TABLE ADD HL, DE ; Additionner la table et le nombre de (MaxiCHR * ligne)
DEC A ; Jusqu'a obtenir l'adresse du MaxiCHR
JR NZ, MAXICHR_TABLE
MAXICHR_NUMERO
LD A, C ; Recuperer le Nombre de parametre
LD DE, Caractere ; 'DE' pointe vers la zone de travail
CP A, 1 ; Pas d' OPTION, donc affichage rapide Effet=1
JR Z, EFFET_01 ; SE DIRIGER Vers l'Option desiree
LD A, (IX + 2) ; Lire le numero de l'OPTION
CP 1 ; Si OPTION=1 alors affichage normal
JR Z, EFFET_01
CP 2 ; Si OPTION=2 alors Rotation GD
JR Z, EFFET_02
CP 3 ; Si OPTION=3 alors rotation HB
JR Z, EFFET_03
CP 4 ; Si OPTION=4 alors rotation HB GD
JR Z, EFFET_04 ;
JP EFFET_01 ; Sinon ERREUR donc affichage normal
EFFET_01 ; EFFET NUMERO 1 AFFICHAGE SIMPLE
LD BC, 16 ; Option 1, On va simplement transferer les 16 Octets du MaxiCHR
LDIR ; vers la zone de travail... Voila c'est fait
JP MAXICHR_OK ; Reste plus qu'a afficher le MaxiCHR
EFFET_02 ; ROTATION GAUCHE DROITE GD
EX HL, DE ; On echange les deux registres car 'HL' est plus adapte pour cette tache
LD C, 16 ; 16 Lignes de hauteur = 16 Octets du MaxiCHR
EFFET_GD_LIGNES
LD B, 8 ; Il faut faire tourner les 8 Bits de chaques octets
LD A, (DE) ; 'A' contient l'octet a modifier
EFFET_GD_8BITS
RRA ; 'A' est pousse vers la droite, et le BIT 0 va dans le 'CARRY'
RL (HL) ; '(HL)' est pousse vers la gauche et le BIT 0 recupere le 'CARRY'
DJNZ, EFFET_GD_8BITS
INC DE
INC HL
DEC C
JR NZ, EFFET_GD_LIGNES
JP MAXICHR_OK ; Une fois les 16 octets operes, on peut afficher le MaxiCHR
EFFET_03 ; ROTATION HAUT BAS HB
LD DE, Caractere + 15 ; 'DE' pointe ver la zone de travail + 16 (0 a 15) situee en bas
LD B, 16 ; 16 lignes a transferer
EFFET_HB_LIGNES
LD A,(HL) ; 'A' contient l'octet a transferer
LD (DE), A ; Qui est inscrit en partant du bas vers le haut
INC HL
DEC DE
DJNZ, EFFET_HB_LIGNES
JP MAXICHR_OK ; Les 16 octets sont transferes, on affiche le MaxiCHR
EFFET_04 ; ROTATION 90 DEGRES HBGD
LD DE, Caractere + 15 ; On fait les deux options en meme temps
EX HL, DE ; 'HL' pointe sur la zone de travail + 16
LD C, 16 ; 'DE' est la source. 16 octets a traiter
EFFET_HBGD_LIGNES
LD A, (DE) ; 'A' Contient l'octet source
LD B, 8 ; Et on va tourner les 8 BITS pour les transferer dans 'HL'
EFFET_HBGD_8BITS
RRA RL (HL)
DJNZ, EFFET_HBGD_8BITS
DEC HL
INC DE
DEC C
JR NZ, EFFET_HBGD_LIGNES ; Les 16 octets sont tournes puis tranferer du bas vers le haut
JP MAXICHR_OK MAXICHR_OK
LD A, (Curseur) ; Regarder si on peut l'afficher en bas de l'ecran
CP A, 15
RET C ; Si A < 15 alors on n'affiche pas et on sort
LD A, 1
LD (Zoom + 1), A ; On inscrit la hauteur du ZOOM VERTICAL avant d'appeler la routine
LD A, 16 ; On inscrit aussi le nombre de ligne (8=caractere et 16=MaxiCHR)
LD (CarCHR + 1), A
LD A, 136
LD (RotCou + 1), A ; Rotation (10001000) A chaque 1, les couleurs changes
CALL AfficheCarCHR ; Et on affiche le caractere en appelant la sous routine
RET
NOP
La dernière routine avant la création des RSX.
Cette routine est un peu longue mais au début on recherche l'adresse du MaxiCHR à afficher puis si il il y a une option qui doit être effectuée avant l'affichage et on oriente le programme en conséquence.
On va donc raccourcir directement sur les options possibles.
Option 1:
La c'est très simple, on inscrit la matrice que l'on veut afficher dans la zone de travail et on dirige le programme vers l'affichage.
L' instruction 'LDIR' transfert le nombre d'octets voulu du registre 'HL' vers le registre 'DE'
Comme 'HL' pointe sur le MaxiCHR et 'DE' pointe sur la variable 'Caractere', on a plus qu'à inscrire dans 'BC' le nombre d'octets à transférer et à lancer l'instruction 'LDIR' puis de sauter vers la suite du programme.
Option 2:
Cette fois on va faire subir une rotation horizontal au MaxiCHR.
Pour cette option, on a besoin de deux instructions pour faire tourner les BITs de chaque lignes du MaxiCHR
On place d'abord dans le registre 'A' la ligne à traiter, puis on lui fait faire une rotation vers la droite afin de récupérer dans le 'CARRY' la valeur du BIT 0 du registre 'A'
On injecte dans le contenu de 'HL' ce BIT en lui faisant subir une rotation vers la gauche.
Les images parlent mieux:
L' instruction 'RRA' récupère le BIT 0 du registre 'A' dans le 'CARRY' et fait tourner son contenu vers la droite. Et l'instruction 'RL (HL)' fait tourner le contenu du registre 'HL' vers la gauche et injecte le 'CARRY' dans le BIT 0. En effectuant cette opération 8 fois de suite, on fait faire une rotation horizontale du contenu du registre 'HL'. Et on répète aussi l'opération pour parcourir les 16 lignes du MaxiCHR avant de sauter vers la suite du programme.
Option 3:
La rotation verticale est assez simple à faire. Au lieu de faire pointer la destination sur la variable 'Caractere' on va la faire pointer 15 octets plus loin. Et on inscrira la valeur de chaque ligne dans les sens inverse en décrémentant le registre 'DE' de sorte que la dernière ligne du MaxiCHR se retrouve sur la première ligne de la zone de travail. On sautera à la suite du programme pour finir.
Option 4:
Ici il s'agit de faire l'option 2 et l'option 3 en même temps. Ce qui ne devrait pplus être un problème maintenant.
Il y a plein de possibilités si vous voulez aller plus loin, comme par exemple afficher un MaxiCHR à l'orizontal, mais ce n'est pas le but de mon programme que je voulais de moins de 1 Koctet une fois assemblé.
Le reste du programme parle de lui même. Une fois les variables définies, on affiche le MaxiCHR grâce à la sous routine 'AfficheCarCHR'.
Cette routine ne déplace pas le curseur, c'est voulu pour la rendre plus rapide et dans ma logique, ce n'est pas une routine pour afficher plusieurs MaxiCHR les uns derrières les autres.
Il nous reste à voir comment implanter les RSX.; ########## ########## ########## ##########
; MISE EN PLACE DES RSX : CALL &A22C
FIXERLESRSX
LD A, #C9 ; Un Retour au basic sera effectue pour ne pas rappeler la routine
LD (FIXERLESRSX), A ; des RSX en inscrivant 'C9' a l'adresse de l'appel
LD BC, AdrNomsRSX ; 'BC' pointe sur l'adresse des noms des RSX
LD HL, BuffetRSX ; 'HL' pointe sur un buffet de 4 octets reserve par la routine
JP #BCD1 ; Fabuleuse routine qui fixe les RSX
AdrNomsRSX DW NOMSdesRSX ; 2 octets qui stocks l'adresse des noms
JP RSXENCRE ; Suivis d'autant de sauts vers les routines
JP RSXPAPIER ; Qu'il y a de noms de RSX dans le meme ordre
JP RSXCURSEUR
JP RSXGCURSEUR
JP RSXAFFICHE
JP RSXDEFMAXICHR
JP RSXMAXICHR
BuffetRSX DS 4 ; Zone de 4 Octets reserves par le vecteur RSX #BCD1
NOMSdesRSX ; Adresse des noms des RSX
STR "ENCRE" ; Chaque nom devraient finir par un + #80
STR "PAPIER" ; Mais WinApe le fait pour nous
STR "CURSEUR" ; Exemple pour la commande 'CURSEUR'
STR "GCURSEUR" ; DEFB "CURSEU", "R" + #80
STR "AFFICHE"
STR "DEFMAXICHR"
STR "MAXICHR"
NOP
Au lancement, on empêchera de rappeler la routine en plaçant l'instruction de 'RET' qui effectue un retour vers le basic. Je ne sais pas si c'est vraiment utile, mais dans le sens ou la construction des RSX sera effectuée, je ne vois pas trop l'utilité de rappeler cette routine. Peut être pour pouvoir changer le nom des RSX grâce à une routine prévue pour ça... Bref
Le Vecteur &BCD1 a besoin de 2 variables (ou adresses) dans les registres pour pouvoir s'orienter vers les RSX à définir.
Le registre 'BC' doit pointer sur 2 octets qui doivent contenir l'adresse ou sont stockés les noms des RSX.
Le registre 'HL' doit pointer sur 4 octets de libres que le vecteur &BCD1 utilisera pour son fonctionnement.
Ensuite on exécute le vecteur &BCD1 en faisant directement un saut.
En dessous, j'y ai mis les 2 octets qui contiennent l'adresse vers les noms des RSX suivis des sauts à effectuer pour chacun des RSX.
Entre les sauts et les noms, j'ai programmé le buffet de 4 octets utilisé par le vecteurs &BCD1. Puis viennent naturellement les noms de chaque RSX.
C'est terminé avec les Maxi Caractères et MaxiCHR. D'autres projet suivront !
✔ Vous avez la possibilité de redéfinir vos 23 MaxiCHR et d'en faire une sauvegarde avec les RSX. Pour ce fait, une fois redéfinis, tapez: SAVE"MAXICARA.BIN", b, &A000, &400. Elle n'est pas belle la vie 😁
Contenu du fichier 'MaxiCaracteres.ZIP'
MaxiCaracteres.ZIP (Contenu)
Maxi caracteres - RSX.ASM ; Fichier assembleur des RSX
Maxi caractere - matrice x 23.ASM ; Fichier de définition des 23 MaxiCHR prêt à l'emploi
MaxiCara.DSK ; Disquette AMSTRAD contenant les programmes
ALIRE.BAS ; Fichier expliquant l'utilisation des RSX
DEMO.BAS ; Petite démo rapide
MAXICARA.BIN ; Fichier binaire des RSX
IMPLANT.BAS ; Programme d'implantation du code binaire
Téléchargement: MaxiCaracteres.ZIP