Motorola 68000
# Motorola 68000

Il Motorola 68000 (nome in codice MC68000) è un microprocessore CISC a 16/32 bit.

È stato inizialmente progettato, prodotto e commercializzato da Motorola a partire dal 1979, ed in seguito prodotto e commercializzato dalla Freescale Semiconductor, ex Semiconductor Products Sector di Motorola dalla quale si è separata nel corso del 2004.

Come primo membro della famiglia di microprocessori m68k il suo software in generale è compatibile con gli altri processori suoi successori.

Il modello 68000 è ancora utilizzato per fini didattici, mentre, dopo vent'anni, la sua architettura resta ancora una scelta popolare in nuovi progetti.

## Storia

Originariamente il MC68000 è stato progettato per essere un processore per usi generici. È stato utilizzato da diversi produttori di personal computer come Amiga, Atari e Apple. Molte console lo hanno utilizzato, per esempio il Sega Genesis/Sega Mega Drive, l'Atari Jaguar, il Neo Geo e molte macchine da sala giochi. Nel Sega Saturn, il 68000 era dedicato alla gestione del suono.

Molti progettisti lo hanno utilizzato e apprezzato e dal loro lavoro sono nati Amiga 1000, Atari ST, vari modelli di Macintosh, l'originale Sun Microsystems e le macchine UNIX della SGI. Il processore è stato utilizzato anche dai server Apollo/Domain.

I successori del 68000 sono stati utilizzati per molto tempo dalle macchine Unix dato che la sua architettura era molto simile a quella del Digital PDP-11 e VAX e quindi erano macchine eccellenti per eseguire programmi scritti in linguaggio C. Il 68000 ha avuto anche molto successo come microcontroller; è stato utilizzato da aziende quali HP, Printronix e Adobe per costruire stampanti. Da una sua derivazione sono nati i processori CPU32 e Coldfire utilizzati in milioni di sistemi di automazione industriale. È stato utilizzato anche in apparecchiature mediche per il suo vantaggioso rapporto costo/affidabilità. Nel 2001 la versione Dragonball è stata utilizzata dalla Palm Computing per realizzare i propri PDA e anche Handspring lo ha utilizzato per la serie Visor, sebbene le ultime versioni montino processori ARM. Il 68000 viene tuttora utilizzato dalla Texas Instruments per realizzare le sue calcolatrici grafiche.

La versione iniziale del 68000 è stata presentata nel 1982 per competere con Intel 8086 e Intel 80286 e i loro successori. La prima versione raggiungeva gli 8 MHz di clock, che per i tempi era una frequenza operativa molto elevata.

Motorola ha cessato di produrre direttamente il 68000 nel 2000 anche se continua a produrre alcuni suoi derivati come le CPU32. Dal 2001 Hitachi ha ripreso a produrre 68000 grazie a una licenza concessa da Motorola.

## Architettura

### Bus indirizzi

Il 68000 era un compromesso intelligente: quando venne presentato, i bus a 16 bit erano effettivamente la soluzione più ragionevole, in quanto relativamente veloci e non molto costosi. Ciononostante, il 68000 venne progettato con registri e spazio d'indirizzamento a 32 bit, assumendo che il costo dell'hardware sarebbe sceso rapidamente e che quindi il maggior costo iniziale della soluzione a 32 bit si sarebbe ripagato in poco tempo.

Sebbene l'ALU del 68000 fosse a 16 bit, il processore gestiva tutti gli indirizzamenti a 32 bit; aveva cioè uno spazio d'indirizzamento di 32 bit lineare. Questo significa che il 68000 era, ed è, di fatto, un microprocessore a 32 bit. L'8086 aveva uno spazio d'indirizzamento di 20 bit, ma essendo segmentato non poteva accedere a blocchi di più di 64 kilobyte (16 bit) alla volta, dovendo manipolare i registri di segmento.

