CODING ★ CRÉATION D'UNE ROM SUR CPC|MASTERGLOB) ★

Création d'une ROM sur CPC (Masterglob)Menu - Soft - ROM
Description du format d'une ROM, pour qu'elle soit reconnue est installée automatiquement au démarrage du BASIC

Description:

Les ROMs (upper ROM) sont situées en mémoire de &C000 a &FFFF. Pour sélectionner et activer une ROM particulière, reportez-vous aux articles sur le GATE ARRAY ici et sur l'activation des ROMS ici

Pour être reconnue par le CPC,

Le premier octet de la ROM doit être &01. Ceci indique au BASIC que cette ROM contient un programme qui sera exécuté en tâche de fond (Background), contrairement à la ROM BASIC qui contient la valeur &80 pour indiquer qu'il s'agit de la tâche princiaple (FOREGROUND)

Des informations complémentaires, mais non indispensables sont les 3 octets suivants. Ils correspondent au numéro de version de la ROM.

Exemple pour la version 1.23 il faudra mettre les octets &01 &02 &03. Toutes ces informations peuvent être visualisées à l'aide par exemple de la ROM Maxam 1.5, grâce à la commande ùHELP.

Les 2 octets suivants doivent donner l'adresse de la table des commandes externes définies par la ROM.

Ensuite se trouve la table des adresses à exécuter, correspondant à la table décrite précédemment.

Ces 2 informations ont le même format que celui utilisé par le CALL &BCD1, à savoir:

La table est composée d'entrées dont les noms sont des chaînes de caractères dont la fin est déterminée lorsque la valeur d'un caractère est supérieure à &7F

Un Octet &00 est placé à la fin de la table.

Exemple, pour une ROM avec 3 commandes externes:

org &c000
; DEFB &01 ; bg ROM
; DEFB &07,&04,&01 ; Version 7.41
; DEFW RSX_TABLE ; Adresses des noms des Commandes externes
.JUMP_TABLE
; JP INIT_ROM ; Adresse d'execution lors du demarrage
; JP COMMANDE1
; JP COMMANDE2
; JP COMMANDE3
.RSX_TABLE
; TEXT "INITIALISE MA RO","M"+&80
; TEXT "COMMANDE","1"+&80
; TEXT "COMMANDE","2"+&80
; TEXT "COMMANDE","3"+&80
; DEFB 0 ; FIN

On remarquera en particulier qu'il y a en réalité 4 commandes déclarées: "COMMANDE1","COMMANDE2","COMMANDE3" et "INITIALISE MA ROM". La première commandes déclarée (dans notre exemple "INITIALISE MA ROM") va être automatiquement appelée par le BASIC lors du démarrage et sera donc la commande d'initialisation de la ROM. Il est recommandé d'utiliser pour cette commande externe un nom de commande qui ne pourra pas être utilisé en BASIC, comme c'est le cas ici à cause des espaces. Ceci évidemment dans le but d'éviter d'appeler plusieurs fois la commande d'initialisation.

Comme vous l'avez compris, après avoir automatiquement installé vos commandes externes, le BASIC va exécuter la première commande décrite par la ROM à savoir ici: "INITIALISE MA ROM".

Pour être installée correctement par le CPC,

Cette première commande externe doit répondre à certaines obligations.

En entrée, HL contient l'adresse jusqu'à laquelle la mémoire est libre. Si la seule autre ROM utilisée est AMSDOS, alors HL vaudra &A700, car AMSDOS et le BASIC utilisent la zone mémoire de &A700 a &BFFF.

En sortie, HL contient l'adresse jusqu'à laquelle la mémoire est libre. Cette valeur tient désormais compte de la mémoire nécessitée par la ROM. Par exemple si la ROM requiert 9 octets en RAM pour stocker des informations, il faudra retourner dans HL sa valeur en entrée moins 9. Les autres registres (sauf AF) ne doivent pas être affectés. De plus si l'initialisation s'est bien passée alors il faut positionner le Carry à 1. Dans le cas contraire (pas assez de mémoire par exemple) alors mettre le carry à 0.

En retour, le BASIC va tenir compte de cette nouvelle valeur pour la prochaine ROM à installer (sachant que le BASIC cherche d'abord à installer la ROM 7, puis 6, etc, jusqu'à 0). Bien sur, plus la ROM nécessite de RAM pour être utilisée, plus la valeur Max de HIMEM en BASIC va diminuer.

