MC68020

Généralités


Après le MC68000, il est temps de s'attaquer à un plus gros processeur, le MC68020.

Il s'agit là du digne successeur du 68000 !!


Dans le genre belle carte, voici celle que Marc m'a gentiment donnée, je la trouve vraiment très belle.


Le but premier était de récupérer des composants pour ma carte MC68020 ou pour la prochaine MC68000, mais je trouve presque dommage de la scrapper et je me demande si je ne vais pas plutôt l'encadrer pour l'accrocher dans mon bureau...


J'ai déjà dessoudé un MC68661 (celui qui est en bas à gauche du MC68000 avant que je ne le dessoude...) et c'est quelque part un peu dommage.

D'un autre côté, ça redonnerait vie à ce MC68000 et à toute sa petite famille, donc : réflexion en cours ...


Marc m'a également donné un MC68861 qui combine DUART, et quelques lignes de PIA pour la carte MC68020.

Carte MC68000 de Marc

J'ai mis d'autres photos sur cette page: La carte de Marc.

Revenons-en au MC68020 ...


Le 68020 est le successeur de 68000, en version full 32 bits.


Son bus de données sort du processeur 68020 en 32 bits, de D0 à D31. De ce fait, le câblage d'un prototype est beaucoup plus délicat.

Fort heureusement le MC68020 possède un mode 8 bits, ainsi qu'un mode 16 bits en plus de son mode natif 32 bits.


Pour signifier la largeur du bus de données, deux signaux sont utilisés sur cette maquette: DSACK0\ et DSACK1\, qui sont l'équivalent de DTACK\ et UDS\ LDS\ du MC68000.


Pour ces essais, j'ai pu acheter un processeur MC68020RC16 sur un site de matériel d'occasion, sans aucune garantie de son bon fonctionnement.

Monté sur une carte veroboard, les premiers essais ont pu commencer après une petite lecture du manuel MC68020 de Motorola ...

Le dessous de la carte:

Le dessous de la carte est beaucoup moins fun, avec pas mal de difficultés pour les bus...

Assembleur:


Tous les programmes Assembleur utilisés ici sont compilés avec Ed!, le cross assembleur 68000 que j'avait écrit en 1994 en Turbo Pascal, et qui est disponible en téléchargement ici.

Etant actuellement sous MacOS, j'utilise l'excellent émulateur Boxer qui tourne donc sur MacOS et qui permet très simplement de lancer et utiliser Ed, comme sur un ancien PC sous MSDOS.

Il est vraiment très cool, et il suffit de glisser le répertoire contenant Ed sur l'icône de Boxer, et une fenêtre DOS s'ouvre. Il suffit de taper Ed et return pour le lancer, comme sur un PC.

En plus de lancer Ed, Boxer crée un répertoire qui émule C: et qui permet de récupérer les fichiers compilés sur le Mac.

C'est vraiment excellent.

La seule restriction est qu'il ne fonctionne pas sous Catalina. Il faudra donc ressortir un vieux Mac du placard (j'ai un vieux MacBook blanc pour ça, qui fait très bien l'affaire...).

L'autre solution que j'utilise de plus en plus est Easy68K qui tourne sous Windows, ou bien sur MacOS en le faisant passer par PlayOnMac, qui permet de faire tourner des programmes Windows sur Mac. C'est une très bonne solution également, car il existe deux autres utilitaires avec Easy68K qui sont EasyBin (qui permet d'éditer et préparer les fichiers BIN), et Sim68K qui est un simulateur qui permet de faire trouner le programme en examinant tous les registres du 68000).

Cet ensemble est vraiment excellent.

MC68020 et Arduino ATMega:


Pour voir si mon MC68020 d'occasion pouvait encore fonctionner, j'ai monté une maquette où la ROM a été remplacée par un Arduino ATMega suivant le schéma ci-dessous.

Dans cette configuration, le MC68020 adresse l'Arduino comme s'il s'agissait d'une ROM, ce dernier répondant en mettant sur le bus de données le code correspondant à l'adresse sélectionnée par le 68020. Ensuite, il suffit ensuite pour lui d'acquitter DSACK0\.


Avec ce peu de code implanté dans l'Arduino, il a été facile de voir que le MC68020 que j'avais acheté répondait bien aux sollicitations, savait adresser l'Arduino comme une ROM, et savait répondre aux signaux de synchronisation.


L'Arduino ATMega n'est pas suffisamment rapide pour faire fonctionner le MC68020 correctement, mais ça a suffit pour voir les principaux ensembles du processeur fonctionner à l'oscilloscope.

Avec un peu de code, tout a pu fonctionner:

MC68020 en mode 8 bits:


Après cette phase de tests, j'ai pu reprendre une vielle carte sur laquelle était câblé un MC6809.


Après un petit moment de décâblage du 6809 et de recâblage en mode 68020 8 bits, voilà ce que ça donne:

Sur la carte, il n'y a pas de RAM, seulement une EEProm de type 28C64 afin de réaliser un fonctionnement minimal, ce qui a plus de chances d'aboutir du premier coup...

De fait, les appels aux sous-programmes sont interdits car le Stack Pointer n'est pas initialisé.


On retrouve donc le MC68020, avec son eeprom et un buffer sur lequel seulement 2 Leds sont câblées, ce qui est suffisant pour faire un clignotement gauche/droite et voir que tout fonctionne.

Un peu de logique câblée, et voilà...


Il n'y a pas de CPLD ou autre pour la logique externe, car bien qu'étant adepte des FPGA et autre CPLD, je préfère garder une logique hard autour du micro, comme on aura pû le faire il y a quelques dizaines d'années. Les composants en jaune ne sont pas montés pour l'instant, on verra plu stard.

Question de principe...


Le schéma de la carte à ce stade est le suivant:

