Le microprocesseur Motorola ColdFire
Le 68000 à la sauce RISC

Cela faisait quelque temps que le 68060 était sorti. Motorola semblait ne vouloir orienter ses futurs développements que vers la gamme Power PC, au grand dam des amoureux du code 68K, quand soudain un espoir est apparu.

Présentation

La gamme de processeurs ColdFire (le "feu froid", ou le "feu sous la glace") est dite de technologie VL-RISC (Variable Length - RISC). En fait de jeu d'instructions RISC à longueur variable, il s'agit tout simplement du jeu d'instructions CISC de la gamme 68K (ou plus précisément d'un sous-ensemble de celui-ci). C'est vrai qu'en comparaison d'un processeur comme que le Power-PC (réputé RISC) et son jeu d'instructions compliqué, la liste des opcodes 68K peut paraître d'une simplicité extrème.

Si la gamme 68K était classifiée sous la forme 680X0, où le X indique la génération du processeur, la gamme ColdFire est classifiée en 5XNN, X correspond également à la génération et les NN permettent de classifier les différents produits de cette génération. La première génération, n'a pratiquement pas été diffusée, il s'agissait surtout d'un galop d'essai, elle comprenait le 5102, une puce 100% compatible avec un 68EC040 (sans MMU ni FPU), cette puce a été peu distribuée. La deuxième génération (5202, 5203, 5204 et 5206) a été plus largement répandue, même si les membres de cette famille avaient le gros inconvénient de ne pas inclure d'unité de division. Cette carence a été corrigée dans la troisième génération, celle que nous allons décrire dans la suite de cet article. Quand à la quatrième génération, elle vient juste d'être disponible, je vous en reparlerai dans un futur article.

Les processeurs de la gamme ColdFire sont bien plus que de simple microprocesseurs, ils intègrent toute la logique pour en faire des ordinateurs embarqués complets, ce sont en fait également des micro-contrôleurs, ils intègrent ports série, parallèles, timers, contrôleurs d'interruption, DMA, contrôleur DRAM, décodage d'adresses...

Le 5307

Il s'agit du circuit de troisième génération le plus répandu et également le plus intéressant. Son jeu d'instructions est très proche de celui du 68000. En fait, 95% du code est exactement identique. Les 5% restants correspondent à des instructions peu utilisées, mais aussi, hélas, à des instructions importantes telles que DBcc ou ROL, ROR, ROXL et ROXR. Heureusement, depuis la troisième génération, Motorola s'est décidé à implémenter un décodage intégral des instructions illégales, il est donc possible d'émuler les instructions manquantes à la volée grâce à un code adéquat dans le TRAP de l'instruction ILLEGAL. Le 5307 inclut 4Ko de SRAM zéro wait state qui n'a aucune utilité sous TOS (rien a été prévu pour en tirer parti), on peut donc avantageusement y placer le code d'émulation des instructions manquantes. Une émulation reste toujours plus lente qu'un code natif, mais quand la puce tourne à 90 MHz et que la plupart des instructions s'effectue en un cycle, qui verra réellement la différence?

Les instructions en moins

ABCD, NBCD, SBCD
Instructions de calcul en "binaire codé décimal". Elles sont très rarement utilisées (on prèfère maintenant calculer tout en binaire puis convertir le résultat en décimal lors de l'affichage). Elles sont simples à émuler.

ANDI/EORI/ORI to SR/CCR
Ces instructions de modification des flags ont disparu. Il faudra utiliser un "MOVE from", puis un ANDI/EORI/ORI dans un registre, puis un "MOVE to".

CHK
Teste un registre et génère une exception en cas de débordement. Cette instruction ne doit rellement pas être souvent utilisée. Elle demeure malgré tout facile à émuler.

CMPM
Compare deux cellules mémoire avec un adressage indirect post-incrémenté (permet donc de comparer deux zones de mémoire). Peut être remplacé par les deux instructions move et cmp.

DBcc
Le BIG problème! C'est une des instructions les plus utilisée dans les programmes codés en assembleur (les compilateurs C ne savent pas s'en servir pour réaliser des boucles) et elle n'existe pas. On peut la remplacer par la séquence suivante:

    Bcc end
    SUBQ.w#1,Dn
    CMPI.w#-1,Dn
    BNE loop
    end:

L'émulation peut certainement être optimisée en testant Dn à zéro avant la décrémentation . Ici, le code est vraiment très lourd, mais on n'a pas le choix. Espérons juste que Motorola remette cette instruction dans les futures générations de ColdFire, comme ils l'on déjà fait en remettant la division dans la troisième génération de circuits.

