Nouveau design de cartouche : ROMBA π

Certains se souviennent peut-être de ROMBA, une cartouche que j’ai sortie il y a près de 10 ans, qui était une Rombox dotée de fonctionnalités DMA limitées. Le temps a passé, le COVID est arrivé, et le CPLD utilisé par cette cartouche est passé de moins de 2 € pièce à plus de 10 € l’unité, faisant perdre tout intérêt au très petit nombre de personnes qui s’y intéressaient.

Comme les prix des CPLD disposant d’un grand nombre d’E/S ne semblent pas près de redescendre à leur niveau d’antan, j’ai commencé il y a quelque temps à réfléchir à une nouvelle conception axée, encore une fois, sur un faible coût de fabrication, tout en ajoutant davantage de fonctionnalités. Voici ROMBA π (ou ROMBA 3.14) :

La conception repose sur le RP2350B, un microcontrôleur « pi-pico2 », plutôt que sur un CPLD. Ces microcontrôleurs sont bon marché, possèdent de nombreuses broches tolérantes au 5V et prennent en charge jusqu’à 16 Mio de mémoire flash QSPI économique. La cartouche se branche sur le port d’extension, et comme pour mon ancienne ROMBA, elle peut être connectée directement via un connecteur de bord de carte (edge connector), ou via une carte MX4 à l’aide d’un connecteur DIL.

Utiliser un MCU au lieu d’un CPLD/FPGA pour l’interfaçage avec le bus parallèle, combiné à l’utilisation de flash QSPI plutôt que de flash NOR parallèle, a rendu son fonctionnement en tant que Rombox particulièrement complexe en raison des latences liées au scrutation du bus et à la lecture de la puce QSPI, mais ça y est, ça fonctionne !

Les fonctionnalités actuellement implémentées sont les suivantes :

  • Jusqu’à 16 Mio (128 mégabits) de capacité Flash ROM. La majeure partie est utilisable comme mémoire ROM pour le CPC, à l’exception de l’espace réservé au firmware (qui est actuellement d’environ 48 Kio, mais devrait augmenter si d’autres fonctionnalités sont ajoutées).
  • Port hôte USB. Actuellement, la prise en charge de la souris est implémentée, mais d’autres périphériques USB pourraient être ajoutés.
  • La prise en charge de la souris comprend une mise à l’échelle fractionnaire configurable (pour ajuster la sensibilité depuis le CPC), avec des réglages indépendants pour X, Y et la molette.
  • Compatible avec les Rombox Amstrad CPC (jusqu’à 256 slots).
  • DMA matériel pouvant être utilisé pour copier des données de la ROM vers la RAM interne (1 octet par microseconde).
  • Le moteur DMA peut copier en mode linéaire et en mode 2D, ce qui permet de copier des tuiles dans la mémoire d’écran sans avoir à se soucier des bizarreries du CRTC et du Gate Array.
  • Le moteur DMA en mode 2D prend également en charge la mise en miroir des tuiles à la volée pour les 3 modes graphiques.

La prise en charge des fonctionnalités ci-dessus est stable, mais je ne considérerais pas le firmware comme complet en l’état (plus de détails là-dessus plus bas). Le matériel permet d’ajouter également la prise en charge des éléments suivants :

  • Décalage de pixels (pixel shifting) pour les tuiles.
  • Masquage de pixels pour les tuiles (actuellement implémenté, mais uniquement avec une granularité d’un octet).
  • Prise en charge de la Lower ROM.
  • Gestion plus complexe de la mémoire (memory mapping).
  • Extension de RAM (le MCU dispose de 512 Kio de RAM, et la portion non utilisée par le firmware pourrait servir de RAM pour le CPC).
  • Capacités sonores (capacités FM, lecture d’échantillons PCM).
  • Sauvegarde de données en mémoire Flash.
  • Générateur de NMI programmable.
  • Prise en charge du DMA de la RAM interne du CPC vers la RAM interne du CPC (seul le transfert ROM vers RAM est pris en charge pour le moment).

Vous pouvez voir ici la prise en charge de la souris à l’œuvre :