Description des signaux:


Comme mentionné, le micro est passé en mode 8 bits pour ces premiers essais.


Pour cela, il suffit de forcer le signal DSACK1\ à Vcc, et d'acquitter DSACK0\ à Gnd à la fin du transfert sur les bus.


Par cette combinaison, le MC68020 sait qu'il est en mode 8 bits. Il va alors transmettre ses données, qui restent 32 bits pour lui, uniquement sur le poids fort de son DataBus (D31-D24).

Pour transmettre une données 32 bits, il fera donc cette opération 4 fois sur D31-D24.


Voici le détail de ce décodage DSACK0\ DSACK1\ d'après la doc Motorola:

Dans ce tableau, DSACK0\ et DSACK1\ étant actifs à l'état bas, Negated équivaut à mettre l'entrée à Vcc et Asserted équivaut à mettre l'entrée à Gnd.

Décodage d'adresse:


Le décodage d'adresse se fait à l'aide des signaux DataStrobe\ (DS\) et AdressStrobe\ (AS\).


Les vecteurs d'interruption (qui ne sont pas pris en compte pour l'instant), ainsi que le Stack Pointer et le Program Counter (PC) sont situés en bas du mapping mémoire, soit à partir de l'adresse $00000000.

Le MC68020 ayant 255 vecteurs sur 32 bits, ceux-ci occupent donc 255 x 4 = 1020 octets.

Le dernier vecteur se trouvant alors à l'adresse 1020 ($000003FC), et celui-ci occupant 4 octets, la première adresse disponible pour notre programme sera donc 1020 + 4 = 1024 ($00000400).


Notre vecteur PC sera donc initialisé à $00000400.


Le Stack Pointer n'est pas initialisé pour l'instant, ni les autres vecteurs car nous n'avons pas de RAM à cette étape du schéma.


On va donc utiliser directement A0-A12 sur l'eeprom, et par exemple A16-A18 sur le décodeur d'adresse 74LS138 (U5), en utilisant la sortie Q0 du décodeur afin de valider le boitier eeprom de $00000000 à $00001FFF.

On retrouve bien la totalité du boitier eeprom décodé: $00001FFF = 8192 octets = 8 Ko, ce qui correspond bien à notre boîtier eeprom 28C64 (8Ko sur 8 bits).


Comme le MC68020 est en mode 8 bits par le traitement de DSACK0\ DSACK1\, le bus de données de l'eeprom est relié à D24-D31 du processeur.


Le buffer de sortie de l'eeprom est quant à lui directement validé par le signal DS\ (DataStrobe\).


Elle sera détectée par le 74LS138 comme les autres boitiers, et sera adressée par A12-A0.

Génération de DSACK0\ DSACK1\:


Afin d'indiquer au MC68020 que le cycle en cours est en mode 8 bits, nous allons positionner DSACK1\ à Vcc, et DSACK0\ à Gnd quatre coups d'horloge après le décodage d'adresse.

La double bascule 74LS74 génère une horloge à CLOCK div 4, et la logique câblée va donc amener la sortie de cette bascule sur DSACK0\ lorsqu'un des boitiers est adressé par le 74LS138.


Lorsqu'aucun boitier n'est adressé par le 74LS138, la double bascule 74LS74 est bloquée au reset et DSACK0\ reste à Vcc.


On va ainsi acquitter DSACK0\ quatre coups de CLOCK après le décodage des boitiers par les 74LS138.


DSACK1\ étant figé à Vcc, le MC68020 comprends alors qu'il est en mode 8 bits et reconduit le reste de sa donnée 32 bits sur D24-D31, et ce en 4 fois.


J'essaierai de mettre des oscillogrammes en photo, ce qui sera plus clair qu'un long discours...

Buffer des Leds:


Le buffer des Leds est directement décodé par Q7 du décodeur 74LS138, et se trouve donc à l'adresse $00070000.

Code assembleur, compilé avec ED:


Le code assembleur pour faire tourner cette carte MC68020 est le suivant, afin d'allumer l'une des deux Leds, et de suivre les signaux à l'oscilloscope:


Premier programme:


; MC68020: premier programme de test

VECTEUR

SSP $00000000

RAM $00000000

ROM $00000400

MAIN

; Programme principal

@Init MOVE.L #$AAAAAAAA, D1 ; Chargement D1 pour OUT

MOVE.L D1, $00070000 ; Sortie sur OUT

@Bcle JMP @Bcle



Le code est très simple afin de minimiser les risques d'erreurs.


De même, les transferts s'effectuent en mots longs .L afin de s'affranchir dans un premier temps du transtypage en 8 bits effectué par le MC68020 suivant notre schéma.


En changeant la valeur de chargement AA à 55 sur deux eeproms différentes, on peut voir que la Led 1 ou la Led 2 s'allument.


La gestion des registres est faite en entiers Longs, même si le bus externe est 8 bits. Ceci permet de garder un code simple, sans extrapolation du MC68020 sur la longueur des mots à transmettre.


Cette méthode semble un peu simpliste de nos jours où l'on utilise des debuggers et compilateurs de plus en plus évolués, mais le meilleur principe reste ici KISS (Keep It Simple, Stupid...)

Si ça ne fonctionne pas, il n'y a que peu de choses à mettre en cause, et si ça fonctionne, la partie la plus importante du schéma est validée.


Ce code a été assemblé avec Ed qui se trouve en téléchargement à la page MC68000 de ce site...


Second programme:


Le second programme utilise des boucles et des sauts, afin de vérifier si l'adressage du MC68020 reste correct sur une plus grande quantité d'instructions enchainées.

Comme il n'y a toujours pas de RAM, il n'y a pas de possibilité d'utiliser de sous programmes par JSR, on va donc répéter le même code :


; MC68020: second programme de test

VECTEUR