Nonostante il bus della ALU fosse a 16 bit, le operazioni sugli indirizzi venivano eseguite a 32 bit ed era previsto fuori dalla ALU un sommatore e sottrattore a 32 bit, da utilizzare per le operazioni di post incremento e pre decremento sugli indirizzi, senza dover attendere l'ALU e quindi senza riduzioni delle prestazioni.

Come detto, sebbene Motorola avesse rilasciato un processore a 16 bit, le sue istruzioni e la sua architettura erano evidentemente plasmati per essere a 32 bit. Questa scelta venne presa per non dover affrontare problemi di compatibilità quando l'architettura fosse migrata ad un bus a 32 bit. L'architettura scelta era flessibile, infatti era già previsto sia il 68008 (processore con bus a 8 bit) che il futuro successore a 32 bit (che poi fu il 68020).

Per venire incontro alle esigenze del mercato Motorola aveva previsto inizialmente tre processori. Il 68000, dotato di un bus a 16 bit per i dati e un bus indirizzi a 24 bit (corrispondenti a 16 MB). Il 68008, dotato di un bus a 8 bit per i dati e in grado di indirizzare 18 bit (con possibilità di utilizzare 19 o 20 bit) e infine il processore della generazione successiva dotato di un indirizzamento a 32 bit e di bus dati a 32 bit (in grado di indirizzare 4 GB).

### Registri interni

La CPU ha i seguenti registri, tutti a 32 bit:

* 8 registri di uso generale per i dati (D0-D7)
* 8 registri per gli indirizzi (A0-A7)
* un registro puntatore d'istruzione (PC)
* un registro (SSP) per lo stack supervisore

Tutti i registri dati sono di uso generico, non ci sono registri specializzati, dedicati ad esempio alla moltiplicazione o alla divisione, come nei processori precedenti. L'ultimo registro indirizzi è lo stack pointer e può essere chiamato indifferentemente A7 oppure SP. Questo numero di registri rappresenta un buon compromesso: abbastanza basso da non penalizzare troppo il 68000 nelle commutazioni di contesto, ma tuttavia sufficiente a velocizzare la maggior parte dei calcoli.

Si ritiene che la separazione dei registri in due tipi abbia consentito ai progettisti della CPU di raggiungere un più alto grado di parallelismo, grazie all'uso di un'unità d'esecuzione ausiliaria per i registri indirizzi.

È presente inoltre un registro di stato (SR) a 16 bit.

### Registro di stato

Le istruzioni aritmetico-logiche e i trasferimenti impostano automaticamente i bit di condizione (flag) nel registro di stato, tranne quando la destinazione è un registro indirizzi. Esistono 5 bit di condizione:

* N (Negative): bit di segno. È una copia del bit più significativo del risultato;
* Z (Zero): indica che il risultato è zero;
* V (oVerflow): superamento di capacità (in aritmetica con segno);
* C (Carry): riporto (superamento di capacità, in aritmetica senza segno);
* X (eXtend): normalmente assume lo stesso valore di C, ma solo per le operazioni aritmetiche. Semplifica l'implementazione di operazioni a precisione superiore a 32 bit.

I bit di condizione vengono usati principalmente dalle istruzioni di salto condizionato, per il controllo del flusso di un programma.

### Set di istruzioni

I progettisti hanno cercato di rendere il linguaggio assembly del 68000 ortogonale. Ovvero, le istruzioni sono divise in operazioni e modi di indirizzamento: quasi tutti i modi d'indirizzamento sono utilizzabili con la maggior parte delle istruzioni.

Chi scriveva un assemblatore per il 68000 si rendeva chiaramente conto che queste "istruzioni", al livello dei bit, erano traducibili in più codici operativi differenti. Era un compromesso abbastanza buono perché dava quasi gli stessi vantaggi di un sistema veramente ortogonale, e tuttavia garantiva ai progettisti della CPU la libertà di estendere la tabella dei codici operativi.