Exemple complet :

; Cette ROM definit les commandes:
; ùAZERTY qui change le mapping des touches en RAM pour simuler un clavier azerty
; ùQWERTY qui change le mapping des touches en RAM pour simuler un clavier qwerty
; ùABOUT qui affiche un message.
org &c000
; DEFB &01 ; bg ROM
; DEFB &01,&00,&00 ; Version 1.00
; DEFW RSX_TABLE ; Adresses des noms des Commandes externes
; JP INIT_AZERTY ; Adresse d'execution lors du demarrage
; JP AZERTY
jp QWERTY
jp ABOUT
.rsx_table
; text "INIT CLAVIE","R"+&80
; text "AZERT","Y"+&80
; text "QWERT","Y"+&80
; text "ABOU","T"+&80
; defb 0 ; FIN
.init_AZERTY
push hl
; PUSH DE
call AZERTY
pop DE
pop hl
ret
.AZERTY
ld hl,TABLE_AZERTY
call COPIE_TABLE
ret
.QWERTY
ld hl,TABLE_QWERTY
.COPIE_TABLE
ld BC,CHAR_TABLE_LEN
ld DE,CHAR_TABLE
ldir
ret
.ABOUT
ld hl,ABOUT_TEXT1
.textout
ld a,(hl)
call &BB5A
inc hl
or a
jr nz,textout
ret
.ABOUT_TEXT1
text "Transcription des touches pour clavier AZERTY",10,13
text "Par Masterglob, 2004",10,13,0
.TABLE_AZERTY
db &F0 ,&F3 ,&F1 ,&89 ,&86 ,&83 ,&8B ,&8A ,&F2 ,&E0 ,&87 ,&88 ,&85 ,&81 ,&82 ,&80
db &2A ,&5B ,&0D ,&24 ,&84 ,&FF ,&32 ,&FF ,&3D ,&29 ,&A0 ,&70 ,&7C ,&2C ,&21 ,&3A
db &40 ,&5E ,&6F ,&69 ,&6C ,&6B ,&6D ,&3B ,&5F ,&60 ,&75 ,&79 ,&68 ,&6A ,&6E ,&20
db &2D ,&28 ,&72 ,&74 ,&67 ,&66 ,&62 ,&76 ,&27 ,&22 ,&65 ,&77 ,&73 ,&64 ,&63 ,&78
db &26 ,&23 ,&FC ,&71 ,&09 ,&61 ,&FD ,&7A ,&10 ,&2A ,&2F ,&2D ,&2B ,&3C ,&FF ,&7F
db &F4 ,&F7 ,&F5 ,&89 ,&86 ,&83 ,&8B ,&8A ,&F6 ,&E0 ,&87 ,&88 ,&85 ,&81 ,&82 ,&80
db &75 ,&7B ,&0D ,&A3 ,&84 ,&FF ,&6E ,&FF ,&2B ,&30 ,&A2 ,&50 ,&25 ,&3F ,&A6 ,&2F
db &30 ,&39 ,&4F ,&49 ,&4C ,&4B ,&4D ,&2E ,&38 ,&37 ,&55 ,&59 ,&48 ,&4A ,&4E ,&20
db &36 ,&35 ,&52 ,&54 ,&47 ,&46 ,&42 ,&56 ,&34 ,&33 ,&45 ,&57 ,&53 ,&44 ,&43 ,&58
db &31 ,&32 ,&FC ,&51 ,&09 ,&41 ,&FD ,&5A ,&10 ,&2A ,&2F ,&2D ,&2B ,&3E ,&FF ,&7F
db &F8 ,&FB ,&F9 ,&89 ,&86 ,&83 ,&8C ,&8A ,&FA ,&E0 ,&87 ,&88 ,&85 ,&81 ,&82 ,&80
db &00 ,&1B ,&0D ,&A4 ,&84 ,&FF ,&00 ,&FF ,&7D ,&5D ,&00 ,&10 ,&00 ,&00 ,&00 ,&00
db &40 ,&5E ,&0F ,&09 ,&0C ,&0B ,&0D ,&00 ,&5C ,&60 ,&15 ,&19 ,&08 ,&0A ,&0E ,&FF
db &7C ,&5B ,&12 ,&14 ,&07 ,&06 ,&02 ,&16 ,&7B ,&23 ,&05 ,&17 ,&13 ,&04 ,&03 ,&18
db &FF ,&7E ,&FC ,&11 ,&E1 ,&01 ,&FE ,&1A ,&10 ,&2A ,&2F ,&2D ,&2B ,&00 ,&FF ,&7F
db &07 ,&03 ,&4B ,&FF ,&FF ,&FF ,&FF ,&FF ,&AB ,&BF ,&01 ,&30 ,&01 ,&31 ,&01 ,&32
db &01 ,&33 ,&01 ,&34 ,&01 ,&35 ,&01 ,&36 ,&01 ,&37 ,&01 ,&38 ,&01 ,&39 ,&01 ,&2E
db &01 ,&0D ,&05 ,&52 ,&55 ,&4E ,&22 ,&0D