SSP $00000000

RAM $00000000

ROM $00000400

MAIN

; Programme principal

@Init MOVE.L #$AAAAAAAA, D1 ; Chargement chenillard

MOVE.B D1, $00070000 ; Sortie sur Chenillard

MOVE.L #$0FFFFFFF, D0 ; Init Compteur pour tempo

@Bcl1 DBEQ D0, @Bcl1

MOVE.L #$55555555, D1 ; Chargement chenillard

MOVE.B D1, $00070000 ; Sortie sur Chenillard

MOVE.L #$0FFFFFFF, D0 ; Init Compteur pour tempo

@Bcl2 DBEQ D0, @Bcl2

JMP @Init



L'ensemble fonctionne également correctement, ce qui va permettre de passer à l'étape suivant au niveau du schéma et du code ...

NAND OR or AND NAND, that is the question...


Sur le schéma précédent, la génération de DSACK0\ était faite avec un deux NAND et un OR, qui allait sur le Reset des bascules D.

N'ayant pas de OR de type 74LS32 dans les tiroirs, il faut trouver une autre solution.


On va alors utiliser deux AND et une NAND, ce qui donnera au final le même résultat, les composants en jaune n'étant toujours pas montés à ce stade:

Démonstration:


On pose Y_ROM = sortie du 74LS138, noté ROM\ sur le schéma, idem pour les autres signaux.


Sachant que (a.b)\ = a\ + b\, et que a\.b\ = (a + b)\, on peut dire que:


RST_DSACK0\ = (Y_ROM . Y_OUT)\ + (Y_RAM . Y_LCD)\ ( Schéma 1 )

= (Y_ROM\ + Y_OUT\) + (Y_RAM\ + Y_LCD\)

= ( (Y_ROM\ + Y_OUT\) + (Y_RAM\ + Y_LCD\) ) \\ (On complémente deux fois pour pouvoir distribuer )

= ( (Y_ROM\ + Y_OUT\)\ . (Y_RAM\ + Y_LCD\)\ ) \

= ( ( Y_ROM . Y_OUT) . (Y_RAM . Y_LCD) ) \ ( Schéma 2 )


Et voilà ...


La prochaine étape va maintenant être de câbler l'afficheur LCD.

Afficheur LCD


L'afficheur LCD choisi est le même modèle que celui de la carte Lisa68K, à savoir un 2x8 caractères.

Ce n'est pas très grand, mais ça suffit amplement pour les premiers essais, et il ne tient pas de place sur la carte.


Sa datasheet peut être trouvée sur Internet en tapant simplement LCD 2x8, mais elle reste la même que pour les 2x16 ou 4x16 caractères.

J'ai pris celle d'un modèle CM0820S1LYC7-J2.

Décodage d'adresse:

Au niveau du décodage d'adresse, il faut apporter une modification au schéma précédent afin de l'adresser sur une adresse 32 bits: la sélection de registres RS va être adressée par A2 au lieu de A0 comme je l'avait fait précédemment.


De ce fait, l'afficheur aura les adresses $00060000 et $00060004.

Le schéma avec afficheur est disponible en téléchargement en bas de cette page, et la RAM en jaune n'est toujours pas montée.


Programme de tests:

Le programme de test de l'afficheur ne peut toujours pas utiliser les sous-programmes du fait de l'absence de RAM pour le Stack Pointer (ce devrait être la prochaine étape...).

Le code est donc long et répétitif, mais il permet de tester l'afficheur.
De même, les écritures sur OUT se font maintenant avec des MOVEQ et des .B au lieu des .L, ce qui est tout de même plus élégant...


; MC68020: Mise en route de l'ecran LCD

VECTEUR

SSP $00000000

RAM $00000000

ROM $00000400


CONST

OUT = $00070000 ; Out

LCD = $00060000 ; Ecran LCD - config -

LCDat= $00060004 ; Ecran LCD - caracteres -


MAIN

; Programme principal

@Init MOVEQ #$38, D0 ; 2 lignes, 5x7 dots, 8 bits

MOVE.B D0, LCD


MOVE.L #$0000FFFF, D0

@WLc0 DBEQ D0, @WLc0



MOVEQ #$01, D0 ; Clear screen

MOVE.B D0, LCD


MOVE.L #$0000FFFF, D0

@WLc1 DBEQ D0, @WLc1



MOVEQ #$02, D0 ; Return Home

MOVE.B D0, LCD


MOVE.L #$0000FFFF, D0

@WLc2 DBEQ D0, @WLc2



MOVEQ #$0E, D0 ; Turn display ON

MOVE.B D0, LCD


MOVE.L #$0000FFFF, D0

@WLc3 DBEQ D0, @WLc3



MOVEQ #$06, D0

MOVE.B D0, LCD ; Init and select DDRAM


MOVE.L #$0000FFFF, D0

@WLc4 DBEQ D0, @WLc4



@Car1 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car1 ; Attente Busy Flag= 0

MOVEQ #$46, D0

MOVE.B D0, LCDat


@Car2 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car2 ; Attente Busy Flag= 0

MOVEQ #$72, D0

MOVE.B D0, LCDat


@Car3 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car3 ; Attente Busy Flag= 0

MOVEQ #$65, D0

MOVE.B D0, LCDat


@Car4 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car4 ; Attente Busy Flag= 0

MOVEQ #$64, D0

MOVE.B D0, LCDat


@Wai MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Wai ; Attente Busy Flag= 0

MOVEQ #$C0, D0 ; Ligne 2

MOVE.B D0, LCD


@Car5 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car5 ; Attente Busy Flag= 0

MOVEQ #$36, D0

MOVE.B D0, LCDat


@Car6 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car6 ; Attente Busy Flag= 0

MOVEQ #$38, D0

MOVE.B D0, LCDat