SyX a patché plusieurs jeux pour intégrer la souris et je devrais aussi faire une vidéo de certains d’entre eux :grinning_face_with_smiling_eyes:. Il m’a également beaucoup aidé sur des points comme la compréhension de l’agencement de la mémoire vidéo, ainsi qu’avec des extraits de code et des programmes de test.

Et ici, vous pouvez observer les capacités du DMA 2D en action :

Ce sprite fait 32x64 pixels (mode 0) et le DMA met environ 1 ms pour le dessiner (il dessine deux pixels mode 0 par microseconde). Le moteur DMA 2D gère également la mise en miroir à la volée de manière matérielle, ainsi que le découpage à l’écran (clipping) et le masquage (mais dans la version actuelle, uniquement avec une granularité à l’octet, soit deux pixels mode 0).

Le matériel comme le firmware sont publiés en Open Source. La documentation sur la façon de programmer pour ces derniers fait défaut pour l’instant, mais je prévois de l’ajouter plus tard.

Maintenant, concernant l’état actuel « inachevé » du firmware. Je voulais ajouter la plupart (si ce n’est la totalité) des fonctionnalités énumérées ci-dessus qui ne sont pas encore implémentées. Mais il semble qu’une grande partie (peut-être la majorité ?) de la communauté CPC ne s’intéresse qu’aux prouesses logicielles et perçoive ces extensions matérielles comme des « anti-fonctionnalités », en disant que « ce n’est plus un CPC » et d’autres remarques du même genre. Donc plutôt que d’y consacrer davantage d’efforts, je suspends le développement en attendant de voir un réel intérêt pour la cartouche. Comme quelqu’un de véritablement motivé à développer pour cette plateforme en exploitant ces fonctionnalités. Car s’il s’agit de ma deuxième conception pour le CPC destinée à finir aux oubliettes, je préfère consacrer mon temps à d’autres projets matériels qui pourraient être utiles à d’autres développeurs.

Alors, qu’en pensez-vous ? Est-ce que ce genre de projet vous intéresse ? Y a-t-il des personnes motivées à développer pour ces cartouches économiques et performantes ? Ou bien est-ce qu’ajouter quoi que ce soit d’autre que de la mémoire relève de la triche et devrait être enterré ?

10 « J'aime »

En tant que passionné de matériel CPC, j’aimerais beaucoup que le projet aboutisse, mais n’étant pas développeur, je ne peux rien créer.

Si c’est bon marché et utile (ajout de ROM / RAM / souris / une sorte de gestion rapide des sprites), je ne vois pas pourquoi cela ne pourrait pas être intéressant…
Les jeux du type Populous / god games pourraient utiliser la souris pour une prise en main plus facile. Même moi, je pourrais modifier mon jeu de démineur pour l’utiliser.
Avec Vespertino qui réclame une carte de 4 Mo pour pouvoir y jouer, il y a de la place pour de bons jeux avec un petit coup de pouce matériel :slight_smile:. Et ils utilisent pas mal de ROM si je ne m’abuse.

Pour vos futurs développements, je dirais par ordre de priorité :

  • Extension de RAM (c’est toujours appréciable d’en avoir dans du nouveau matériel)
  • DMA RAM CPC vers RAM CPC pour des transferts de mémoire rapides
  • Décalage de pixels / masquage pour les tuiles
  • Capacités sonores (des échantillons avec un faible impact sur la vitesse/mémoire, c’est sympa)
  • Sauvegarde de données sur Flash
  • Prise en charge de la Lower ROM

Pour les autres points, ce n’est pas assez clair pour que je puisse donner un retour (mapping mémoire plus complexe / NMI programmable). Je ne vois pas où je pourrais m’en servir.

Ça m’intéresse carrément !

Je trouve ta présentation (doragasu) extrêmement captivante :slight_smile:

… depuis quelque temps, je bricole sur un « GOD GAME » (similaire à Populous). Quoi que j’essaie, je suis constamment confronté à des goulots d’étranglement de performances très importants et tout aussi tenaces. J’aimerais bien tester le nouveau matériel (ROMBA π pour les sprites ainsi que la souris) dès qu’il sera disponible. Les sprites pourraient être d’une grande aide pour les « petits bonshommes qui grouillent » (= sprites logiciels) sur la zone de jeu.

