Retourner au sommaire

La Multiface Two

Basé sur les articles publiés dans Quasar CPC numéro 20 et numéro 21, Assembleur : Hardware, par OffseT.

Voici un petit dossier expliquant de façon détaillée comment fonctionne la fameuse Multiface Two de chez Romantic Robot, comment elle se programme et enfin quels outils existent pour celle-ci.

Le fonctionnement de la MF2

Les présentations

Une Multiface Two Je pense que la plupart d'entre vous connaissent déjà le principe de fonctionnement de ce petit bijou, mais une bonne mise au point n'est jamais superflue. Tout d'abord, vous devez savoir que la Multiface Two n'est pas la première interface de ce type produite sur CPC ; avant, il y a par exemple eu le non moins célèbre Mirage Imager. Néanmoins, la Multiface Two, sortie en 1988, demeure sans nul doute la plus aboutie. Le petit blond à lunettes trépigne d'impatience… mais que fait donc cette interface ?

C'est en quelque sorte un observateur du fonctionnement du CPC. Elle mémorise en permanence tous les accès aux principaux circuits du CPC (PPI, CRTC, Gate Array) afin, lorsque vous l'activez, d'en permettre l'édition… mais aussi et surtout de retourner au programme interrompu dans l'état où vous l'aviez laissé. En effet, ceci est en temps normal tout bonnement impossible. Puisque vous changez l'état du système lorsque vous l'interrompez et que la plupart des registres des circuits du CPC ne sont pas accessibles en lecture, vous n'avez absolument aucun moyen de pouvoir en restituer les valeurs initiales.

Comment ça marche ?

Techniquement, la Multiface Two est composée de trois organes. Tout d'abord, il y a les circuits logiques qui servent essentiellement à l'observation du CPC. Ces circuits (trois PAL) stockent le résultat de leurs observations (valeurs en cours des registres du PPI, du CRTC, du Gate Array) dans une RAM de 8ko, c'est notre deuxième organe. Enfin, il y a une ROM de 8ko qui contient le programme de gestion de la Multiface Two ; celle-ci, ainsi qu'une grande partie de la RAM, n'est donc utilisée (exécutée) que lorsque vous activez l'interface via son bouton STOP. L'autre bouton, le RESET, ne fait rien d'autre qu'un reset hard complet du CPC (mise à la masse du signal /BUS_RESET du port expansion).

Les possibilités

La présence d'une RAM de taille conséquence ouvre, du fait du judicieux code implémenté dans la ROM, de nombreuses possibilités. Mais, nous allons tout d'abord nous attacher aux fonctionnalités offertes par le programme en ROM lui-même.

Lorsque vous appuyez sur le bouton STOP, la Multiface Two fait plusieurs choses. En premier lieu, elle génère une NMI (interruption non masquable). Sitôt l'interruption prise en compte par le Z80 et avant qu'elle ne soit traités (RST &66), elle commute alors sa ROM entre &0000 et &1FFF et sa RAM entre &2000 et &3FFF. Dès lors, le Z80 part sur le code en &66 : c'est celui de la ROM de l'interface ; le tour est joué.

La Multiface Two vampirise votre CPC ! Une fois la ROM en route, elle commence par sauver dans la RAM de l'interface tout ce qui ne l'a pas déjà été automatiquement via la logique hardware (les trois PAL). Les registre du Z80, les registres du AY, l'interruption Gate Array en cours, etc.. Oui, oui, oui, le petit blond à lunettes a raison, c'est en fait plus compliqué que ça, mais je schématise car notre objectif est avant tout l'utilisation de la Multiface Two et non son fonctionnement intime. Bref, après avoir sauvé tout ce qui pouvait l'être, la Multiface Two consulte quelques octets dans sa RAM afin de savoir si un programme utilisateur y est installé en mode “Direct Jump”, si tel est le cas, elle lui donne aussitôt la main et n'aura plus qu'à s'occuper de la restitution des paramètres système et hardware pour gérer le retour au programme stoppé lorsque le programme utilisateur aura rendu la main. En d'autres termes, les autres parties du code de la ROM ne sont pas exécutées. Le plus connu et le plus performant de ces programmes est The Insider, développé par Romantic Robot. Nous reviendrons plus tard sur le comment de l'installation de tels programmes dans la mémoire de la Multiface Two. En outre, dans le cas où le programme utilisateur stocké en RAM serait défaillant ou que l'on voudrait tout simplement l'annuler sans avoir à le déprogrammer à la main ou à mettre le CPC hors tension, si une touche du clavier est enfoncée lorsque vous activez la Multiface Two, celle-ci l'ignorera et exécutera son code en ROM normalement.

D'ailleurs, qu'avons-nous dans ce code en ROM par défaut ? Eh bien, nous avons un menu avec diverses options pour éditer ou sauvegarder sur disque la RAM ainsi que les divers paramètres en cours dans le programme interrompu (valeurs des registres du CRTC, couleurs, etc.). Nous avons également un curieux menu “Jump”… celui-ci nous permet d'exécuter un programme installé dans la RAM de la Multiface Two en mode “Indirect Jump”. L'avantage d'installer un programme de cette manière est qu'il vient s'ajouter aux fonctionnalités de l'outil présent en ROM. Mais, en contre partie, du fait que le code en ROM utilise une bonne partie des 8ko de RAM, il ne reste que peu de place contrairement à une installation en “Direct Jump”.

La mémoire de la MF2