EXG
Echange deux registres. Encore une instruction que je n'avais jamais eu l'occasion d'utiliser. En utilisant un registre intermédiaire, cela s'émule en trois move.

MOVE USP
La distinction entre pointeur de pile superviseur et utilisateur a été supprimée du ColdFire, en conséquence de quoi, cette instruction n'a plus lieu d'être.

MOVEP
Cette instruction a déjà disparu du 060 et est donc déjà émulée sur les Hadès et Milan qui en sont équipés.

ROL, ROR, ROXL, ROXR
La disparition de ces instructions est fort dommage. Elles sont souvent utilisées, en particulier pour des conversions de formats graphiques packbits-shifter. Espérons que la généralisation des modes graphiques true color en réduise le champ d'action.

RTR
Encore une instruction que je n'ai jamais eu à utiliser. On peut utiliser un RTE standard en modifiant le stack frame en conséquence (dites-moi si je me trompe).

TAS
Une instruction de test assez facile à émuler avec un bcc, un bra et deux move.

TRAPV
Génère un trap si le flag V (overflow). Aussi simple à émuler que l'instruction CHK.

Notez que la plupart des instructions émulées nécessitent un registre de données. Il va donc falloir en libérer un (D0 par exemple). L'empiler représenterait une perte de temps inutile, l'idéal est de le stocker dans la S-RAM avec le code de l'émulateur. Par ailleurs, certaines instructions ne disposent pas de tous les modes d'adressage permis par le 68000, nous aurons l'occasion de revenir la dessus dans un prochain article.

Les instructions en plus

Heureusement, tout n'est pas pour le pire. Le 5307 dispose également d'instructions supplémentaires. Qui, même si elles ne peuvent pas être utilisées par des applications déjà écrites, permettront d'écrire de nouveaux programmes encore plus rapides, en particulier grâce à l'unité MAC intégrée qui permet d'effectuer au sein même de la puce les calculs effectués généralement par un DSP externe (donc sans temps perdu à transférer les données par le port host ou le DMA).

EXTB
Extension directe d'un byte en long. Sur 68K il faut faire ext.w suivi de ext.l pour réaliser la même opération.

MAC, MACL MSAC, MSACL
Opérations de multiplication-accumulation. Elles permettent des opérations telles que: fransformées de fourier, transformées de cosinus discrètes (DCT, compression JPEG), filtrage, interpolation, matrices de convolution (effets graphiques).

MOVE from/to CCR/ACC/MACSR/MASK
Permettent de lire ou écrire dans les registres:
CCR: Registre de codes-condition du processeur
ACC: Accumulateur de l'unité MAC
MACSR: Registre d'état de l'unité MAC
MASK: Masque d'adressage de l'unité MAC

MOVEC
Transfert vers un registre de contrôle. Permet l'accès aux ressources spécifiques du ColdFire en terme d'entrées-sorties intégrées. Est essentiellement destiné à initialiser la puce.

REMS, REMU
Reste sur 32 bits de la division. Les DIVS et DIVU classiques ne fournissent un reste que sur 16 bits.

DIVS,DIVU, MULS, MULU
Extension de ces instructions pour supporter des opérandes et des résultats en 32 bits.

TRAPF
Variante de l'instruction NOP. TRAPF ne fait rien mais occupe 2, 4 ou 6 octets selon le mot d'adressage utilisé.

L'unité MAC

Certainement la partie la plus fun du ColdFire. L'unité MAC est l'unité de calcul principal de tout DSP (en autres du 56001). Le fait d'en avoir une directement intégrée au CPU va permettre à des personnes comme moi, qui n'ont jamais tenté de programmer le DSP (pour ne pas avoir à se prendre la tête avec les transferts CPU-DSP et avec le reste des instructions DSP) de s'y mettre.

MAC: Multiply and Accumulate. Permet de multiplier deux registres entre-eux et d'ajouter le résultat à un accumulateur. Il existe 4 variantes de cette instruction

mac Rw,Rx,<shift>
Rw est muliplié par Rx, le résultat est éventuellement décalé de 1 bit à droite ou à gauche puis est additionné au contenu de l'accumulateur.
msac Rx,Rx,<shift>
Opération similaire sauf que le résultat est soustrait au contenu de l'accumulateur.
macl Rw,Rx,<shift>,<ea>,Ry
Opération mac classique plus stockage dans Ry du contenu de l'adresse <ea> préalablement masquée par le registre MASK.
msacl Rx,Rx,<shift>
Opération similaire sauf que le résultat est soustrait au contenu de l'accumulateur.

