Revenir au plan du site
Utilisation des ROM sur CPC/Plus/GX
L'Amstrad CPC est capable de gérer 4Mo de ROM sans bidouille. Oui, vous avez bien lu, 4 méga-octets... Le calcul est assez simple, il peut sélectionner 256 ROM hautes de 16k (à laquelle
on peut ajouter une ROM basse mais les puces mémoire étant des puissances de 2 en capacité, c'est souvent la ROM haute zéro qui est mappée en tant que ROM basse).
Sur la gamme Plus/GX, on considère que la limitation est de 2Mo car l'ASIC utilise les valeurs de 128 et plus pour distinguer les ROM classiques de la cartouche. Il reste néanmoins capable d'adresser des ROM
de 0 à 127 de façon classique si on lui met une ROM-board aux fesses. Et on s'occupera des histoires de cartouche un autre jour ^_^
Les ROM activées ont priorité en lecture sur la mémoire (on peut continuer à écrire dans la mémoire "dessous"). Lorsque les ROM ou l'ASIC sont actifs, vous devez faire
attention à l'emplacement du pointeur de pile dans l'espace mémoire. Si l'écriture reste possible, toute lecture se fera avec la priorité pour la ROM ou la page ASIC.
Que peut-on mettre dans les ROM ?
Hé bien contre toute attente, on peut mettre ce qu'on veut! Des données, du code et il est possible d'exécuter du code directement sans le copier en mémoire. Je précise qu'on peut le faire
car l'usage majoritaire des ROM actuellement consiste surtout à copier des données, éventuellement compressées, vers la mémoire. La ROM c'est bien plus que ça!
Concernant l'exécution directe de code depuis la ROM, quelques contraintes s'imposent :
- Il n'est pas possible de modifier le code (donc pas d'automodification)
- Il n'est pas possible de lire la mémoire sous le mapping de la ROM en cours
Des générations de codeurs sur console s'en sont très bien sortis pendant des décennies, pas d'inquiétude à avoir. Pour les compteurs et variables, il faut les mettre
ailleurs en mémoire. Par contre, concernant un code qui aurait besoin de lire la mémoire "sous" la ROM, il vaut mieux copier ce code une fois pour toutes en mémoire
et désactiver la ROM, sinon on va se heurter à d'incessants jonglages de connexions et brider les performances.
Un exemple concret avec notre routine d'affichage de texte ?
Dans l'article précédent, la fonte et le code était en mémoire vive. Voyons voir comment adapter notre code pour loger la routine et les données dans une ROM et gagner le plus possible de place en mémoire vive.
Dans notre cas, il y aura seulement à positionner la variable
position_char en mémoire vive, tout le reste est déjà en lecture seule. Nous économisons presque 4k de mémoire vive comme nous l'indique
RASM lors de la compilation dans le log d'export du snapshot.
WriteSNA ROM 15 of 3982 bytes start at #C000
|
Pour la connexion ROM, il faut activer les roms hautes avec le RMR et choisir le numéro de la ROM haute active avec le port idéal #DFxx. On utilisera le préfixe {bank} suivi d'un label pour
récupérer le numéro de la ROM contenant ce label!
RMR ROM_UP | MODE_1 ; activer la ROM haute + Mode 1
ld bc,#DF00+{bank}affiche_caractere : out (c),c ; sélectionner la ROM qui contient la routine, la fonte, le message
|
Vous aurez besoin du
[ binaire de la fonte ] pour assembler ce source
BUILDSNA : BANKSET 0
ORG #100 : RUN #100 : LD SP,#100
MODE_0 equ 0 : MODE_1 equ 1 : MODE_2 equ 2 : MODE_3 equ 3 : CLEAR_INT equ %10000
ROM_OFF equ %1100 : ROM_BOTH equ 0 : ROM_UP equ %100 : ROM_LOW equ %1000 : INTRESET equ %10000
macro RMR tags : ld a,{tags}+%10000000 : ld b,#7F : out (c),a : mend
ld bc,#7F00 : out (c),c : ld a,#58 : out (c),a : ld c,#10 : out (c),c : out (c),a
ld bc,#7F01 : out (c),c : ld a,#49 : out (c),a
RMR ROM_UP | MODE_1 ; activer la ROM haute + Mode 1
ld bc,#DF00+{bank}affiche_caractere : out (c),c ; sélectionner la ROM qui contient la routine, la fonte, le message
ld hl,message : call affiche_chaine
jr $
position_char defw #C000 ; besoin d'avoir cette VARIABLE en mémoire vive pour la modifier
ROMBANK 15 ; peu importe le numéro!
org #C000 ; par contre une ROM haute commence TOUJOURS en #C000!
affiche_chaine
ld a,(hl) : inc hl ; récupérer la valeur dans le tableau et incrémenter le pointeur
cp #FF : ret z ; terminateur?
push hl : call affiche_caractere : pop hl ; on a besoin de conserver notre pointeur HL
jr affiche_chaine
affiche_caractere
; nos caractères font 48 octets
add a : ld h,0 : ld l,a : add hl,hl : add hl,hl : add hl,hl ; x 16
ld bc,hl : add hl,hl : add hl,bc ; x 48
ld bc,fonte : add hl,bc ; HL=adresse des données du caractère dans le tableau fonte
ld de,(position_char) ; on récupère la position du curseur
ld xl,16 ; nombre de lignes
ld bc,#10FF ; le LDI décrémente BC donc on charge C au maximum pour que B puisse servir de compteur
affiche_ligne_caractere
push de : ldi 3 : pop de
ld a,d : add 8 : ld d,a : and #38 : jr nz,.noOVF
ld a,80 : add e : ld e,a : ld a,#C0 : adc d : ld d,a : res 3,d
.noOVF
djnz affiche_ligne_caractere
; avancer le curseur
ld hl,(position_char) : inc hl : inc hl : inc hl : ld (position_char),hl
ret
charset ' ABCDEFGHIJKLMNOPQRSTUVWXYZ!()*+,-./0123456789:;<=>?@_abcdefghijklmnopqrstuvwxyz#',0
message defb 'Oh la belle fonte!',#FF
charset
fonte incbin 'simpleFonte.bin'
|