Maintenant que nous avons vu les grandes lignes du fonctionnement matériel et logiciel de la Multiface Two, nous allons nous intéresser à sa RAM qui est la clef de sa programmation. La mémoire intégrée à l'interface est accessible de deux manières différentes. Via l'outils de la ROM après que la Multiface Two ait été activée, la mémoire vue entre &2000 et &3FFF est soit celle de la MF2 (Multiface Two), soit celle du CPC selon la configuration choisie (touche M sur les claviers azerty). Il faut bien l'admettre, si nous n'avions pas d'autre moyen d'accès à cette RAM, cela limiterait sérieusement les possibilités de programmation de l'interface. Mais, comme l'a judicieusement constaté le petit blond à lunettes, tous les programmes s'installant dans la MF2 ne demandent qu'une seule chose ; avoir fait un reset hard juste avant l'installation.

Beaucoup se sont cassé les dents sur la Multiface Two ; elle ne se laisse pas faire !

En effet, la MF2 possède deux ports (&FEE8 et &FEEA) qui permettent d'activer et de désactiver sa page ROM+RAM entre &0000 et &3FFF. Toutefois, cette porte ouverte vers la MF2 depuis le CPC posait problème car elle permettait simplement à tout programme de détecter la présence d'une MF2 et par exemple, dans le cas de la plupart des jeux, de refuser alors de fonctionner ! Mais chez Romantic Robot, ils ont trouvé une parade : ces ports deviennent inertes suite à une activation de la MF2 et ne redeviennent actifs que consécutivement à un reset hard. En d'autres termes, lorsque vous allumez votre CPC, la MF2 est visible ; si vous l'activez ne serait-ce qu'une seule fois, elle devient invisible ! Pour la rendre à nouveau visible, il n'y a qu'une seule alternative ; un reset hard (via le bouton RESET de la MF2 elle-même par exemple).

Il est par ailleurs important de noter que lorsque vous souhaitez commuter la page ROM+RAM de la MF2, vous devez le faire alors que le firmware est complètement désactivé. En effet, la page entre &0000 et &3FFF est utilisée pratiquement en permanence par l'OS du CPC ! Y commuter la page de la MF2 sans aucune précaution provoquera irrémédiablement un plantage… heureusement un simple DI bien placé suffit à inhiber tout activité de l'OS.

Voici donc à quoi pourrait ressembler le code de commutation :

        Org &8000      ; Une adresse sans conflit
 
Multiface
        di             ; On "désactive" le firmware
 
        ld bc,&7f8a
        out (c),c      ; On active la ROM basse
 
        ld bc,&fee8    ; On commute la page ROM/RAM
        out (c),c      ; de la Multiface Two
 
        ...            ; Code de configuration de la
        ...            ; RAM qui ne doit utiliser
        ...            ; aucun appel système
 
        ld bc,&feea    ; On désactive la page ROM/RAM
        out (c),c      ; de la Multiface Two
 
        ei             ; On "restaure" le firmware
        ret            ; C'est prêt !

Ah, le petit blond à lunettes est visiblement très pertubé par l'activation de la ROM basse (via le mode RMR du Gate Array) qui précède le OUT de commutation de la page ROM/RAM de la MF2. Il ne faut pas perdre de vue que la ROM de la MF2 est une ROM basse et que celles-ci doivent donc être activées pour que la page de la MF2 puisse être accessible. À noter toutefois que sur CPC+, pour changer, il y a une anomalie qui fait que la MF2 parvient à commuter sa page ROM/RAM même si les ROM basses sont désactivées !

Mais qu'y a-t-il donc dans cette mémoire ?

Maintenant que nous savons comment accéder à cette mémoire de la MF2 via son mapping entre &2000 et &3FFF, nous allons voir ce qu'elle a dans le ventre. Dès lors, nous serons en mesure de personnaliser notre MF2 en mode “Direct Jump” ou “Indirect Jump” selon le cas.

Hein ?!

Comme je vous l'ai déjà dit au tout début, certaines parties de la RAM sont modifiées en temps réel par le hardware de la MF2. D'autres sont initialisées par le programme en ROM, pour certaines avant le “Direct Jump” (on en hérite donc dans un programme utilisateur installé en lancement direct), pour d'autres via l'outil intégré à la ROM (on a donc à nous en soucier uniquement pour les programmes utilisateurs lancée grâce au menu “Jump”). De plus, certaines données stockées en RAM sont utilisées pour mémoriser quel était l'état du système lorsque le programme tournant sur le CPC a été interrompu par la MF2. Si vous les modifiez, cela changera en conséquence l'état du retour au programme initial. C'est d'ailleurs déjà le cas avec l'outil de la ROM. Concernant la partie de la mémoire modifiée matériellement, vous ne pourrez simplement pas l'utiliser vu que même lorsque votre programme utilisateur tournera dans la MF2, elle continuera d'être modifiée au gré de vos OUT ; tout au plus vous pourrez la consulter en lecture.

Le détail

Ci-après, vous allez trouver un tableau détaillant de manière assez précise le contenu de la RAM de la MF2. Ceci étant, dans un soucis de simplicité, je ne vous ai mis le plan de la mémoire libre seulement dans le cas du “Direct Jump”. En effet, le mode “Indirect Jump” est beaucoup moins utile ; de plus, une grande partie de la mémoire de la MF2 étant alors occupée pour le fonctionnement de l'outil intégré à la ROM, ce mode sera plus volontier utilisé pour configurer des sauts directement dans la mémoire du vive ou morte du CPC. Seules les informations sur le système disponibles dans la RAM de la MF2 seront alors éventuellement utilisées (la page mémoire de la MF2 reste en effet commutée par défaut entre &2000 et &3FFF dans le cas de la programmation d'un “Jump”, qu'il soit direct ou indirect).

Avant de me lancer dans des explications plus détaillées de ce tableau, en voici la légende :

Adresse : l'adresse de départ de la zone, Taille : taille de la zone en octets, Type : type de mise à jour de la mémoire :

  • PRG : par l'utilisateur, pour la programmation et la configuration de la MF2,
  • ROM : par la ROM lors de l'appui sur le bouton STOP de la MF2,
  • ROM* : idem, mais peut-être modifié par l'utilisateur pour changer les conditions du retour au programme stoppé,
  • HARD : modifié matériellement en temps réel par la MF2,
  • FREE : mémoire non utilisée par la MF2,