@Car7 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car7 ; Attente Busy Flag= 0

MOVEQ #$30, D0

MOVE.B D0, LCDat


@Car8 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car8 ; Attente Busy Flag= 0

MOVEQ #$32, D0

MOVE.B D0, LCDat


@Car9 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @Car9 ; Attente Busy Flag= 0

MOVEQ #$30, D0

MOVE.B D0, LCDat


@Loop MOVEQ #$01, D1 ; Chargement chenillard

MOVE.B D1, $00070000 ; Sortie sur Chenillard


MOVE.L #$0FFFFFFF, D0 ;Init Compteur

@Bcl1 DBEQ D0, @Bcl1


MOVEQ #$02, D1 ; Chargement chenillard

MOVE.B D1, $00070000 ; Sortie sur Chenillard


MOVE.L #$0FFFFFFF, D0 ;Init Compteur

@Bcl2 DBEQ D0, @Bcl2


JMP @Loop

Câblage de la RAM:


La RAM D449C de 2Ko va également être montée en mode 8 bits, de la même façon que ce qui a été fait sur l'eeprom.


On pourra prendre un 6116, mais n'ayant que des D449C dans les tiroirs, mon choix s'est naturellement porté sur celle-ci...


Par contre, sa datasheet est difficile à trouver, et on va donc se baser sur une RAM statique 2Ko standard type CY6116 par exemple.


Elle sera détectée par le 74LS138 comme les autres boitiers, et sera adressée par A10-A0.

Le fichier pdf est également téléchargeable en bas de la page

Programme de test avec Sous-programmes:

Maintenant que la RAM est câblée sur la carte MC68020, on va pouvoir initialiser le Stack Pointer et utiliser les sous-programmes avec des instructions comme JSR (Jump to SubRoutine).

Le programme est tout de suite plus élégant ...

; MC68020: Mise en route de la RAM

; Code sur la base de la carte LIsa 68000

VECTEUR

SSP $00010FF0

RAM $00010000

ROM $00000400


CONST

OUT = $00070000 ; Out

LCD = $00060000 ; Ecran LCD - config -

LCDat= $00060004 ; Ecran LCD - caracteres -

Pile = $00010E00 ; Pile de sauvegarde generale - en plus du stack -


St1 = " 68020 ^"

St2 = " Ready ^"

MAIN

; Programme principal

LEA Pile, A0 ; Init Pointeur Pile A0

JSR @IniLcd ; Init LCD

LEA St1, A2 ; Affichage St1

JSR @StrLcd

JSR @Lg2Lcd

LEA St2, A2 ; Affichage St2

JSR @StrLcd

@Loop JSR @Chenil ; Appel au chenillard

JMP @Loop



; Chenillard sur OUT


@Chenil MOVE.L D0,(A0)+ ; Sauvegarde D0

MOVEQ #$AA, D0 ; Chargement chenillard

MOVE.B D0, $00070000 ; Sortie sur Chenillard


MOVE.L #$0FFFFFFF, D0 ;Init Tempo

@Bcl1 DBEQ D0, @Bcl1


MOVEQ #$55, D0 ; Chargement chenillard

MOVE.B D0, $00070000 ; Sortie sur Chenillard


MOVE.L #$0FFFFFFF, D0 ;Init Compteur

@Bcl2 DBEQ D0, @Bcl2

MOVE.L -(A0), D0

RTS




; Init LCD


@IniLCD MOVE.L D0,(A0)+

MOVEQ #$38, D0 ; 2 lignes, 5x7 dots, 8 bits

MOVE.B D0, LCD

JSR @WaiLcd ; Tempo reset LCD

JSR @CursOf ; Curseur Off

JSR @ClrLCD ; Efface ‚cran

MOVE.L -(A0), D0

RTS


; Display On, Curseur on, not Blink


@CursOn MOVE.L D0, (A0)+

MOVEQ #$0E, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS


; Display On, Curseur off, not Blink


@CursOf MOVE.L D0, (A0)+

MOVEQ #$0C, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS


; Efface l'cran LCD


@ClrLCD MOVE.L D0, (A0)+

MOVEQ #$01, D0 ; Clear screen

MOVE.B D0, LCD

JSR @WaiLCD

MOVEQ #$02, D0 ; Return Home

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS



; Tempo d'init du LCD

@WaiLcd MOVE.L D0, (A0)+

MOVE.L #$00004FFF, D0

@WaiLc1 DBF D0, @WaiLc1

MOVE.L -(A0), D0

RTS


; Ecrit le caractere de (D0) sur le LCD


@CarLcd MOVE.L D1, (A0)+

@CarLc1 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @CarLc1 ; Attente Busy Flag= 0

MOVE.B D0, LCDat

MOVE.L -(A0), D1

RTS


; Ecrit la chaine pointe par A2 sur LCD

@StrLcd MOVE.L D0, (A0)+

@StrLc2 MOVE.B (A2)+, D0 ; Envoie le caractre en cours @CarLcd

CMP.B #$5E, D0 ; tant qu'on ne pointe pas sur ^: EoString.

BEQ @StrLc1

JSR @CarLcd

BRA @StrLc2

@StrLc1 MOVE.L -(A0), D0

RTS


; Lcd: Ligne 1


@Lg1Lcd MOVE.L D0, (A0)+

JSR @WaiLCD

MOVE.B #$80, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS


; Lcd: Ligne 2


@Lg2Lcd MOVE.L D0, (A0)+

JSR @WaiLCD

MOVE.B #$C0, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS

Connecteur Alimentation USB-B:


Afin de faciliter l'alimentation, l'ensemble est alimenté par une alimentation de type chargeur de téléphone USB.

Pour ce faire, un connecteur USB-B est monté sur la carte:

Le schéma est alors celui-ci:

DUART MC68681:

A présent, on va pouvoir monter un circuit d'interfaçage afin de communiquer avec un ordinateur, PC ou Mac.

L'interface la plus simple à mettre en oeuvre sera une liaison série de type RS232.

Si l'ordinateur connecté ne dispose pas de liaison série, ce qui est fort possible, il suffira d'utiliser un convertisseur Série/USB, ce qui fonctionne très bien.

Plus tard, on pourra embarquer un tel convertisseur sur notre carte.


Le connecteur standard de l'interface RS232 est un DB9 femelle en mode DCE, et un femelle DB9 mâle en mode DTE, on va donc implanter les deux.


Le connecteur DCE permettra de se connecter directement à un port série d'ordinateur (ou à un convertisseur RS232 / USB standard), tandis que le connecteur DTE permettra de brancher un équipement tel qu'une souris série par exemple.


Pour créer cette interface RS232, on va utiliser le DUART MC68681 que Marc m'a donné.

DUART MC68681

L'avantage de ce circuit, est qu'en plus de l'interface série, il dispose d'un Timer et de lignes de PIA intégrées (interface parallèle).


Horloge et générateur de Bauds:

La liaison série RS232 n'a pas de ligne d'horloge séparée, la synchronisation se fait avec le timing des bits transmis.

Pour générer ces signaux, le circuit DUART (ou UART ou ACIA pour certaines familles de processeurs) utilise un générateur de Bauds, qui peut être interne ou externe. Ce circuit génère une horloge aux temps normalisés, qui va permettre une transmission des bits sur la ligne série de façon connue des autre circuits périphériques que l'on connectera à notre interface.


Les vitesses de transmission les plus utilisées sont par exemple 4800, 9600, 19200 Bauds, ou leurs multiples et sous-multiples.

Comme le DUART MC68681 possède un générateur de Bauds intégrés, on n'aura pas besoin d'en câbler un sur la carte.


Pour travailler aux fréquences normalisées, le MC68681 utilise un quartz d'une valeur un peu exotique, à savoir 3,6864 MHz.


Pourquoi une telle valeur ??


Si on regarde la valeur de ce quartz par rapport aux vitesses de transmissions normalisée, on s'aperçoit de la chose suivante:


3,6864 MHz / 19200 = 192

3,6864 MHz / 9600 = 384

3,6864 MHz / 4800 = 768


Si on continue ainsi avec les autres valeurs de transmission normalisées, on va s'apercevoir que tous les résultats sont des nombres entiers, ce qui est plutôt une bonne chose pour créer une horloge.


Pour passer de 19200 Bauds à 4800 Bauds par exemple, il suffira de rediviser notre horloge par 19200/4800 = 4.


Si on montait notre générateur de Bauds avec un quartz de 1MHz par exemple, on aurait des valeurs de diviseurs plus exotiques:


1MHz / 19200 = 52,0833

1MHz / 9600 = 104,166

1MHz / 4800 = 208,333


On voit qu'ici le résultat est décimal, et est faux par rapport à nos valeurs normalisées.

Pour retomber juste, il faudrait diviser notre horloge primaire de 1MHz par une valeur décimale de 52,0833 au lieu de 52 pour tomber juste, ce qui est beaucoup plus compliqué à réaliser avec de simples bascules.

Si on divise par la valeur la plus proche de 52 par exemple, on aurait:


1MHz / 52 = 19230.76 Bauds.


Pour une valeur normalisée de 19200 Bauds, on arriverait donc à 19230 Bauds, ce que certains circuits récepteurs n'accepteront pas.


Si on prenait l'horloge système de notre carte qui est à 16MHz, on aurait le même problème:


16MHz / 19200 = 833,333


En fait, comme on peut difficilement diviser notre Clock avec une valeur décimale, on va contourner la difficulté en utilisant un quartz ou un oscillateur qui aura une valeur décimale.

Si on le choisit bien, il suffira alors de diviser sa sortie par la bonne valeur entière, et le tour est joué.


Les valeurs les plus courants sont donc 3,6864MHz ou 14,7456MHz ou par exemple 4,9152MHz.

On comprend mieux pourquoi la datasheet du MC68681 demande un quartz de 3,6864MHz.


Le problème est que je n'ai pas de quartz de 3,6864MHz comme demandé ....


Par contre, la carte de Marc a deux oscillateurs de valeurs décimales.... 3,93216 MHz et 4,9142MHz !!!


Peut-on utiliser le 3,93216MHz ?


Essayons avec 19200 Bauds:

3,93216MHz / 19200 = 204,8 -> Valeur décimale, pas bon...


On va donc essayer d'utiliser le second à 4,9152MHz.


4,9152MHz / 19200 = 256

4,9152MHz / 9600 = 512

4,9152MHz / 4800 = 1024


Impeccable, on va utiliser celui-ci.


Que dit la datasheet du MC68681 ? Elle dit que l'on peut utiliser un quartz de 3,6864MHz, ou un oscillateur d'une valeur max de 4MHz.


Il va donc falloir diviser l'horloge fournie par notre nouvel oscillateur par 2, ce qui donnera 2,4576MHz.


2,4576MHz / 19200 = 128

2,4576MHz / 9600 = 256

2,4576MHz / 4800 = 512



Plutôt Quartz ou plutôt Oscillateur ??


La solution avec oscillateur pour le MC68681 permet de se passer de quartz, et de récupérer l'oscillateur de la carte de Marc.

Par contre, je n'ai plus de 74LS74 ou équivalent pour ramener cette horloge à une vitesse acceptable par le DUART... Dilemme ...


Profitant donc d'une commande de composants, j'ai acheté un quartz de 3,6864 MHz et je réserve l'oscillateur pour plus tard.


Voici le schéma, avec les deux possibilités:

Le lien de téléchargement du schéma en format pdf se trouve en bas de page.