Les modes d'adressage pour l'adresse effective <ea> de macl et msacl sont (An), (An)+, -(An), (d16,An) et (d16,PC), le mode d'adressage n'influe pas sur le temps d'exécution de l'instruction. D'ailleurs au niveau des temps d'exécution, ils sont très réduits, les voici:

mac.w

msac.w:

1 cycle

mac.l

msac.l:

3 cycles

macl.w

msacl.w:

3 cycles

macl.l

msacl.l:

5 cycles


En tenant compte du fait que mac et msac effectuent 2 opérations et que macl et msacl en effectuent 3, c'est monstrueux (le 5307 tourne à 90 MHz).

Question simple: à quoi servent les instructions macl et msacl?
Réponse: elles permettent de charger dans un registre une donnée destinée à servir d'opérande lors de la prochaine opération mac. Ce "prefetch" réalisé en soft permet d'optimiser les accès au pipeline.

Les registres spécifiques à l'unité MAC sont au nombre de trois:
ACC (32 bits): l'accumulateur, qui reçoit les résultats des calculs.
MASK (16 bits): registre de masquage, permet d'utiliser une table en boucle sans avoir à revenir manuellement au début.
MACSR(8 bits): registre d'état.

Un exemple

Pour vous prouver la simplicité d'utilisation de l'unité MAC et effectuer également un petit bench, nous allons écrire une routine de filtrage d'image 3x3 (selon les coefficients, on peut effectuer un flou, une netteté, une détection des contours...). Je n'ai pas encore pu essayer ce programme, donc je vous le livre tel quel, avec le risque qu'il comporte des défauts, mais ça reste toujours une base de travail.

Nous allons filtrer une image en niveaux de gris (c'est plus simple). La détection des bords n'est pas effectuée, cela signifie que des données extérieures à l'image (donc parasites) vont s'intégrer dans le calcul des bords, cela peut être évité grace à un code un peu plus compliqué (mais pas nécessairement plus lent). On pourrait fort bien ne faire qu'une seule boucle pour calculer tous les pixels en bloc, mais ces deux boucles imbriquées permettent d'ajouter très simplement le code de détection des bords. Aucun test n'est effectué quand à d'éventuels débordements de l'accumulateur, cela pourrait être effectué par sécurité.

d0: pixel lu
d1: coefficient à appliquer (et temporairement le résultat)
d2: largeur d'une ligne
d3: largeur d'une ligen en négatif
d4: position en X
d5: position en Y
a0: pointeur source
a1: pointeur destination
a2: pointeur sur la matrice 3x3
a3: adresse de la matrice







line:

pixel:

clr.l d0
move.l width,d2
move.l d2,d3
neg.l d3
movea.l #matrice,a3
move.l height,d5


move.w d2,d4

move.w #0,acc
movea.l a3,a2
move.w (a2)+,d1
move.b -1(a0,d3.w),d0
macl.w d0,d1,(a2)+,d1
move.b (a0,d3.w),d0
macl.w d0,d1,(a2)+,d1
move.b 1(a0,d3.w),d0
macl.w d0,d1,(a2)+,d1
move.b -1(a0),d0
macl.w d0,d1,(a2)+,d1
move.b (a0),d0
macl.w d0,d1,(a2)+,d1
move.b 1(a0),d0
macl.w d0,d1,(a2)+,d1
move.b -1(a0,d2.w),d0
macl.w d0,d1,(a2)+,d1
move.b (a0,d2.w),d0
macl.w d0,d1,(a2)+,d1
move.b 1(a0,d2.w),d0
mac.w d0,d1
move.l acc,d1
move.b d1,(a1)+
lea.l 1(a0),a0
subq.l #1,d4
bne pixel
subq.l #1,d5
bne line
_______________________

(1)
(4)
(1)
(1)
(1)
(4)

(1)

(1)
(1)
(4)
(5)
(3)
(5)
(3)
(5)
(3)
(5)
(3)
(4)
(3)
(5)
(3)
(5)
(3)
(5)
(3)
(5)
(1)
(3)
(1)
(1)
(1)
(1)
(1)
(1)


Conclusion

Ce programme prend 25.191.852 cycles pour traîter une image de 640 par 480 pixels, soit 0s28 à 90 MHz. Une image de la même taille, mais en true-color 24 bits mettra 0s84. De surcroît, ce code peut certainement être amélioré. A titre de comparaison le même traîtement true-color prend 6s avec Digital Lab sur un Hadès040 sous MonoTOS. Je n'ai pas d'Hadès060 à ma disposition, mais je pense que je ColdFire doit encore aller 2 à 3 fois plus vite et ceci pour un prix... Le 060 coûte 1500 FF, le ColdFire 10 fois moins!

Pascal Barlier

- Mis en page sous Expresso -