Description : brève description de la zone mémoire.

Houaaaahh ! C'est pas encore fini ? Concernant les zones modifiées par le hardware et le programme de la ROM de la MF2, je n'ai mis de description précise que dans le cas de données réellement utiles ; le reste du temps, vous trouverez juste le commentaire “Réservé”. Dans le cas où vous seriez intéressé, j'ai établi la description de la plupart de ces zones et je les tiens à votre disposition, toutefois, ça ne me paraît vraiment pas utile. À titre d'exemple, en &3F00 vous trouverez une zone “HARD” “réservée” de 16 octets de long. Il s'agit en fait d'une zone parasitée par le hardware de la MF2 lorsqu'il décrypte le numéro du stylo en cours de sélection sur le Gate Array. Vous y trouverez à l'adresse &3F0x le numéro du pen x s'il a déjà été utilisée ou est en cours d'utilisation… mais vous y trouverez également le numéro du border s'il est programmé via 16+x dans le mode PENR du Gate Array ! En fait, tout ceci pour vous dire que les zones non décrites ici sont de toute manière sans grand intérêt. De plus, étant donné qu'il existe plusieurs révisions de la MF2 (au moins trois à ma connaissance), il est fort possible que ces zones mémoire diffèrent d'une version à l'autre… mieux vaut donc les ignorer.

Le tableau qui suit a été élaboré par mes soins sur le modèle de MF2 répondant “0E” lors de l'appui sur la touche f0 dans le menu de l'outil intégré en ROM. Toutes les zones que j'y ai documentées semblent compatibles avec le modèle répondant “8B” (modèle ©1990). Je les ai de plus confrontées avec divers documents disponibles sur web qui, bien que contenant quelques boulettes, correspondent assez.

La configuration de la MF2

Entre &2000 et &2007, se trouvent les zones permettant de configurer le mode de fonctionnement souhaité de la MF2. En &2000 vous devez placer l'adresse du code utilisateur (au format little endian Z80 habituel) et en &2002 et &2003 les deux valeurs à envoyer au Gate Array pour fixer les modes de commutation ROM (RMR) et RAM (MMR).

Enfin, en &2005, vous avez la zone permettant de choisir le type de “Jump” souhaité. Si vous y placez le mot-clé “RUN” (&52,&55,&4E) alors ce sera du “Direct”, sinon ce sera un “Indirect”. Bien sûr, neuf fois sur dix, on y pokera ce mot-clé puisque le “Direct Jump” est bien plus intéressant. En outre, lorsque vous désactivez le “Direct Jump” (en gardant une touche appuyée lorsque vous enfoncez le bouton STOP de la MF2), le code en ROM de la MF2 efface simplement le premier octet de cette zone (le “R”).

La description

À partir de &2008 et sur 6135 octets de long, se trouve la principale (et légale) zone à utiliser pour placer votre programme dans la MF2. Dans tous les cas, je vous conseille d'utiliser uniquement cette zone car rien ne garantit la validité des autres zones “FREE” sur toutes les révisions de MF2.

En &37FF, nous avons un octet “poké” par le hard. Il s'agit de la dernière valeur chargée sur le port de contrôle du PPI (port &F7xx). C'est cet octet qui est recopié en &3AA8 par la ROM avant toute modification pour pouvoir le rendre en l'état lors du retour au programme stoppé.

Nous avons ensuite une alternance de zones libres et de zones utilisées par la ROM jusqu'en &3A6E où se trouve le numéro du registre CRTC qui était sélectionné lorsque le programme a été coupé par la MF2. La ROM met à jour cette valeur avant toute modification personnelle de l'état du CRTC à partir de l'adresse &3CFF qui contient la valeur du dernier octet envoyer sur le port &BCxx (sélection de registre CRTC).

Je ne vais pas tout détailler, c'est toujours sur le même principe ; nous avons les valeurs des principaux ports et des principaux registres des circuits du CPC “pokées” par le hard en temps réel et ces valeurs copiées par la ROM à une autre adresse (lors de l'activation de la MF2) qui représentent donc l'état du CPC à ce moment là. La ROM utilise ensuite les valeurs qu'elle avait mises en place pour reconfigurer le CPC avant de faire repartir le programme interrompu. Dès lors, si vous modifiez ces valeurs (type “ROM*”), ça influera directement sur le fonctionnement du programmation que vous aviez stoppé.

Il y a néanmoins quelques octets positionnés par la ROM qui ont un statut à part. En &3A96, nous avons un octet nous indiquant si nous avons plus de 64ko sur le CPC. Ceci est déterminé par un test de la mémoire dans le code de la ROM.

Ensuite, en &3EE6, nous avons la valeur de tous les registres et flags du Z80 lorsque le programme a été stoppé.

Salut ! こんにちは Hallo!

&3EF8 : IF
&3EE6 : IY &3EEC : DE' &3EF2 : BC &3EFA : HL
&3EE8 : IX &3EEE : HL' &3EF4 : DE &3EFC : AF
&3EEA : BC' &3EF0 : AF' &3EF6 : RF &3FFE : SP

Rien de particulier à noter sinon que la valeur de PC au moment de l'arrêt du programme est en (SP). Ah si, RF et IF auront sans doute éveillé votre curiosité… Il s'agit des valeurs de R et I dans le programme stoppé, couplées avec l'état des flags au moment de leur chargement dans A (LD A,R et LD A,I). Nous reviendrons plus tard sur ce point.

Plan de la mémoire de la MF2