Mon défi personnel : je n’ai plus de CPC. J’ai dû le vendre à l’époque. Je ne travaille plus qu’avec des émulateurs.

Idée : si tu (doragasu) me donnes les specs, je regarderai de plus près l’émulateur CPC Caprise32 pour voir s’il est possible de l’étendre au niveau logiciel pour l’adapter à ton matériel. Autre option : créer une carte adaptatrice pour utiliser les ports GPIO d’un Raspberry Pi comme port d’extension CPC. (Un peu barré, mais tout aussi intéressant). Je n’ai pas encore jeté un œil au code de Caprise32, mais peut-être qu’avec toute la communauté, nous pourrions trouver une bonne idée ensemble…

Ça a l’air intéressant. Pour être honnête, j’ai été surpris qu’il faille attendre si longtemps avant que le RP2350B ne soit utilisé pour une extension multifonction de ce genre.

Une chose à laquelle je penserais : si une autre extension intégrant de la RAM est branchée en même temps, tu auras très probablement un conflit car elles fonctionneront toujours en parallèle. Par exemple, une DDI-5 reste pertinente en parallèle de ton extension. Il faudrait peut-être ajouter un commutateur pour désactiver la RAM dans ces situations.

Merci pour l’intérêt porté au projet.

@SoftDevil J’écrirai les spécifications plus tard, quand j’aurai un moment. L’interface de la souris devrait être définitive en l’état. En avant-première, voici comment cela fonctionne. Elle utilise les ports d’E/S de $F990 à $F993 :

Port Lecture Écriture Par défaut
$F990 STAT N/A N/A
$F991 WHEEL_BTN WHEEL_SCALING 64 (1.0)
$F992 X_AXIS X_SCALING 32 (0.5)
$F993 Y_AXIS Y_SCALING 32 (0.5)
  • STAT : le bit 0 est à 1 si la souris est branchée, 0 si elle n’est pas branchée.
  • WHEEL_BTN : les 5 bits de poids fort représentent le delta de défilement de la molette (depuis la dernière lecture) en complément à deux, positif pour un déplacement vers le haut, négatif pour un déplacement vers le bas. Les 3 bits de poids faible indiquent l’état actuel des boutons : M (milieu), R (droit), L (gauche).
  • X_AXIS : delta de l’axe X (depuis la dernière lecture) en complément à deux sur 8 bits. Positif pour un déplacement vers la droite, négatif vers la gauche.
  • Y_AXIS : delta de l’axe Y (depuis la dernière lecture) en complément à deux sur 8 bits. Positif pour un déplacement vers le haut, négatif vers le bas.
  • WHEEL_SCALING : facteur d’échelle fractionnaire de la molette.
  • X_SCALING : facteur d’échelle fractionnaire de l’axe X.
  • X_SCALING : facteur d’échelle fractionnaire de l’axe Y.

Lors de la lecture de la molette et des axes, vous obtenez le delta depuis la dernière lecture, et la valeur est réinitialisée à 0. Les valeurs saturent à leur maximum/minimum (15 à -16 pour la molette, 127 à -128 pour les axes) si vous déplacez la souris rapidement ou si vous attendez trop longtemps entre les lectures.

Les facteurs d’échelle permettent d’ajuster la sensibilité de la souris. Ils sont au format virgule fixe Q1.6 (1 bit de signe, 1 bit pour la partie entière, 6 bits pour la partie fractionnaire). Pour obtenir la valeur d’échelle, il faut diviser par 2^6 = 64. Ainsi, un facteur d’échelle de 64 correspond à 1.0, une échelle de 32 à 0.5, une échelle de 20 à 20/64 = 0.3125, et ainsi de suite.

L’utilisation de valeurs d’échelle négatives entraîne l’inversion de l’axe (par exemple, si vous définissez l’axe Y sur 0xE0, ce qui correspond à -0.5, en plus du facteur d’échelle de 0.5, un déplacement vers le haut donnera des valeurs négatives, et un déplacement vers le bas donnera des valeurs positives). Définir 0 comme valeur d’échelle désactive tout simplement cet axe.