Vous allez demander: "Comment peut-on récupérer l'adresse de la zone mémoire que le système nous a attribué?"

S'il s'agit de la fonction d'initialisation, nous connaissons déjà la réponse puisque c'est grâce au registre HL que nous pouvons choisir son emplacement.

Lorsque une commandes externe ùCOMMANDE1 est appelée depuis le BASIC, les conditions d'entrée dans la routine sont les suivantes:
1. IX Contient la liste des paramètres (IX+&00),(IX+&01) contient l'adresse ou la valeur du dernier paramètre, (IX+&02),(IX+&03) l'adresse de l'avant dernier etc...
2. A contient le nombre de paramètres
3. IY contient l'adresse mémoire du début de la zone réservée à la ROM en RAM.
4. C contient le numéro de la ROM (0..7)

Autre exemple:

org &c000
; DEFB &01 ; bg ROM
; DEFB &07,&04,&01 ; Version 7.41
; DEFW RSX_TABLE ; Adresses des noms des Commandes externes
.JUMP_TABLE
; JP INIT_ROM ; Adresse d'execution lors du demarrage
; JP ECRIT
; JP LIT
.RSX_TABLE TEXT "INITIALISE MA RO","M"+&80
; TEXT "ECRI","T"+&80
; TEXT "LI","T"+&80
; DEFB 0 ; FIN
.INIT_ROM
; DEC HL
; DEC HL
; RET
.LIT
; OR A
; RET Z ;On ne fait rien si il n'y a pas de parametres
; LD H,(IX+1) ; Lecture du parametre
; LD L,(IX+0)
; LD (IY+1),H ; Ecriture du parametre en memoire
; LD (IY+0),L
; RET
.ECRIT
; LD A,1
; CALL &BB5A
; LD A,(IY+1) ; Lecture du parametre
; CALL &BB5A
; LD A,1
; CALL &BB5A
; LD A,(IY+0) ; Lecture du parametre
; CALL &BB5A
; RET

Plus compliqué:

Imaginons maintenant que le but de la ROM soit de surcharger des routines systèmes, via les vecteurs d'interruption. Par exemple, vous voulez écrire un programme qui utilise une autre ressource que la cassette ou AMSDOS pour lire/écrire dans des fichiers (RAM DISC par exemple).

Nous allons traiter un exemple simple ou la ROM va surcharger les routines basic de gestion des fichiers (&BC77 à &BC9B) et afficher "Aujourd'hui j'ai pas envie de travailler" au lieu de faire ce qu'on lui demande:

org &c000
; defb &01 ; bg ROM
; defb &01,&00,&00 ; Version 1.0
; defw rsx_table ; Adresses des Commandes externes
; JP INIT_ROM ; Adresse d'execution lors du demarrage
; JP FATIGUE ;
.rsx_table text "INIT MA RO","M"+&80
; text "FATIGU","E"+&80
defb 0 ; FIN
; INIT_ROM reserve 3 octets en RA et y inscrit
; l'adresse de p_func_sel et le numéro de la ROM courante
.INIT_ROM
push bc
push DE
ld de,-3 ; Place reservee en RAM
add hl,de
push hl
ld de,p_func_sel ; Adresse de la routine de selection de fonction
inc hl
ld (hl),e
inc hl
ld (hl),d
inc hl
call &b912 ;Get ROM number into A register
ld (hl),a
pop hl
; POP DE
pop bc
; scf
ret
;FATIGUE change les vecteurs d'interruption de gestion des fichiers
.fatigue
ld hl,coucou_t
call textout ; Affiche un texte
push IY ; Sauve l'adresse des donnees en RAM
pop de ; et recuperation dans DE
; En ecrivant &DF puis la valeur de IY qui contient
; maintenant l'adresse de p_func_sel on va demander
; au systeme d'executer le code en p_func_sel
; Nota; toutes ces fonction peuvent etre reactivees correctement
; avec ùDISC ou ùTAPE qui fait le meme genre
; de traitement
ld hl,&BC77 ; override BASIC function
ld b,13 ; 13 functions
.fatigue1
ld (hl),&DF
inc hl
ld (hl),e
inc hl
ld (hl),d
inc hl
djnz fatigue1
ret
; Cette fonction recupere l'argument dans
; la pile correspondant à l'adresse d'execution
; de la fonction demandee et l'execute
; Le principe est de determiner l'adresse
; du call qui a ete effectue (exemple CAT => call &BC9B)
; et d'en deduire quelle fonction appeller.
; COmme la table des appels ci-dessous est dans le
; meme ordre que celle de &BC77 a &BC9B,
; on a simplement une translation à faire sur l'adresse demandee.
.p_func_sel
di
ex af,af'
exx
ld a,c
pop de
pop bc
pop hl
ex (sp),hl
push bc
push de
ld c,a
ld b,&7F
; pour HL=&bc9e (fonction Cat ) il faut avoir jp_cat
ld de,jp_cat-&bc9e
add hl,de
push HL ;adresse to jump
exx
ex af,af'
ei
jp #BE7F ; execution...
; Overriding BASIC functions
.jp_1rst_block_read jp greve ;&bc77
.jp_close_file jp greve ;&bc7a
.jp_cancel_i_file jp greve ;&bc7d
.jp_read_char jp greve ;&bc80
.jp_read_file jp greve ;&bc83
.jp_unread_char jp greve ;&bc86
.jp_test_EOF jp greve ;&BC89
.jp_openout ;jp greve ;&BC8C
.jp_closeout jp greve ;&BC8F
.jp_cancel_o_file jp greve ;&bC92
.jp_write_char jp greve ;&BC95
.jp_write_file jp greve ;&BC98
.jp_cat ;jp greve ;&BC9B
.greve
ld hl,texte2
call textout
; Pour signaler au systeme que la commande a echoue ( a cause de la greve)
; on positionne C a 0
xor a
ret
.textout
ld a,(hl)
inc hl
or a
ret z
push af
and &7f
call &bb5a
pop af
and &80
jr z,textout
ret
.coucou_t text "C'est la greve",10,13,#80
.texte2 text "Non on ne veut pas travailler!",10,13,#80

Sur cet exemple, on s'est amusé à faire un traitement compliqué alors que finalement, tous les vecteurs surchargés appellent la même procédure
(greve). Le but était de montrer comment pouvoir distinguer simplement quel vecteur est utilisé.

A noter que la routine p_func_sel n'est pas de moi, elle est intégralement recopiée d'une ROM surchargeant ces vecteurs pour l'émulateur (ROM CPCDOS). Donc ne m'en voulez pas si elle parait un peu compliquée... Elle est cependant nécessaire pour appeler une routine qui se trouve dans une ROM. Si le programme avait été recopié en RAM par exemple, on aurait pu se contenter d'écrire JP MA_ROUTINE_CAT en &BC9B,etc ...

L'intérêt de ce genre de manipulation est qu'un ùDISC, ùTAPE (ou ùDOS sous émulateur, ou ùPCDISC pour les connaisseurs) réinitialise la table des vecteurs, étant donné que les autres ROMs procèdent de la même façon.

N'hésitez pas à faire vos suggestion à Masterglob

http://site.voila.fr/masterglob/CPC ( Attention le site est HS pour le moment)

★ ANNÉE: ???
★ AUTEUR: MasterGlob

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding » De port en port : Programmation du contr├┤leur de disquettes ├á travers les ports [1/2] (Micro-Mag)
» Coding » Clefs1 59 - Tables des Valeurs Chromatique
» Coding » Initiation à L'Assembleur Amstar&CPC 28 - Architecture et Composition des Rsx
» Coding » De port en port : Programmation directe du clavier (Micro-Mag)
» Coding » ROM-Listings im Vergleich (Happy Computer)
» Coding » Rsx - Variable Locales et Recursivite (CPC Infos)
Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop
Page créée en 942 millisecondes et consultée 2666 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.