Adresse Taille Type Description
&2000 2PRG Adresse du programme utilisateur à exécuter via la Multiface Two.
&2002 1PRG Configuration ROM du Gate Array (mode RMR du port &7Fxx) à adopter.
&2003 1PRG Configuration RAM du Gate Array (mode MMR du port &7Fxx) à adopter.
&2004 1ROM Réservé.
&2005 3PRG Mode de lancement du programme utilisateur (Direct ou Indirect Jump).
&2008 6135FREE Zone mémoire libre à utiliser pour un programme utilisateur en “Direct Jump”.
&37FF 1HARD Valeur mise à jour en temps réel du port de contrôle du PPI (port &F7xx).
&3800 523FREE Non utilisé en mode “Direct Jump”.
&3A0B 3ROM Réservé.
&3A0E 1FREE Non utilisé en mode “Direct Jump”.
&3A0F 5ROM Réservé.
&3A14 1FREE Non utilisé en mode “Direct Jump”.
&3A15 20ROM Réservé.
&3A29 33FREE Non utilisé en mode “Direct Jump”.
&3A4A 5ROM Réservé.
&3A4F 1FREE Non utilisé en mode “Direct Jump”.
&3A50 1ROM Réservé.
&3A51 23FREE Non utilisé en mode “Direct Jump”.
&3A68 2ROM Réservé.
&3A6A 2FREE Non utilisé en mode “Direct Jump”.
&3A6C 2ROM Réservé.
&3A6E 1ROM* Registre CRTC sélectionné (port &BCxx) lorsque le programme a été interrompu.
&3A6F 1ROM* Couleur du border active lorsque le programme a été interrompu.
&3A70 16ROM* Palette de couleurs active lorsque le programme a été interrompu.
&3A80 16ROM* Valeurs des 16 registres du CRTC lorsque le programme a été interrompu.
&3A90 2ROM* Adresse de l'écran système lorsque le programme a été interrompu.
&3A92 1ROM* Configuration ROM du Gate Array (mode RMR) lorsque le programme a été interrompu.
&3A93 1ROM* Configuration RAM du Gate Array (mode MMR) lorsque le programme a été interrompu.
&3A94 1ROM* Mode d'interruption (IM 0, 1 ou 2) lorsque le programme a été interrompu.
&3A95 1ROM État des interruptions (1=EI, 0=DI) lorsque le programme a été interrompu.
&3A96 1ROM Indicateur de taille de la RAM du CPC (0 si 64ko, 2 si plus).
&3A97 1ROM* Couleur sélectionnée (port &7Fxx, mode PENR) lorsque le programme a été interrompu.
&3A98 16ROM* Valeur des 16 registres du PSG lorsque le programme a été interrompu.
&3AA8 1ROM* Valeur du port de contrôle du PPI (port &F7xx) lorsque le programme a été interrompu.
&3AA9 7FREE Non utilisé en mode “Direct Jump”.
&3AB0 2ROM Réservé.
&3AB2 14FREE Non utilisé en mode “Direct Jump”.
&3AC0 2ROM Réservé.
&3AC2 1ROM* Nombre d'interruptions jusqu'à la prochaine VBL lorsque le programme a été interrompu.
&3AC3 1ROM Réservé.
&3AC4 571FREE Non utilisé en mode “Direct Jump”.
&3CFF 1HARD Numéro du registre CRTC en cours de sélection (port &BCxx) en temps réel.
&3D00 176FREE Non utilisé en mode “Direct Jump”.
&3DB0 16HARD Valeur des 16 registres du CRTC en temps réel.
&3DC0 286FREE Non utilisé en mode “Direct Jump”.
&3EDE 8ROM Réservé.
&3EE6 26ROM* État du Z80 (registres et flags) lorsque le programme a été interrompu.
&3F00 16HARD Réservé.
&3F10 16HARD Palette de couleurs mise à jour en temps réel (zone miroir de &3F90).
&3F20 16FREE Non utilisé en mode “Direct Jump”.
&3F30 1ROM Réservé.
&3F31 95FREE Non utilisé en mode “Direct Jump”.
&3F90 16HARD Palette de couleurs mise à jour en temps réel (zone légale).
&3FA0 1FREE Non utilisé en mode “Direct Jump”.
&3FA1 2HARD Réservé.
&3FA3 2FREE Non utilisé en mode “Direct Jump”.
&3FA5 2HARD Réservé.
&3FA7 2FREE Non utilisé en mode “Direct Jump”.
&3FA9 2HARD Réservé.
&3FAB 2FREE Non utilisé en mode “Direct Jump”.
&3FAD 2HARD Réservé.
&3FAF 32FREE Non utilisé en mode “Direct Jump”.
&3FCF 1HARD Stylo sélectionné en temps réel (port &7Fxx, mode PENR).
&3FD0 5ROM Réservé.
&3FD5 1HARD Réservé.
&3FD6 9ROM Réservé.
&3FDF 1HARD Couleur du border en cours en temps réel.
&3FE0 15FREE Non utilisé en mode “Direct Jump”.
&3FEF 1HARD Configuration ROM du Gate Array en temps réel (mode RMR).
&3FF0 1HARD Réservé.
&3FF1 3FREE Non utilisé en mode “Direct Jump”.
&3FF4 1HARD Réservé.
&3FF5 10FREE Non utilisé en mode “Direct Jump”.
&3FFF 1HARD Configuration RAM du Gate Array en temps réel (mode MMR).

La fin des hostilités ?

Voilà, nous avons fait le tour des fonctionnalités de la MF2 et v… “à quelques détails près !” vient de me lancer le petit blond à lunettes avec arrogance. Effectivement, pour une fois il n'a pas tort (mais il se prend tout de même une gifle pour le ton sur lequel il m'a parlé) ; nous allons donc de ce pas revenir sur la gestions des flags…

À quoi bon sauver AF après un LD A,I ?