Chaque axe peut être configuré individuellement. C’est pratique par exemple pour inverser des axes spécifiques comme expliqué ci-dessus, mais aussi parce qu’il est parfois nécessaire d’avoir des valeurs différentes pour chaque axe. Par exemple, le patch pour jouer à la souris à Operation Wolf est bien plus agréable à jouer avec une échelle X réglée sur 16 (0.25) et une échelle Y sur 32 (0.5) plutôt qu’avec une échelle identique pour les deux.

Concernant le DMA, je n’ai pas le temps pour le moment d’expliquer tous les registres, mais je le ferai plus tard. De plus, si le développement du micrologiciel (firmware) se poursuit, cela risque d’évoluer. Beaucoup. Ils sont situés entre $FC00 et $FC0F :

enum rdma_reg {
	RDMA_REG_DMASRCL = 0,
	RDMA_REG_DMASRCH,
	RDMA_REG_DMASRCU,
	RDMA_REG_2D_MASK,      // Pour le mode 2D, ne copie pas si le masque correspond
	RDMA_REG_DMADSTL,
	RDMA_REG_DMADSTH,
	RDMA_REG_DMALENL,
	RDMA_REG_DMALENH,
	RDMA_REG_SCR_WIDTH,    // En caractères, ex. : 40
	RDMA_REG_SCR_HEIGHT,   // Hauteur de ligne - 1 et hauteur en caractères : lllhhhhh (ex. 0xF9)
	RDMA_REG_2D_W,         // En octets. REMARQUE : la hauteur est déduite de LEN
	RDMA_REG_2D_X,         // En octets, signé
	RDMA_REG_2D_YL,        // En lignes, signé
	RDMA_REG_2D_YH,
	RDMA_REG_DMACTRL2,
	RDMA_REG_DMACTRL1,
	__RDMA_REG_MAX
};

// Masques du registre DMACTRL1
enum rdma_reg_dmactrl1 {
	RDMA_DMACTRL1_START_LSB = 0,    // Lance le DMA si mis à 1
	RDMA_DMACTRL1_SRCINC_LSB = 1,   // Active l'auto-incrémentation de SRC
	RDMA_DMACTRL1_DSTINC_LSB = 2,   // Active l'auto-incrémentation de DST
	RDMA_DMACTRL1_2D_MASK_LSB = 3,  // Active le masquage 2D si mis à 1
	RDMA_DMACTRL1_2D_XMIR_LSB = 4,  // Active le miroir selon l'axe X
	RDMA_DMACTRL1_FULLADDR_LSB = 6, // 0 : utilise la banque, 1 : adresse 24 bits
	RDMA_DMACTRL1_MODE_LSB = 7,     // 0 : standard, 1 : 2D
	RDMA_DMACTRL1_START_MASK = BIT(RDMA_DMACTRL1_START_LSB),
	RDMA_DMACTRL1_SRCINC_MASK = BIT(RDMA_DMACTRL1_SRCINC_LSB),
	RDMA_DMACTRL1_DSTINC_MASK = BIT(RDMA_DMACTRL1_DSTINC_LSB),
	RDMA_DMACTRL1_2D_MASK_MASK = BIT(RDMA_DMACTRL1_2D_MASK_LSB),
	RDMA_DMACTRL1_2D_XMIR_MASK = BIT(RDMA_DMACTRL1_2D_XMIR_LSB),
	RDMA_DMACTRL1_FULLADDR_MASK = BIT(RDMA_DMACTRL1_FULLADDR_LSB),
	RDMA_DMACTRL1_MODE_MASK = BIT(RDMA_DMACTRL1_MODE_LSB),
};

// Masques du registre DMACTRL2
// PARAMÈTRE DE MIROIR :
// 0b00 : pas de miroir
// 0b01 : miroir mode 0
// 0b10 : miroir mode 1
// 0b11 : miroir mode 2
enum rdma_reg_dmactrl2 {
	RDMA_DMACTRL2_XMIRR_LSB = 0, // Miroir sur l'axe X
	RDMA_DMACTRL2_XMIRR_MASK = 0x3,
};

