Les CPU des Mac : Scorpius
TL;DR
Apple a créé une CPU au potentiel fabuleux pour des cas de niche, avec des moyens pharaoniques dont un Cray qui a après pris la poussière, mais totalement inadaptée pour les logiciels existants de la famille 68000 ou aucun portage de logiciel venu du monde des workstations ou des PC.
Pire encore inadaptée pour les OS multitâches qui apparaissaient de plus en plus et qui étaient évidemment l'avenir de l'informatique individuelle dont le Macintosh.
Un échec absolument fabuleux, magistral, à nul autre pareil!
Motorola avait annoncé en 1988 que l'avenir n'était plus la famille 68000 CISC mais le nouveau 88000 RISC, alors que le 68030 était un succès, très compétitif, et que le Mac IIx qui en était équipé impressionnait tout le monde.
Apple avait peu d'options à ce point pour protéger ces intérêts: faire des Macintosh sur une nouvelle plateforme et sans aucune garantie pour l'avenir surtout avec Motorola, relancer les descendants de l'Apple ][ et sa compatiblité logicielle, ou même créer sa propre CPU, soyons fou!
En fait Apple a fait les trois sur 3 ans entre 1989 et 1991!
John Sculley
Je dois dire qu'évidemment j'avais trouvé un peu cavalier le limogeage de Steve Jobs par l'ex-vendeur de soda.
Mais je pense qu'il était mérité et d'un autre coté qu'il a été temporairement bénéfique à Apple, mais aussi à Steve Jobs qui a appris de ces erreurs, de son immense échec qui est aussi une réussite indubitable, et est revenu plus puissant que jamais.
John Sculley croyait en Apple, et je pense aussi au Macintosh et ses ingénieurs, et quand des voies faciles auraient pu être empruntées, comme aller vers le leader Intel ou simplement passer au Motorola 88000, il a lancé le projet Aquarius en 1989.
Le projet Aquarius
Le projet Aquarius consistait à concevoir une CPU RISC en interne chez Apple et appelée Scorpius, des puces avec les idées les plus avancées de l'époque, avec d'ailleurs certains point communs avec les premiers ARM dans ce qu'ils ont de plus radicaux sur les transactions mémoires.
Apple n'avait jamais développé de CPU, même si évidemment la société avaient plusieurs puces custom à son actif, peut-être la passion l'a-t'elle emporté sur la raison?
Une chose est certaine, John Sculley croyait en Apple et ses forces vives, et dans le Macintosh.
Apple dépense sans compter
Comme dans Jurassic Park, John Sculley a dépensé sans compter, jusqu'à acheter un super-ordinateur Cray pour le projet, et sans qu'on ai de détails précis et corroborés, possiblement à la fois pour le design de la puce, mais aussi comme émulateur de celle-ci, pour la création des outils logiciels dont elle aurait besoin.
Il a été postérieurement reproché cela comme une gabegie, mais si le projet avait réussi et nos Macintosh avec des puces Apple en leur sein dès 1989, les mêmes auraient soulignés ce coup de maître!
L'architecture radicale
Scorpius peut avoir de 1 à 4 CPU RISC ayant chacune 4 PU que j'appellerais threads et non cœurs, capable donc de supporter jusqu'à 16 threads, mais uniquement 4 processus à chaque instant.
Chaque thread ou PU a 16 registres généraux dont 5 dédiés, un jeu d'instruction limité encodé avec 16 bits par instructions, nécessitant un Prefix Register et des instructions surnuméraires pour charger 8 bits à la fois dans celui-ci pour les constantes...
Une architecture RISC de type Harvard, enfin pas vraiment Harvard puisque chaque groupe de 4 threads appelées PU au sein d'une CPU ou nœud se partagent le cache d'Instruction, le cache de Données ainsi que la TLB, ce qui donne le la: ça n'est pas une CPU avec 4 cœurs, mais plutôt une CPU capable d'exécuter 4 threads du même processus simultanément. Et limité à un seul processus à chaque instant.
Il existe 4 modes de fonctionnement, SISD, SIMD, MISD et MIMD!
SISD fait exécuter une seule thread sur la CPU 4-threads, avec 3 threads bloquées, ce mode est surtout utilisé pour les interruptions.
SIMD fait exécuter en parallèle le même code sur 4 jeux de données en parallèle, transformant alors la CPU en mono-thread 4x32 bits, équivalent à du SSE apparu 10 ans plus tard sur le Pentium III.
MISD est vraiment original puisque exécutant plusieurs instructions différentes sur la même donnée, transformant alors cette CPU en mono-thread capable d'exécuter 4 instructions en parallèle (pipeliné en cascade en fait).
MIMD est le mode le plus courant où la CPU peut exécuter indépendamment 4 threads d'un même process, sur des données communes.
Le dernier point étonnant et posant des problèmes pour les compilateurs classiques, ainsi que pour des implémentations ultérieures, c'est le Shadow Branching: l'instruction suivant un branchement conditionnel ou non est toujours exécutée!
Outre la perte de temps dans une boucle, sauf à mettre la première instruction de celle-ci à cet endroit, pour les compilateurs traditionnels c'est une énorme nouveauté et à l'époque complexe à gérer sauf à placer un NOP systématiquement...
Le modèle memoire, NUMA en pire!
La mémoire est locale à chaque CPU, pas un problème quand on en a qu'un, mais quand on en a 4, ça se complique, avec la nécessité de passer par l'autre CPU ou nœud pour y accéder en lecture comme en écriture.
Cela amène aussi la capacité de dialoguer entre CPU via la mémoire et un mécanisme d'interruption sur écriture géré sur la CPU branchée sur la mémoire.
On est très loin de la mémoire unifiée, on est non-seulement sur un modèle NUMA, mais plus encore cela a des impacts en terme de gestion des pages mémoires de l'OS sur les systèmes multi-CPU.
Et c'est pour ça que les caches d'Instructions et de Données sont modifiables par des instructions spécifiques, pour précharger, invalider ou faire écrire en mémoire une ligne de cache.
Le premier problème est que pour accéder à de la mémoire partagée en lecture, comme pour les architectures mémoire NUMA, il est important et des fois essentiels de recopier ces données en mémoire locale en configuration multi-CPU pour éviter un goulet d'étranglement en lecture.
Cela limite aussi la capacité à travailler sur un grand ensemble de données directement, il vaut mieux le segmenter par lot de threads ou par CPU.
Le second problème est qu'il n'y a pas de Bus Snooping, les caches ne se mettent pas à jour ou invalidées quand les données sont changées, nécessitant d'invalider la ligne de cache avant toute lecture, augmentant derechef la bande-passante mémoire nécessaire lorsqu'on consulte les données créées ou modifiées sur une autre CPU.
Réciproquement, si une CPU génère des données pour une ou plusieurs autres, il lui faut flusher les lignes de cache correspondantes pour s'assurer que la mémoire contienne les modifications.
Plus exotique, quand la gestion de mémoire virtuelle libère une page, il faut alors interrompre toutes les autres CPU pour leur faire invalider cette même page de leurs caches. C'est extra-terrestre.
La compatibilité
0 que nada, comme pour le 88000 de Motorola d'ailleurs.
On peut bien entendu envisager des solutions d'émulation, qui tourneraient alors bien plus lentement que sur du 68030 et probablement même du 68000, ou la transpilation comme sur les Mac Apple Silicon pour le code x86, là aussi plus lent faute d'un nombre de registres largement supérieur qui est un point essentiel pour Rosetta 2.
Imaginez une simple opération mémoire, un incrément: ADDQ.L #1,(A0)
Il faut alors sauver un registre en mémoire, charger la donnée, l'incrémenter, écrire la données en mémoire, faire une comparaison (pour le status register), puis recharger le registre depuis la mémoire. 6 instructions.
L'autre option étant d'avoir des registres du 68000 en mémoire (D3 à D7 et A3 à A5 par exemple) mais c'est pire pour du code 68000 optimisé exploitant l'ensemble des registres ou un ADD.L Dx, Dy peut se traduire en 5 instructions!
Donc incompatible, et faute d'un fichier de registre plus étendu, peu à même de faire tourner plus rapidement le code 68000 existant, les 16 threads étant absolument inutiles puisque ce code mono-thread et non automatiquement parallélisable à cette époque.
Conclusion
Inadapté pour du code existant mono-thread de la famille 68000.
Un cauchemar pour les Devs devant à la fois multithreader leurs programmes mais aussi tenir compte de l'aspect NUMA de l'architecture mémoire, ce qui peut amener la nécessiter de recopier des données localement pour accélérer leur accès.
Aussi totalement différent des modèles multiprocesseurs existant, où chaque unité d'exécution peut indépendamment exécuter toute thread de tout processus, modèle essentiel pour les OS modernes supportant le multi-tâche.
Impossibilité de faire tourner plus de 4 processus séparés simultanément sur un système 4 CPU 16 threads, avec une inefficacité incroyable puisqu'un processus simple mono-thread monopolise 1 CPU 4 threads à la fois qui se partagent le TLB et les caches L1.
Théoriquement avec sa capacité de monter à 16 threads en 1989, son mode SIMD, Scorpius avait le potentiel d'être la CPU ou la multi-CPU la plus performante de son époque.
Mais avec les choix fait, seules les applications très multithreadées et tournant quasi-indépendamment de toute autre au sein finalement d'un OS monotache comme le Finder en auraient pu exploiter le potentiel.
Peut-être la CPU idéale pour Photoshop sous le Finder?
Le projet a été abandonné après le prototype Antares (1 CPU ou nœud 4 threads) et on ne sait ce qu'il est advenu du prototype Venus (4 CPU ou nœuds 16 threads). Un coup d'épée dans l'eau, très onéreux!
Et mon humble avis est que ce machin ne ressemblait à rien pour un OS multi-processus multi-thread, peut-être le meilleur cas d'usage en aurait été une GPU ou une workstation mono-processus avec des logiciels spécialisés genre CAD.
Apple ne va pas s'en tenir là et après cette expérimentation ratée, va essayer une des autres voies pour sauver l'avenir du Macintosh...