Oui, rappelez-vous, nous avons vu plus haut que la MF2 sauve l'état de AF après avoir récupéré les valeurs des registres I et R… une petite révision sur le fonctionnement du Z80 s'impose. Commençons par le plus simple. En premier lieu, le programme de la MF2 sauve le contenu du registre I dans A, puis stocke AF dans sa RAM dans l'espace des registres Z80. F se retrouve en &3FF8 (nommé Mi dans le menu de la MF2) et A se retrouve en &3FF9 (nommé I - logique - dans le menu de la MF2). Il est important de conserver ainsi le contenu du registre I pour pouvoir le restaurer lorsque la MF2 rendra la main au programme car il est utile en mode vectorisé (IM 2) pour connaître l'octet de poids fort de l'adresse de la table des vecteurs d'interruption (pour plus de détail voir l'article sur les interruptions). Mais, en même temps, notre chère MF2 sauve le contenu de F… “c'est naze, ça ne sert à rien, encore un programme pas optimisé !” s'indigne le petit blond à lunettes. Mais non ! Pas du tout ! La valeur de F après un LD A,I (ou LD A,R) est primordiale ! Elle nous permet de connaître l'état du flag IFF2.

Mais qu'est-ce donc que ce flag IFF2 et à quoi sert-il ? En fait, le Z80 dispose de deux flags pour la gestion des interruptions: IFF1 et IFF2. Ces deux flags sont positionnés simultanément à 1 lors d'un EI, et à 0 lors d'un DI. Lorsque IFF1 est à 1, alors le Z80 accepte les interruptions ; lorsqu'il est à 0, il les ignore… voilà qui semble bien obscur ! En fait, pas tant que ça, car lorsqu'une NMI a lieu (ce qui est le cas lorsque la MF2 s'active), IFF1 est mis à 0 de sorte que les interruptions soient désactivées mais IFF2 est laissé inchangé ! Ce qui signifie qu'il vaut 1 si on était en EI lors de la NMI, et 0 si on était en DI… d'où l'intérêt de connaître son état pour la MF2 afin de savoir, au retour, si on devra réactiver les interruptions ou pas. Mais où diable se cache ce flag ? Eh bien il est positionné dans F, à la place du flag P/V (bit 2) suite à une instruction LD A,I ou LD A,R ! Comme vu plus haut, la MF2 récupère son état à partir du LD A,I ; le LD A,R ne servant qu'à récupérer l'état de R dans ce cas là.

Les limitations de la MF2

Venons-en maintenant aux défauts de conception de cette excellente interface. Eh oui, tout n'est pas parfait dans la MF2 ! Le plus gros soucis vient du fait que contrairement au CPC, la MF2 décode les ports I/O des divers circuits avec rigueur. Je m'explique, sur CPC, chaque circuit est accessible via un port : &7Fxx pour le Gate Array, &BCxx-&BFxx pour le CRTC, &F4xx à &F7xx pour le PPI, etc.. Mais il se trouve qu'en pratique, le décodage de ces ports n'est que partiel ; dans un soucis d'économie de portes logiques, seuls quelques bits finement choisis sont utilisés pour décoder et ainsi sélectionner le bon circuit en fonction du port. Vous trouverez ci-dessous un petit tableau illustrant ce décodage. “x” y désigne un bit non décodé, “0” un bit testé à 0, “1” un bit testé à 1 et “r” un bit permettant la sélection d'un registre sur le périphérique (les ports CRTC ou PPI par exemple).

Le chipset bidule ? C'est par là, par le port truc !

Nom des périphériques bits décodés par le CPC
(adresse des ports logiques) 15 14 13 12 11 10  9  8
Gate Array - PENR, INKR (&7Fxx) 0 1 x x x x x x
Gate Array - RMR, MMR (&7Fxx) 0 x x x x x x x
CRTC (&BCxx-&BFxx) x 0 x x x x r r
Sélection ROM Haute (&DFxx) x x 0 x x x x x
Imprimante (&EFxx) x x x 0 x x x x
PPI (&F4xx-&F7xx) x x x x 0 x r r
Périphériques d'expansion x x x x x 0 r r

On voit dès lors que le CRTC est aussi bien accessible via &BCxx (%10111100) que &ACxx (%10101100) pour la sélection du registre rr=00… et c'est là que réside le problème de notre MF2 qui, forte de sa rigueur de décodage, n'interceptera que les accès sur le port &BCxx. Bien sûr, accéder au CRTC par le port &ACxx n'est vraiment pas très propre puisqu'on accède simultanément au port imprimante, mais le fait est que ça fonctionne. De plus, cela est sans grande conséquence même si une imprimante est connectée compte tenu de l'absence de gestion du signal /STROBE qui est indispensable pour valider les données d'impression. En revanche, si une Soundplayer+ était connectée, des effets secondaires indésirables seraient à prévoir sur le son ou le réseau. D'autres combinaisons d'adressage sont possibles et, dans certains cas, permettent des optimisations de code on ne peut plus subtiles. En outre, une conséquence directe est qu'il est possible de feinter la MF2 assez facilement. Par exemple, tapez en BASIC la ligne suivante :

OUT &BC00,0:OUT &AC00,5:OUT &BD00,0

En pratique, que fait ce programme ? Eh bien, il sélectionne le registre 0 du CRTC via le port légal &BCxx, il sélectionne ensuite le registre 5 (qui est le registre de retard vidéo) tout en mettant également 5 sur le port imprimante, enfin il envoie une donnée via le port légal &BDxx. Mais du point de vue de la MF2, les choses sont différentes. Elle va voir une sélection du registre 0, elle ne verra pas celle du registre 5, puis elle verra l'envoi d'une donnée sur le registre… 0 ! Résultat des courses : activez la MF2 puis faites un “Return” pour rendre la main et paf, écran noir et CPC planté. “Pourquoi ?”, demande le petit blond à lunettes d'un air interloqué. Eh bien tout simplement car au retour, la MF2 va remettre le CRTC dans son état initial… lequel était pour elle un registre 0 à 0 (ce qui fait irrémédiablement “planter”). Et voilà une MF2 dans les choux !

