Nous utilisons des cookies pour améliorer votre expérience.

MacBidouille

Les CPU des Mac : Motorola 68000 (2/2)

On va rentrer un peu plus dans le dur, en abordant des spécificités du M68000 ainsi que des différences fondamentales avec le 8086 sorti un an plus tôt. La première partie est ici.

Bande-passante du bus avec MOVEM.L

La bande passante nécessaire pour une interface graphique est très élevée, Apple en avait l'expérience avec le Lisa, et le M68000 à 8 Mhz contre 5 Mhz pour ce dernier avait outre la capacité de faire 2 millions de cycles de lecture ou écriture en RAM, de le faire en 16 bits, une bande-passante théorique de 4 Mo par seconde. Contre 1 Mo par seconde très théorique pour un 6809.

Cela aurait été gâché en utilisant une boucle de transfert mémoire 32 bits (MOVE.L + DBRA) car coûtant au bas mot 32 cycles pour 4 octets lus et 4 écrits, soit une bande-passante effective de 2 Mo/s, 50% des cycles de bus perdus en quelque sorte!

MOVEM.L intervient ici avec la capacité de lire et d'écrire de multiples registres depuis ou vers la RAM, jusqu'à 512 bits à la fois et au prix de multiples cycles de bus, une façon différente d'optimiser ceux-ci si on pense aux REP MOVSW/STOSW du 8086.

En copie 256 bits utilisant alors 8 registres 32 bits, MOVEM.L va prendre environ 160 cycles par opération incluant un DBRA, on peut taper au-dessus de 3 Mo/s, un gain net de 50%, mais ça n'est pas le seul intérêt de MOVEM.L...

Langages de haut niveau, incluant langages objects avec GC et capabilities

Comme pour le 6809 les modes d'adressages du 68000 conviennent parfaitement à du C ou du Pascal compilé, les multiples registres d'adresse pouvant être indifféremment utilisés et même le pointeur de pile en mode utilisateur sans bloquer les interruptions!

Les 8 registres de données sont aussi très utiles permettant de stocker des données temporaire, de passer des paramètres de fonction via ceux-ci ainsi que leur pendant pour les adresses.

Et en langage objet compilé, on va retrouver notre MOVEM.L, capable depuis une référence de lire dans 4 registres 32 bits à la fois un compteur pour le garbage collecting, un pointeur vers un array du code des fonctions de la classe ou toute autre structure, et un array vers les données de l'instance, ainsi que des capabilities.

En 2 opérations on peut tester les capabilities (AND ou BTST + Bcc), une seule pour vérifier les limites (CHK), on peut rajouter un AND.W #$fffc,Dn (voir AND.W Dm,Dn avec Dm constant!) pour s'assurer de pointer sur un élément (alignement 32 bits), et accéder une données ou appeler indirectement du code en une seule autre instruction.

On peut aussi implémenter un système de pagination des instances via l'exception créée par CHK. Et sans impact sur les performances hors pagination.

Cela permet d'implémenter des modèles très complexes, y compris compilés, et il me semble que c'était le but du 68000, un aspect visionnaire de cette architecture.

Avantages et inconvénients d'un adressage flat sur un adressage segmenté

L'adressage segmenté du 8086 a été probablement pensé pour permettre d'exécuter facilement du code conçu pour le 8080, le modèle 64 Ko utilisé par MS-DOS pour les .com (CS=DS=ES=SS) facilitant énormément le portage/recompilation/réassemblage.

Ensuite on pourra étendre ces programmes pour utiliser différents segments, pour terminer avec les fameux FAR PTR très lourds (recalcul du segment + déplacement) mais permettant d'accéder à toute la mémoire disponible d'un seul tenant, au prix des performances et de code C dépendant de l'architecture.

Une solution pragmatique, permettant d'offrir à la fois un modèle connu avec du code facilement portable, tout en ouvrant la voie à 1 Mo d'espace adressable.

D'un autre coté Motorola était parti sur un modèle d'adressage flat, logiquement 32 bits dans les registres d'adresses, 24 bits adressables sur le 68000 via son bus d'adresse 23 bits.

Chaque pointeur peut adresser tout l'espace sans aucun effort, pas de limite de segments de 64 Ko, parcourir des Mo de données se fait à la même vitesse que 64 Ko ou moins, un code plus simple et plus efficace quand on parle de gros volumes de données.

Je vote pour les pointeurs 32 bits, sauf que ceux-ci consomment évidemment deux fois plus de mémoire, quand stockés, quand paramètres dans la pile, et nécessitent en général deux fois plus d'accès au bus, au final ralentissant l'exécution et étant gloutons en RAM.

Sur ce point l'histoire a donné raison à Motorola, le mode d'adressage plat c'est imposé.

Amour/haine avec les compilateurs C