Con sole 56 istruzioni, la dimensione minima di un'istruzione era enorme per quei tempi: 16 bit. Inoltre, molte istruzioni e modi di indirizzamento richiedono alcune parole in più per gestire operandi immediati, ulteriori bit del modo di indirizzamento ed altro.

Molti progettisti ritenevano che l'architettura del MC68000, relativamente al suo costo, offrisse un set di istruzioni con elevata densità di codice, specialmente per quello generato da un compilatore. Tale caratteristica è stata alla base del successo e della longevità di questa architettura.

Questa convinzione (o caratteristica, a seconda del progettista) ha continuato a rivelarsi vincente per il set di istruzioni (anche per le successive CPU), finché l'architettura ARM non ha introdotto il set di istruzioni Thumb, simile per compattezza.

### Livelli di privilegio

Il 68000 e le sue evoluzioni sono dotati di due livelli di privilegio: il livello utente e il livello supervisore. Un programma eseguito a livello utente ha accesso a tutti i registri, esclusi quelli per la gestione delle interruzioni. A livello supervisore, non ci sono limiti di accesso ai registri. La modalità d'esecuzione è determinata da un bit del registro di stato.

Un notevole vantaggio di questa CPU è avere due stack pointer distinti, uno per ogni modalità. In modalità supervisore il 68000 usa un registro SP diverso, detto SSP (Supervisor SP). Il processore può comunque accedere al registro SP del livello utente (detto USP, User SP) anche dal livello supervisore, mediante apposite istruzioni. Grazie a questa caratteristica, in un sistema multitasking basato sul 68000 è possibile usare stack molto piccoli per i singoli processi, dato che non bisogna prevedere spazio in più per il salvataggio dei registri per le interruzioni. Per la gestione delle interruzioni sarà invece sufficiente che il sistema operativo allochi un solo stack supervisore di dimensioni adeguate.

Il modo supervisore è il meccanismo di base, comune a tutti i processori della famiglia 68000, per implementare politiche di protezione tipiche dei sistemi operativi più avanzati: ai programmi comuni, che vengono eseguiti in modalità utente, non è consentito l'uso di istruzioni potenzialmente "pericolose", che rimangono di competenza esclusiva del sistema operativo.

### Interrupt

La CPU gestisce 7 livelli di interrupt. I livelli vanno dal livello 1 al livello 7 e sono dotati di priorità: un livello ad alta priorità può sempre interrompere un livello a priorità inferiore. Nel registro di stato una istruzione privilegiata seleziona il livello di interrupt in esecuzione in modo da ignorare gli eventuali interrupt di livello inferiore. Il livello 7 non è mascherabile (NMI) mentre il livello 0 indica nessun interrupt. I livelli sono memorizzati nel registro di stato e sono visibili in modo utente.

La tavola delle eccezioni (interrupt vector addresses) è posizionata nelle locazioni di memoria comprese tra 0 e 1023 e permette 256 vettori a 32 bit. Il primo vettore memorizza il punto di partenza dello stack degli indirizzi, il secondo memorizza lo stack delle istruzioni. I vettori tra 3 e 15 sono utilizzati per segnalare gli errori: errore di bus, indirizzo errato, istruzione illegale, divisione per zero, ecc. Dal vettore 24 in poi vengono memorizzati gli interrupt, i 15 livelli di TRAP (interruzione software) e i vettori definiti dall'utente.

Il gestore degli interrupt inizialmente era un chip separato, il 68901: ciò complicava notevolmente il disegno dell'hardware della scheda e rallentava il processore, dato che ogni interrupt doveva essere convertito dal chip esterno. Il 68901 era provvisto anche di una UART molto semplice e di un timer per gli interrupt. Il 68901 aveva molti difetti inclusa una predisposizione a perdere gli interrupt di alto livello se questo e il timer scattavano nello stesso istante. La controparte prodotta dalla Mostek era migliore.