Bluffer le bluffeur

Enfin, pas tout à fait dans les choux… il est facile, avant de rendre la main, de vérifier la liste des valeurs du CRTC (en &3A80) et de les corriger pour que le retour se passe bien. Il en va de même pour la palette des couleurs avec laquelle on peut faire les mêmes blagues. Beaucoup de démos utilisent l'astuce du registre 0 fictivement à 0 (parfois volontairement, parfois simplement en conséquence d'une optimisation d'adressage) alors que des jeux (comme Batman The Movie) ont plutôt bidouillé sur la palette des couleurs (écran noir au retour mais rien de planté… juste toutes les couleurs en noir… ce qui est moins “méchant” mais en réalité, bien plus pénible à remettre en place au niveau de la MF2 avant de rendre la main).

De la même manière, contrairement à ce que j'ai souvent entendu, il est vraiment enfantin d'utiliser la MF2 pour interrompre puis refaire partir une démo pleine de ruptures après modification. Le petit blonc à lunettes se fait avoir à tous les coups, il lance sa démo, coupe avec la MF2, patche ce qu'il a à patcher, et rend la main… mais là, une fois sur deux, ça plante ! Pourquoi ? Eh bien tout simplement car selon le moment où le programme a été interrompu, le CRTC contient des valeurs susceptibles de bloquer le fonctionnement du CPC. Il suffit de remettre dans les principaux registres du CRTC des valeurs viables avant de rendre la main et ça se passera bien à tous les coups ! Vous aurez juste droit à un petit saut d'écran au retour, mais plus de plantage. Bien sûr, cette manipulation devient indispensable lorsque le demomaker s'est amusé (par goût ou par besoin d'optimisation) à adresser le CRTC ou le Gate Array par des ports illégaux.

Le bug "imparable"