Les compilateurs C de l'époque n'ont rien à voir avec les actuels, étant conçus pour des architectures plus simples, limitées en terme de registres et produisant du code trop direct s'appuyant généralement sur un sous-ensemble de registres prédéfinis, par exemple D0 comme accumulateur (AX), D1 comme compteur de boucle (CX), un ou deux pointeurs, et générant des instructions simples et elles-aussi prédéfinies, sans exploiter vraiment les registres et les modes d'adressage du 68000.

Par exemple une boucle de transfert strcpy(), sera généralement générée avec les pieds, les pointeurs en paramètres dans la pile, avec une tonne d'échanges inutiles avec celle-ci, et même en copiant ses pointeurs dans des variables locales associé a1 un registre (register en C), les échanges continueront au lieu d'exploiter directement les registres.

Cela peut se voir dans le Cribble d'Ératosthène de Byte 1983-01 (merci à @patrick_a_a), où le 68000 à 8 Mhz est quasiment quatre fois plus rapide que le 8086 à la même fréquence en langage d'assemblage, son véritable potentiel, mais dès qu'on passe aux compilateurs C avec le même code portable, les performances s'écroulent et il est largué!

Alors bien sûr on a joué du register pour essayer de faire en sorte que les compilateurs se sortent les doigts du cul, du loop unrolling aussi, mais au final ceux-ci n'étaient tout simplement pas fait pour une architecture orientée sur les registres, et cela changera à partir de la fin des années 80, puisqu'ayant émergé une multitude d'architectures RISC ayant de très nombreux registres.

Le 68000 était en avance sur son temps et une architecture même réussie n'est rien sans les logiciels dont les compilateurs, qui en tirent le meilleur.

Pour le coup, l'histoire a aussi donné raison à Motorola mais trop tard, le choix pragmatique d'Intel a payé!

Les limites d'une MMU: pas de reprise d'exécution

Le 68000 paraissait parfait pour implémenter un modèle de mémoire virtuelle paginée, avec même un mode "superviseur" avec sa propre pile, sauf que si tant est qu'on puisse implémenter une MMU externe faisant d'ailleurs perdre 1 cycle à chaque accès mémoire, une grosse perte, il n'est pas possible de gérer une faute d'accès pour paginer des blocs sur un disque dur.

Le 68000 ne savait pas récupérer une telle erreur et continuer l'exécution des instructions, rendant quasi-inutile le mode superviseur.

Il y a eu des exceptions (sic) dont Apollo Computer et son double-68000, l'un pour l'exécution proprement dite, l'autre pour intercepter les erreurs de la MMU et réinterpréter l'instruction ayant causé la faute. Cela sera réglé sur les 68010/68012 deux ans plus tard.

Le manque d'une FPU

C'est un manque criant, Intel avait développé dès le début des coprocesseurs spécialisés dont le fameux 8087 pour augmenter les performances et permettre ainsi de concevoir des ordinateurs pour des marchés spécifiques, évidemment le calcul et la simulation dans ce cas, le Fortran en tête.

Motorola avait moins de puissance de feu, et comptait sur les qualités du 68000, mais dès qu'on parlait de calcul flottant, plus encore pour de la simulation, il était à la ramasse et au mieux pouvait-on y accoler une vieille FPU destinée aux 8 bits, à la fois compliquée et inefficace!

Le manque d'un processeur d'entrée/sortie

Là aussi Intel avait fait fort avec son processeur d'entrée/sortie programmable 8089, dans l'esprit des processeurs d'IO des mini-ordinateurs et au-dessus, idéaux pour de la gestion et de la comptabilité surtout associé au 8087 et son mode BCD à 18 chiffres.

Peu de machines utilisèrent cela, le marché visé étant très conservateur pour le dire poliment, et le 8089 sombra rapidement dans l'oubli!

Les DMA permettant des entrées/sorties asynchrones ont remplacé ces coprocesseurs pour la plupart des usages, même si on verra une résurgence de cette bonne idée sous la forme de cartes RAID une décennie plus tard.

Conclusion

Les philosophies d'Intel et Motorola avec leur première génération 16 bits sont à l'opposé, pragmatique pour Intel et visionnaire pour Motorola.

L'histoire commerciale a donné raison au premier, et sa façon de faire que je qualifierais d'agile: on répond juste à la demande, pour le reste on verra plus tard.

Mais en même temps avec nos CPU 64bits basés sur nombre de registres et un mode d'adressage flat avec MMU, la vision de Motorola était bien plus moderne et porteuse d'avenir.

C'est ce qui a permis aux premiers programmes du Macintosh de pouvoir tourner sur des 68020, 68030 et suivant, à pleine vitesse en exploitant toute la mémoire disponible, tandis qu'un programme fait pour le 8086 ne tournait que plus vite sans pouvoir exploiter plus de mémoire (ni de nouveaux périphériques ou composants d'ailleurs).

Sondage

Comptez-vous acheter un Vision Pro ?