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 » A Guide to EPROMs on the CPC (2/4)
» Coding Src's » Rom Kopie Ins Ram (CPC Amstrad International)
» Coding » Cours et Initiation MICROMAG
» Coding » Clefs1 59 - Tables des Valeurs Chromatique
» Coding Src's » SDCC ROM development template for Linux / Windows
» Coding » L'assembleur en Douceur (5/x) : Les modes d'adressage (Micro-Mag)
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 191 millisecondes et consultée 3384 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.