Outre ce petit problème de décodage des ports qui est souvent utilisé pour gêner l'utilisation de la MF2 (sans jamais l'empêcher toutefois), il existe un bug beaucoup plus sévère sur lequel je suis tombé par hasard alors que je désassemblais sa ROM afin d'en comprendre le fonctionnement intime. Il n'est cette fois-ci pas matériel mais logiciel et concerne la routine de détection de la mémoire. En effet, dans la ROM, la MF2 détermine si le CPC possède seulement 64ko de RAM ou plus afin de positionner l'octet à l'adresse &3A96 à 0 (64ko) ou à 2 (plus de 64ko). Eh bien, ce test est buggé et laisse des traces sur les CPC ayant des banks ; dès lors, il est possible de rendre l'utilisation de la MF2 pratiquement impossible sur les CPC ayant 128ko ou plus. Ce bug est à ma connaissance présent dans toutes les MF2 distribuées (y compris la MF2+ de 1990) mais j'ai constaté à ma grande surprise que la ROM de MF2 livrée avec l'émulateur CPC CaPriCe32 a été patchée et ne souffre plus de ce bug. Il serait en théorie possible d'utiliser cette version patchée (ou d'en faire une autre soi-même) et de la programmer dans l'EPROM de la MF2.

Saleté de bug ! Je vois le petit blond à lunettes s'agiter sur sa chaise : “c'est quoi le bug ? c'est quoi le bug ?”. J'y viens. Afin de détecter si le CPC a ou non une page de RAM supplémentaire, la MF2 teste la présence de la première bank de celle-ci (bank &C4). Pour ce faire, elle poke des valeurs en &4000 et regarde ce qui se passe lors de la commutation de la bank pour en déduire si une bank se commute effectivement ou pas. Oui mais voilà, dans l'un des cas de ce test, le programme oublie purement et simplement de restaurer la valeur initialiement présente en bank &C4 ! Pour se retrouver dans ce cas de figure, rien de plus simple, il suffit que la valeur &AA soit présente en &4000 bank &C4 ; après une activation de la MF2 cette valeur sera remplacée par &55. Et il est impossible, lorsqu'on est sous la MF2, de savoir si la valeur initiale était &AA ou &55 afin de rectifier le tir avant le retour au programme (comme on peut le faire pour les registres du CRTC par exemple). Le petit blond à lunettes se la raconte en disant qu'il n'y a que deux cas possibles : si ça plante au retour avec &55, c'est donc qu'il faut poker &AA avant de rendre la main. Certes, mais imaginez un programme anti-multiface un peu plus élaboré qui modifierait régulièrement cette valeur, la passant tantôt à &AA, tantôt à &55 ; tout devient alors bien plus compliqué pour contourner la protection. Oui, rien n'est perdu, l'idéal étant de neutraliser le test lui-même mais que de complications pour un petit bug logiciel !

Les multiples facettes ont été mise au jour ?

Voilà, nous avons plus ou moins fait le tour des fonctionnalités et des défauts d'une des plus célèbres interfaces sur CPC. Bien sûr, nous pourrions pousser encore plus en avant sur le fonctionnement intime de la MF2, ou sur d'autres petits défauts qui permettraient de la déceler ou d'embêter ses utilisateurs1). Mais, je pense que l'essentiel (et même plus) a été dit et qu'il est plus intéressant de s'attaquer à sa programmation avec un petit exemple simple mais qui met en oeuvre les principaux mécanismes qu'il convient de maîtriser.

La programmation de la MF2

Programmons la MF2

Vous trouverez ci-après un petit programme tout simple qui ne fait rien de plus que d'installer dans la MF2 un outil qui permet de copier les 64ko de mémoire centrale dans les 64ko de banks d'un CPC6128 (ou d'un CPC464/664 étendu) lorsque vous appuyez sur le bouton STOP. À la lumière des informations fournies en début d'article, la procédure d'installation dans la MF2 devrait vous paraître assez simple. Il s'agit simplement, après avoir vérifié sommairement la présence d'une MF2 non masquée en tentant de lire un octet de sa ROM, de copier le programme à intégrer dans la MF2 en &2000 (la plage de RAM de la MF2 qui a été largement décrite en amont).

Créfieux ! J'me laisserai pas faire ! Vient ensuite le programme dédié à la MF2 lui-même. Celui-ci s'excécute dans la mémoire de la MF2 et possède un header. La directive de compilation ORG &2000,&8100 permet d'assembler le code en &8100 (son adresse de stockage) pour une exécution en &2000 (là où il est mis dans la RAM de la MF2 par le code d'installation logé en &8000). Le header contient les informations suivantes :

  • l'adresse d'exécution du programme (label MF2Code),
  • la configuration Gate Array pour les ROMs,
  • la configuration Gate Array pour la RAM,
  • un octet vierge (inutile à la MF2),
  • le mot-clé “RUN” pour indiquer le mode “Direct Jump”.

Si vous regardez tout ça à la lumière de tout ce qui précède, tout devrait vous paraître limpide (n'en déplaise au petit blond à lunettes). À la suite de ce header, nous avons donc le bout de code qui sera invoqué par la MF2 lorsque vous presserez le bouton STOP. Ce programme va donc copier une à une les 4 pages de 16ko de RAM centrale sur les 4 pages de 16ko des banks après avoir fait un flash rouge pour vous indiquer le bon fonctionnement.

Copie dans les banks

Le programme commence par copier la page en &4000 dans la bank &C7 (la quatrième page de 16ko des banks). Pour ce faire, il place &C1 sur le Gate Array ; ceci a pour effet de commuter la bank &C7 en &C000. Il effectue ensuite simplement une copie de &4000 vers &C000. Le programme place ensuite &C2 sur le Gate Array. Dans ce mode, les 64ko de banks sont commutés sur la plage d'adressage du Z80 (comme notre programme s'exécute dans la RAM de la MF2, ça ne pose aucun problème). Dès lors, il peut copier tout ce qui se trouve en &C000 (la bank &C7) en &4000 (la bank &C5) : nous avons donc copié la deuxième page de 16ko de la RAM centrale sur la deuxième page de 16ko des banks, missions accomplie, nous pouvons passer à la page suivante.

On envoie ensuite &C7 au Gate Array et on copie de &C000 à &4000 ; voilà la quatrième page de 16ko de RAM centrale copiée là où il faut en bank. On trouve ensuite un nouveau petit bout de code qui a pour mission de gérer le flash sur le border puis on attaque la copie de la page en &8000 vers la bank &C6. Jusque là, tout était simple et chaque page est à sa place. Il ne nous reste plus qu'à copier la page sitruée en &0000 dans la bank &C4, mais c'est un peu plus compliqué vu que notre programme s'exécute dans la RAM de la MF2 qui est elle-même commutée dans ces adresses ! Le programme va donc devoir jongler un petit peu. Tout d'abord, on commute la bank &C4 dont nous aurons de toute façon besoin en destination de copie. Ensuite, on sauve le contenu de 100 octets de la RAM situés en &8000 dans la RAM de la MF2 avant d'y placer notre petit bout de code personnel (label SwapCode) puis de l'appeler (JP &8000).

Ce petit bout de code est la seule difficulté du programme. Premièrement, il déconnecte la page de la MF2 située en &0000-&3FFF. Pour ce faire, il faut invalider la page ROM/RAM de la MF2 elle-même grâce au port &FEEA, puis déconnecter toute la ROM basse via le Gate Array (la MF2 est une ROM basse). Dès lors, on a accès à la RAM centrale située entre &0000 et &3FFF que l'on peut copier simplement en &4000 où nous avions préalablement commuté la bank &C4 (la première page de 16ko des banks). Enfin, on recommute la ROM basse et on active la page ROM/RAM de la MF2 avant de retourner à notre code situé dans celle-ci. Le programme remet le contenu originel de la zone en &8000 dont nous avons eu besoin avant de quitter.

Et voilà, ce qui était à faire a été fait. On a à la sortie de ce programme la copie parfaite de la RAM centrale dans les banks ; couplé avec le Hacker ce petit outil peut être bien pratique. Bien sûr, il ne s'agit pas là d'un programme très complexe et il est possible de faire bien mieux compte tenu des 6ko de mémoire vive disponibles dans la MF2… d'autant que le programme stocké dans cette mémoire peut faire appel à du code stocké sur disquette ou même dans une ROM d'extension. Toutefois, il offre un bon exemple puisqu'il jongle avec les pages mémoire, chose qu'il faut maîtriser à la perfection pour pouvoir faire un logiciel adapté à la MF2.

Listing : programmation de la MF2

Télécharger le listing au format Maxam 1.5

; Copy 64k v1.0
; Programme pour Multiface Two
; OffseT of Futurs' - 02/2003
; 
; Installe un programme en mode Direct Jump
; qui copie les 64k de RAM centrale dans les
; premiers 64k de bank
;
 
        Org &8000       ; Implantation
        Limit &80ff     ; programme d'installation
        Nolist
 
        ld hl,msgintro  ; Texte d'intro
        call afftxt
 
        di              ; Interdiction interruptions
        ld bc,&7f8a
        out (c),c       ; Commutation ROM basse
        ld bc,&fee8
        out (c),c       ; Commutation page MF2
        ld a,(2)        ; Test MF2 présente
        cp &7f
        jr z,erreur
 
        ld hl,&8100
        ld de,&2000
        ld bc,&200
        ldir            ; Installation de Direct Jump
 
        ld bc,&feea
        out (c),c       ; Déconnexion page MF2
        ei              ; Autorisation interruptions
 
        ld hl,msgsucces ; Texte de réussite
AffTxt  ld a,(hl)
        or a
        ret z
        call &bb5a
        inc hl
        jr afftxt
Erreur  ld hl,msgerr
        jr afftxt
 
MSGIntro
        db "Copy 64k 1.0",13,10
        db "OffseT of Futurs' - 02/2003",13,10,0
MSGSucces
        db "Programme installé avec succès,",13,10
        db "Multiface Two prete.",13,10,0
MSGErr  db "Multiface Two non trouvée !",7,13,10,0
 
;
 
        Org &2000,&8100 ; Implantation code
        Limit &9700     ; Direct Jump 
 
MF2Head dw mf2code      ; Header du code Direct Jump
        db &89          ; Config ROM
        db &c0          ; Config RAM
        db 0            ; N/A
        db "RUN"        ; config jump
 
MF2Code ld bc,&7f10     ; Sélection border
        out (c),c
        ld c,&4c        ; Border rouge
        out (c),c
 
        ld c,&c1        ; Copie de la page &4000
        out (c),c       ; vers la bank &C7
        ld hl,&4000
        ld de,&c000
        ld bc,&4000
        ldir
        ld bc,&7fc2     ; Copie de la bank &C7
        out (c),c       ; vers la bank &C5
        ld hl,&c000
        ld de,&4000
        ld bc,&4000
        ldir
        ld bc,&7fc7     ; Copie de la page &C000
        out (c),c       ; vers la bank &C7
        ld hl,&c000
        ld de,&4000
        ld bc,&4000
        ldir
 
        ld bc,&7f4b     ; Border blanc
        out (c),c
 
        ld c,&c6        ; Copie de la page &8000
        out (c),c       ; vers la bank &C6
        ld hl,&8000
        ld de,&4000
        ld bc,&4000
        ldir
 
        ld bc,&7fc4     ; Copie de la page &0000
        out (c),c       ; vers la bank &C4
        ld hl,&8000
        ld de,buffer
        ld bc,100
        ldir
        ld hl,swapcode
        ld de,&8000
        ld bc,100
        ldir
        jp &8000
RetourSwapCode
        ld hl,buffer
        ld de,&8000
        ld bc,100
        ldir
        ret         ; Retour MF2
 
SwapCode            ; Code de copie page &0000
        ld bc,&feea ; Déconnexion page PF2
        out (c),c
        ld bc,&7f8d ; Déconnexion ROM basse
        out (c),c
        ld hl,&0000
        ld de,&4000
        ld bc,&4000
        ldir
        ld bc,&7f89 ; Connexion ROM basse
        out (c),c
        ld bc,&fee8 ; Connexion page MF2
        out (c),c
        jp retourswapcode
 
Buffer  ds 100      ; Buffer swap

Quels softs pour la MF2 ?

Quelques outils pour utiliser la MF2

Dans des temps reculés, la MF2 était utilisée par certains crackers peu compétents pour “déplomber” des jeux ou ripper leurs écrans de présentation. Dans ce dernier cas, aucun soucis, les fichiers d'écrans rippés à l'aide de la MF2 étaient exploitables sur n'importe quel CPC même non équipé d'une MF2. En revanche, dans le cas de programmes sauvegardés via la MF2, celle-ci était indispensable à leur exploitation… toutefois, dans le cas des programmes 64k, des loaders annexes permettaient de contourner cette limitation.

Vous trouverez quelques logiciels permettant d'utiliser les sauvegardes 64k de la MF2 sur un CPC en étant dépourvus sur le Quasar Disc 3.

Customisons la MF2

Voyons voir maintenant les programmes qui customisent cette interface. Je vous en ai déjà parlé brièvement en début d'article, le plus célèbre d'entre eux est The Insider, développé par les auteurs de la MF2 en personne. Il intègre tout un tas d'outils pratiques dont un désassembleur ! Ce programme étant relativement complexe, il a besoin d'avoir sa disquette toujours présente dans le lecteur interne de votre CPC afin d'accéder à ses divers modules vu que tout ne rentrait pas dans les 6ko de mémoire libre de la MF2. Un autre défaut de ce logiciel est son manque certain d'ergonomie et son interface lilliputienne.

Il existe un autre programme similaire à The Insider qui dispose d'une interface plus agréable et n'a pas besoin de faire des accès disque à tout bout de champ pour fonctionner : Tearaway. Ce programme de 1991 (The Insider date de 1989) développé par CPC Network offre globalement les mêmes outils que ce dernier avec un confort d'utilisation amélioré. Toutefois il est moins puissant puisqu'il ne fonctionne que sur un CPC doté d'au moins 128ko et n'est pas compatible avec les logiciels exploitant les banks… car il les utilise lui-même pour fonctionner ! En fait, c'est grâce à ce stratagème qu'il peut offrir une interface digne de ce nom et éviter tout accès disque. À quand un logiciel de ce type s'appuyant sur une ROM d'extention ? Nous pourrions alors avoir des outils très complets sans utiliser une once de mémoire vive.

Vous trouverez divers outils de customisation de la MF2 dans le Quasar Disc 4.

Ciao ! Ciao !

La mot de la fin

J'espère que les informations que j'ai pu vous fournir dans cet article vous donneront envie de développer des logiciels élaborés pour la Multiface Two. Si vous avez des questions sur des points précis, n'hésitez pas à me contacter !

Documentations externes

1) comme par exemple le fait que, sur CPC+, toute activation de la MF2 alors que la page I/O ASIC est commutée provoque irrémédiablement un plantage
 
dossier/mf2.txt · Dernière modification: 2023/05/26 09:32 par offset