Durante l'avvio del computer avere i vettori a indirizzi fissi era molto comodo, dato che consentiva di programmare le ROM dei computer senza troppe complicazioni dovute alle allocazioni dinamiche dei vettori. Ma quando il sistema operativo era caricato una gestione fissa dei vettori era una tecnica sconsigliabile dato che limitava il sistema operativo e lo rendeva molto legato al funzionamento del singolo modello di processore. Per risolvere questo problema spesso i produttori avviavano il computer con le ROM residenti a partire da un particolare indirizzo e dopo l'avvio l'indirizzo di partenza veniva modificato e al posto della ROM veniva allocata della RAM che poteva essere modificata senza problemi.

Un ulteriore problema derivava dalla modalità privilegiata: progettata pensando a un sistema operativo come Unix, che per ragioni di sicurezza attua una netta distinzione tra programmi e sistema operativo. L'idea era buona ma l'implementazione si rivelò lacunosa, vi erano delle dimenticanze che la rendevano non sicura. Questi errori vennero corretti nelle generazioni successive.

Il 68000 non era in grado di gestire correttamente un errore nell'accesso alla memoria e quindi non era in grado di implementare una vera gestione della memoria virtuale, una necessità vitale per molti sistemi operativi. La memoria virtuale è una semplice tecnica utilizzata per simulare la disponibilità di memoria RAM praticamente infinita. Quando il processore accedeva a una locazione di memoria non esistente attivava un interrupt che provvedeva a selezionare un blocco di RAM, salvare il suo contenuto su disco rigido e poi manipolava gli indirizzi in modo che gli indirizzi inesistenti puntassero alla zona di memoria appena liberata. Alcuni produttori di sistemi Unix realizzarono macchine basate sul 68000 con il supporto della memoria virtuale. Fu possibile utilizzando due processori con il clock sfasato. Quando il primo processore si bloccava per via di un accesso a un indirizzo inesistente, la logica di controllo impediva al secondo di fare la stessa fine e attivava l'interrupt di gestione della memoria virtuale che dopo aver liberato la RAM e aver opportunamente manipolato gli indirizzi sbloccava il primo processore che riprendeva l'elaborazione come se non fosse successo niente. Ovviamente era una tecnica molto costosa e inefficiente e appena uscì il 68010 i produttori aggiornarono le macchine eliminando il secondo processore.

Un problema meno visibile ma non meno importante del 68000 era che disponendo di molte istruzioni e molti modi di indirizzamento era difficile da simulare dato che il simulatore doveva tener conto di moltissimi casi con moltissime varianti. Questo è un problema che si presenterà anche in alcune versioni moderne della sua architettura. Nel controllo avionico infatti è stato scelto il processore Intel 80386 per la sua semplicità di simulazione rispetto al corrispettivo processore Motorola.

La revisione successiva del processore, il Motorola 68010 risolse la maggior parte dei problemi del 68000.

## Dettagli sul set di istruzioni

La maggior parte delle istruzioni sono diadiche, hanno cioè due operandi, uno dei quali indica anche la destinazione del risultato. Esempi significativi sono:

* Aritmetiche
   * ADD (somma), SUB (sottrazione)
   * MULU (moltiplicazione senza segno), MULS (moltiplicazione con segno)
   * DIVU (divisione senza segno), DIVS (divisione con segno)
   * NEG (inversione del segno)
   * CMP (confronto: una sorta di sottrazione che scarta il risultato, ma modifica i flag di stato)
* In aritmetica decimale (BCD):
   * ABCD e SBCD
* Logiche:
   * AND, OR
   * NOT (logical not)
   * EOR (Exclusive OR)
* Shift e rotazioni:
   * Logici: LSL, LSR
   * Aritmetici: ASL, ASR
   * ROL (Rotate left), ROR (Rotate right)
   * con bit eXtend: ROXL, ROXR
* Operazioni su bit:
   * BSET (mette a 1)
   * BCLR (mette a 0)
   * BTST (bit test)
* Supporto ai sistemi multiprocessore:
   * TAS, test-and-set, effettua uno speciale ciclo indivisibile di lettura-modifica-scrittura sul bus; permette di implementare facilmente i meccanismi di mutua esclusione in sistemi multiprocessore a memoria condivisa.