Et le DTACK\ ?


Le MC68681 est un périphérique 68000, donc avec une validation de bus de type DTACK\.

Le MC68020, de part sa structure 32 bits avec la possibilité de passer en 16 ou 8 bits, utilise DSACK0\ et DSACK1\ pour la même fonction.


Lorsque l'on aura plusieurs périphériques de la famille 68000 sur la carte, tous les DTACK\ devront aller au même endroit, sur DTACK_DUART\ du schéma.

Comme ces périphériques ont leur sortie DTACK\ de type Open drain, on peut donc tous les relier ensembles, avec une résistance de rappel au +5V.


En rebranchant la carte, elle refonctionne comme avant l'ajout du DUART, ce qui est plutôt encourageant.


On voit que la carte bien évolué depuis le début, avec en haut les deux connecteurs SubD9.


Par contre, le câblage devient un peu délicat...


Lorsque les tests seront terminés, on verra pour faire un circuit imprimé, avec le 68020 en mode 32 bits.


L'idée est de passer en mode 32 bits, avec 4 RAM, 4 EEProm, de la mémoire dynamique, un écran TFT en SPI mais on n'en est pas encore là...

Reste maintenant la partie logicielle à continuer....

MC68681 In et Out:


Afin de tester l'adressage correct du DUART MC68681 ainsi que la génération correcte du DTACK\, on peut commencer par les fonctions du port IN et du port OUT de ce circuit.

Une Led Rouge a été rajoutée sur OUT7 et un bouton poussoir a été ajouté sur IN5.


Ayant également ajouté un support ZIF (Zero Insertion Force) pour l'eeprom, la carte ressemble à présent à ceci (In5 et Out7 sont câblés en bas à gauche):

Le MC68681 ayant son adresse de base en $0000 0000 0005 0000, le registre de configuration des sorties OPCR va se trouver en écriture à l'adresse Base + $0D = $0000 0000 0005 000D.

OUT:

La doc du MC68681 nous indique que pour configurer OUT7 du DUART en pin de sortie utilisable comme bon nous semble, il faut mettre à 0 le bit b7 du registre OPCR, donc OPCR = $00 mettra toutes ses pins OUT en sortie.

En mettant ces bits à 1, on active d'autres fonctions spécifiques de ces pins (voir doc du MC68681).


La mise à 1 et à 0 des ces sorties se fera par l'écriture du bit correspondant dans le registre OPR. Cette opération s'effectue en utilisant les registres OPR.Set (Base + $0E) et OPR.Reset (Base + $0F), mais les sorties du port OP0 à OP7 ont des niveaux inversés par rapport au positionnement de ces bits.

Par exemple, pour mettre la sortie OP7 à 1, il faut mettre le bit OPR.7 à 0 et inversement. Pour mettre OPR.7 à 0, il suffira de mettre OPRReset.7 à 1.


Donc: OPRReset = 1 => OUT7 à 1 et OPRSet = 1 => OUT7 à 0.


Dans le source suivant, j'ai directement fait l'inversion dans ClrOut7 et dans SetOut7.


IN:

Pour la lecture de IN5, il suffira de faire une lecture du registre IP (Base + $0D).



Voici le source du programme de test qui change l'état de la Led OUT7 suivant l'état du bouton poussoir IN5, tout en continuant le chenillard d'origine sur le buffer:



; MC68020: Mise en route du DUART MC68681

; Sauvegarde SourceTree

; Code sur la base de la carte LIsa 68000

; Fred: microcontroller.robotics@gmail.com

; !!! Attention: Ed ne prend pas les TAB en debut de ligne

; Mettre des espaces

; !!! Attention: Suivant la longueur des constantes ROM,

; le PC peut etre a une adresse impaire (Bug de Ed)

; V5: Essai de OUT sur le DUART

; V6: Essai de IN sur le DUART


VECTEUR

SSP $00010FF0

RAM $00010000

ROM $00000400


CONST

OUT = $00070000 ; Out

LCD = $00060000 ; Ecran LCD - config -

LCDat= $00060004 ; Ecran LCD - caracteres -

Pile = $00010E00 ; Pile de sauvegarde generale - en plus du stack -

OPCR = $0005000D

SET_OPR = $0005000E

CLR_OPR = $0005000F

IP_DUART= $0005000D


St1 = " 68020 ^"

St2 = "IniDUART ^"

StRdy = "Ready V6 ^"

MAIN

; Programme principal

LEA Pile, A0 ; Init Pointeur Pile A0

JSR @IniLcd ; Init LCD


LEA St1, A2 ; Affichage St1: 68020

JSR @StrLcd


JSR @Lg2Lcd

LEA St2, A2 ; Affichage St2: IniDUART

JSR @StrLcd


JSR @IniOut7 ; Init Duart Out-7


JSR @Lg2Lcd

LEA StRdy, A2 ; Affichage StRdy: Ready

JSR @StrLcd

@Loop JSR @Chenil ; Appel au chenillard avec Leds et DUART

JSR @ReadIn5 ; Lecture In-5 du DUART

JMP @Loop




@IniOut7 MOVE.L D0,(A0)+

MOVEQ #$00, D0 ; Output Out-7 en Set/Rst (b7=0)

MOVE.B D0, OPCR ; Chargement OPCR

MOVE.L -(A0), D0

RTS




@ClrOut7 MOVE.L D0,(A0)+

MOVEQ #$80, D0 ; Output Out 7 inversee

MOVE.B D0, SET_OPR ; Chargement OPR Set

MOVE.L -(A0), D0

RTS



@SetOut7 MOVE.L D0,(A0)+

MOVEQ #$80, D0 ; Output Out 7 inversee

MOVE.B D0, CLR_OPR ; Chargement OPR Reset

MOVE.L -(A0), D0