En gros, lors de l’initialisation, il faut configurer un ensemble de paramètres liés à la géométrie de l’écran, à l’emplacement de la mémoire vidéo, à l’adresse source du sprite, etc. Ensuite, écrivez les coordonnées X, Y et les drapeaux (flags) de miroir selon les besoins, puis lancez la transaction DMA en écrivant dans DMACTRL1. Si le projet évolue, l’idée serait de disposer d’un ensemble de sprites préconfigurés, mais pour le moment vous n’avez que ce jeu de registres. Ainsi, pour afficher un second sprite, vous devez afficher le premier, puis modifier l’adresse source pour le nouveau sprite, ajuster les dimensions si elles changent, etc., et enfin l’afficher.

Concernant les personnes qui souhaiteraient une cartouche pour faire des tests : s’il y a assez d’intéressés, je peux en fabriquer une petite série, mais j’aurais peut-être besoin de quelques conseils pour des détails comme l’expédition, car c’est quelque chose que je n’ai encore jamais fait. J’habite en Espagne, donc l’envoi en Europe ne devrait pas poser trop de soucis, mais en dehors, cela pourrait être plus compliqué.

2 « J'aime »

Bonjour, j’ai intégré le support de la souris sur mon clone de démineur (sans mise à l’échelle X/Y pour le moment, mais j’ai préparé le code).

Mais il semble que WinAPE renvoie bit0 = 1 sur le port F990, donc c’est activé par défaut (et les valeurs pour deltaX et deltaY sont à -1 par défaut), alors peut-être que 0xFF quand rien ne répond sur un port est « normal » (je ne sais pas trop car je n’utilise pas beaucoup de matériel).

Auriez-vous un autre moyen de savoir si la ROMBOX Pi est présente afin de ne vérifier le port que lorsque c’est possible ? Ou peut-être inverser le bit 0, ou encore fournir une valeur spécifique à vérifier (pas seulement un seul bit) comme 142 ou 155 ?

Si vous souhaitez tester avec votre carte et me dire si tout fonctionne correctement, je peux vous l’envoyer par MP.

Exactement. Mieux vaut se débarrasser du DDI5 dès le départ et intégrer l’émulation de disque sur la même carte :wink: Le RP2350 peut gérer les deux https://youtube.com/playlist?list=PLa1DevUxKDmU&si=sxcJhFYr4qiDhYtl Nous ajouterons probablement l’extension de RAM en plus de la ROM et de l’émulation de disque pour la prochaine révision du PCB. Celle-ci n’a pas les broches nécessaires. Il faut faire des compromis. Cela dit, d’excellentes extensions de RAM comme celle de Revaldhino sont déjà disponibles. Mais un appareil tout-en-un a clairement son charme.

Dans tous les cas, le RP2350 EST INCROYABLE !!

WinApe n’émule pas cette cartouche, et il est fort probable que la lecture depuis ces ports renvoie 0xFF à chaque fois. SyX a patché quelques jeux et a également modifié MAME pour ajouter le support de la souris ROMBA, je pourrais lui demander de publier ses modifications. De plus, @SoftDevil pourrait essayer d’ajouter le support à Caprice.

En attendant qu’il y ait une version publique d’un émulateur prenant en charge ROMBA, si tu veux que je teste ton jeu, aucun problème, tu peux m’envoyer un message privé et je le testerai.

Concernant la mise à l’échelle fractionnaire, son utilisation est totalement facultative. La configuration par défaut devrait bien fonctionner pour la plupart des jeux, et si nécessaire, elle pourrait même être ajoutée sur un chargeur BASIC.

Le problème avec l’extension de RAM, du moins avec ma cartouche, c’est que je n’ai pas de RAM supplémentaire soudée sur la carte (et je ne prévois pas d’en ajouter). La seule RAM que je peux donc utiliser pour l’extension de mémoire est celle que le micrologiciel (firmware) n’utilise pas parmi les 520 Kio intégrés au RP2350. Selon ce qui se retrouve sur la cartouche, une extension de 256 Kio de RAM pourrait être envisageable, mais atteindre 512 Kio est impossible.

De toute façon, il ne devrait pas y avoir de collision tant qu’une application n’essaie pas d’utiliser la RAM, n’est-ce pas ? Alors peut-être qu’au lieu d’un commutateur, je pourrais écrire dans une configuration non volatile (modifiable via une écriture sur un port de configuration).