Condizioni Bcc/DBcc :

| T true | 0000 | $1$ |
| - | - | - |
| F false | 0001 | $0$ (solo per DBcc) |
| CC carry clear | 0100 | ${\bar {C}}$ |
| CS carry set | 0101 | $C$ |
| EQ equal | 0111 | $Z$ |
| GE greater or equal | 1100 | $N\land V\lor {\bar {N}}\land {\bar {V}}$ |
| GT greater than | 1110 | $N\land V\land {\bar {Z}}\lor {\bar {N}}\land {\bar {V}}\land {\bar {Z}}$ |
| HI high | 0010 | ${\bar {C}}\land {\bar {Z}}$ |
| LE less or equal | 1111 | $Z\lor N\land {\bar {V}}\lor {\bar {N}}\land V$ |
| LS low or same | 0011 | $C\lor Z$ |
| LT less than | 1101 | $N\land {\bar {V}}\lor {\bar {N}}\land V$ |
| MI minus | 1011 | $N$ |
| NE not equal | 0110 | ${\bar {Z}}$ |
| PL plus | 1010 | ${\bar {N}}$ |
| VC overflow clear | 1000 | ${\bar {V}}$ |
| VS overflow set | 1001 | $V$ |

* Controllo di flusso:
   * JMP (jump)
   * JSR (jump to subroutine)
   * BSR (branch to subroutine: come jump, ma relativa al PC)
   * RTS (return from subroutine)
   * RTE (return from exception, per uscire dalle eccezioni)
   * TRAP (lancia un'eccezione software)
   * CHK (eccezione software con condizione)
* Salti condizionali:
   * Bcc (salta se è verificata la condizione "cc". Questo specifica una delle 16 possibili condizioni di test da verificare sul registro di stato).
   * DBcc (se la condizione è falsa, decrementa il registro dati e, se il registro non è -1, salta. L'uso di -1 invece di 0 come valore di uscita consente di programmare facilmente i cicli in cui il numero di ripetizioni può essere nullo, senza bisogno di un controllo aggiuntivo all'inizio nel ciclo)
* Altre:
   * accesso al registro di stato e, nei modelli successivi, ad altri registri speciali
   * supporto a legacy device

Molte istruzioni ammettono un suffisso che permette di specificare la dimensione dei dati dell'operazione:

* ".b" per 8 bit (byte),
* ".w" per 16 bit (word),
* ".l" per 32 bit (long word).

Il default è 16 bit.

I modi di indirizzamento supportati sono:

* Diretto
   * a registro dati, es. "D0"
   * a registro indirizzi, es. "A6"
* Indiretto
   * Semplice tramite registro indirizzi, es. (A0)
   * Tramite registro indirizzi con post-incremento, es. (A0)+
   * Tramite registro indirizzi con pre-decremento, es. -(A0)
   * Tramite registro indirizzi con scostamento a 16 bit, es. 48(A0)

Si noti che la quantità effettivamente sommata o sottratta al registro indirizzi, rispettivamente nei modi con post-incremento e pre-decremento, dipende dalla dimensione dei dati: 1 se si opera su byte, 2 se su word, 4 se su long word.

* Indicizzato
   * indiretto tramite registro indirizzi, indicizzato con registro (a 16 o 32 bit) e scostamento di 8 bit con segno, es. 15(A0, D0.w) or 76(A0, A1.l)
* Relativo al PC (program counter)
   * con scostamento a 16 bit con segno, es. 1234(PC)
   * indicizzato con registro (a 16 o 32 bit) e scostamento ad 8 bit con segno, es. 24(PC, D2.w)
* Assoluto
   * Corto, a 16 bit (con estensione del segno), es. "$4000"
   * Lungo, a 32 bit, es. $00123456
* Immediato
   * Memorizzato nell'istruzione, es. #$400