RTS


@ReadIn5 MOVE.L D0,(A0)+

CLR.L D0

MOVE.B IP_DUART,D0 ; Lecture IP

AND.B #$20, D0 ; Masque IP5

BNE @Read0

JSR @SetOut7

BRA @Read1

@Read0 JSR @ClrOut7

@Read1 MOVE.L -(A0),D0

RTS



@Chenil MOVE.L D0,(A0)+ ; Sauvegarde D0

MOVEQ #$AA, D0 ; Chargement chenillard

MOVE.B D0, $00070000 ; Sortie sur Chenillard


MOVE.L #$0FFFFFFF, D0 ;Init Tempo

@Bcl1 DBEQ D0, @Bcl1


MOVEQ #$55, D0 ; Chargement chenillard

MOVE.B D0, $00070000 ; Sortie sur Chenillard


MOVE.L #$0FFFFFFF, D0 ;Init Compteur

@Bcl2 DBEQ D0, @Bcl2

MOVE.L -(A0), D0

RTS



; Init LCD


@IniLCD MOVE.L D0,(A0)+

MOVEQ #$38, D0 ; 2 lignes, 5x7 dots, 8 bits

MOVE.B D0, LCD

JSR @WaiLcd ; Tempo reset LCD

JSR @CursOf ; Curseur Off

JSR @ClrLCD ; Efface ecran

MOVE.L -(A0), D0

RTS

; Display On, Curseur on, not Blink

@CursOn MOVE.L D0, (A0)+

MOVEQ #$0E, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS

@CursOf MOVE.L D0, (A0)+ ; Display On, Curseur off, not Blink

MOVEQ #$0C, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS

@ClrLCD MOVE.L D0, (A0)+ ; Efface l'cran LCD

MOVEQ #$01, D0 ; Clear screen

MOVE.B D0, LCD

JSR @WaiLCD

MOVEQ #$02, D0 ; Return Home

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS

@WaiLcd MOVE.L D0, (A0)+ ; Tempo d'init du LCD

MOVE.L #$00004FFF, D0

@WaiLc1 DBF D0, @WaiLc1

MOVE.L -(A0), D0

RTS

@CarLcd MOVE.L D1, (A0)+ ; Ecrit le caractre de (D0) sur le LCD

@CarLc1 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE @CarLc1 ; Attente Busy Flag= 0

MOVE.B D0, LCDat

MOVE.L -(A0), D1

RTS

@StrLcd MOVE.L D0, (A0)+ ; Ecrit la chaine pointe par A2 sur LCD

@StrLc2 MOVE.B (A2)+, D0 ; Envoie le caractre en cours @CarLcd

CMP.B #$5E, D0 ; tant qu'on ne pointe pas sur ^: EoString.

BEQ @StrLc1

JSR @CarLcd

BRA @StrLc2

@StrLc1 MOVE.L -(A0), D0

RTS

@Lg1Lcd MOVE.L D0, (A0)+ ; Lcd: Ligne 1

JSR @WaiLCD

MOVE.B #$80, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS

@Lg2Lcd MOVE.L D0, (A0)+ ; Lcd: Ligne 2

JSR @WaiLCD

MOVE.B #$C0, D0

MOVE.B D0, LCD

JSR @WaiLCD

MOVE.L -(A0), D0

RTS


La suite au prochain épisode ...


Remarque:

Ed souffre de quelques imperfection, il nécessiterait un bon dépoussiérage mais je n'ai plus tous les sources.

Donc soit on continue de l'utiliser en étant prudents, soit il faut en réécrire un autre sous Windows ou MasOS mais je n'aurais pas le temps car d'autres projets sont en cours, soit trouver un assembleur (ou C ?) qui fonctionne correctement, de préférence sous MacOS ou DOS (ce qui permettrait de le faire tourner sur MACOS et Windows (avec Boxer).

A méditer ...



Easy68K

Pour l'instant, j'ai pu ressortir un vieux eeePC sous Windows XP, et y installer Easy68K (http://www.easy68k.com) .

Après quelques modifications du dernier source, j'ai pu créer un fichier .bin pour mon programmateur, en mode 8 bits.


Voilà ce que ça donne, et la partie déclarative a dû être adaptée, mais tout s'est fait facilement.

Il faut dire que Ed! ne respectait pas la syntaxe Motorola, car lorsque je l'ai développé, je n'avais ni assembleur Motorola de référence, ni guide de l'assembleur...




; MC68020: Mise en route du DUART MC68681

; Sauvegarde SourceTree

; Code sur la base de la carte LIsa 68000

; Fred: microcontroller.robotics@gmail.com

; !!! Attention: Ed ne prend pas les TAB en debut de ligne

; Mettre des espaces

; !!! Attention: Suivant la longueur des constantes ROM,

; le PC peut etre a une adresse impaire (Bug de Ed)

; V5: Essai de OUT sur le DUART

; V6: Essai de OUT sur le DUART

; V7: Adaptation du source pour Easy68K sous Windows



CODE EQU 0

DATA EQU 1

VECTEURS EQU 2


SECTION VECTEURS

org $0

SSP dc.l $00010FF0 ; Vecteur SSP: Stack Pointer

PC dc.l START ; vecteur PC


SECTION CODE

ORG $400


RAM EQU $00010000


OUT EQU $00070000 ; Out

LCD equ $00060000 ; Ecran LCD - config -

LCDat equ $00060004 ; Ecran LCD - caracteres -

Pile equ $00010E00 ; Pile de sauvegarde generale - en plus du stack -

OPCR equ $0005000D

SET_OPR equ $0005000E

CLR_OPR equ $0005000F

IP_DUART equ $0005000D


St1 dc.b ' 68020 ^'

St2 dc.b 'IniDUART ^'

StRdy dc.b 'Ready V7 ^'

START:

; Programme principal

LEA Pile, A0 ; Init Pointeur Pile A0

JSR .IniLcd ; Init LCD


LEA St1, A2 ; Affichage St1: 68020

JSR .StrLcd


JSR .Lg2Lcd

LEA St2, A2 ; Affichage St2: InitDUART

JSR .StrLcd


JSR .IniOut7 ; Init Duart Out-7


JSR .Lg2Lcd

LEA StRdy, A2 ; Affichage StRdy: Ready

JSR .StrLcd

.Loop JSR .Chenil ; Appel au chenillard avec Leds et DUART

JSR .ReadIn5 ; Lecture In-5 du DUART

JMP .Loop




.IniOut7 MOVE.L D0,(A0)+

MOVEQ #$00, D0 ; Output Out-7 en Set/Rst (b7=0)

MOVE.B D0, OPCR ; Chargement OPCR

MOVE.L -(A0), D0

RTS




.ClrOut7 MOVE.L D0,(A0)+

MOVEQ #$80, D0 ; Output Out 7 inversee

MOVE.B D0, SET_OPR ; Chargement OPR Set

MOVE.L -(A0), D0

RTS



.SetOut7 MOVE.L D0,(A0)+

MOVEQ #$80, D0 ; Output Out 7 inversee

MOVE.B D0, CLR_OPR ; Chargement OPR Reset

MOVE.L -(A0), D0

RTS


.ReadIn5 MOVE.L D0,(A0)+

CLR.L D0

MOVE.B IP_DUART,D0 ; Lecture IP

AND.B #$20, D0 ; Masque IP5

BNE .Read0

JSR .SetOut7

BRA .Read1

.Read0 JSR .ClrOut7

.Read1 MOVE.L -(A0),D0

RTS



.Tempo MOVE.L D0,(A0)+

MOVE.W #$9FFF, D0 ;Init Tempo

.Tmp1 DBEQ D0, .Tmp1 ; DBxx ne fonctionne que sur des Word

MOVE.L -(A0),D0

RTS

.Chenil MOVE.L D0,(A0)+ ; Sauvegarde D0

MOVEQ #$AA, D0 ; Chargement chenillard

MOVE.B D0, $00070000 ; Sortie sur Chenillard


JSR .Tempo


MOVEQ #$55, D0 ; Chargement chenillard

MOVE.B D0, $00070000 ; Sortie sur Chenillard


JSR .Tempo

MOVE.L -(A0), D0

RTS



; Init LCD


.IniLCD MOVE.L D0,(A0)+

MOVEQ #$38, D0 ; 2 lignes, 5x7 dots, 8 bits

MOVE.B D0, LCD

JSR .WaiLcd ; Tempo reset LCD

JSR .CursOf ; Curseur Off

JSR .ClrLCD ; Efface ecran

MOVE.L -(A0), D0

RTS

; Display On, Curseur on, not Blink

.CursOn MOVE.L D0, (A0)+

MOVEQ #$0E, D0

MOVE.B D0, LCD

JSR .WaiLCD

MOVE.L -(A0), D0

RTS

.CursOf MOVE.L D0, (A0)+ ; Display On, Curseur off, not Blink

MOVEQ #$0C, D0

MOVE.B D0, LCD

JSR .WaiLCD

MOVE.L -(A0), D0

RTS

.ClrLCD MOVE.L D0, (A0)+ ; Efface l'cran LCD

MOVEQ #$01, D0 ; Clear screen

MOVE.B D0, LCD

JSR .WaiLCD

MOVEQ #$02, D0 ; Return Home

MOVE.B D0, LCD

JSR .WaiLCD

MOVE.L -(A0), D0

RTS

.WaiLcd MOVE.L D0, (A0)+ ; Tempo d'init du LCD

MOVE.L #$00004FFF, D0

.WaiLc1 DBF D0, .WaiLc1

MOVE.L -(A0), D0

RTS

.CarLcd MOVE.L D1, (A0)+ ; Ecrit le caractre de (D0) sur le LCD

.CarLc1 MOVE.B LCD, D1

ANDI.B #$80, D1

BNE .CarLc1 ; Attente Busy Flag= 0

MOVE.B D0, LCDat

MOVE.L -(A0), D1

RTS

.StrLcd MOVE.L D0, (A0)+ ; Ecrit la chaine pointe par A2 sur LCD

.StrLc2 MOVE.B (A2)+, D0 ; Envoie le caractre en cours .CarLcd

CMP.B #$5E, D0 ; tant qu'on ne pointe pas sur ^: EoString.

BEQ .StrLc1

JSR .CarLcd

BRA .StrLc2

.StrLc1 MOVE.L -(A0), D0

RTS

.Lg1Lcd MOVE.L D0, (A0)+ ; Lcd: Ligne 1

JSR .WaiLCD

MOVE.B #$80, D0

MOVE.B D0, LCD

JSR .WaiLCD

MOVE.L -(A0), D0

RTS

.Lg2Lcd MOVE.L D0, (A0)+ ; Lcd: Ligne 2

JSR .WaiLCD

MOVE.B #$C0, D0

MOVE.B D0, LCD

JSR .WaiLCD

MOVE.L -(A0), D0

RTS

END START


Maintenant que tout ça fonctionne, il faudrait que j'arrive à le faire tourner sur Mac avec Wine par exemple, le temps d'écrire un autre compilateur pour MacOS.

En tout cas, je peux dire que Easy68K semble excellent, de même que les autres programmes qui l'accompagnent (Simulateur, utilitaire Bin). L'aide intégrée est également excellente.


MC68020 avec RAM.pdf
MC68020 et MC68681 IN OUT.pdf
MC68020 avec LCD.pdf
MC68020 et MC68681 Quartz et Oscillateur.pdf