Motorola 68000: la rivoluzione a 32 bit

Se il primo amore non si scorda mai, il secondo può essere quello di tutta una vita…

No, non avete sbagliato a digitare e non siete finiti nel sito ufficiale della collana Harmony : siamo sempre su Appunti Digitali e, anche se l’inizio non sembra in linea con l’argomento “tecnologia”, dipinge piuttosto bene la storia e lo stato d’animo di chi, avendo iniziato la propria carriera di programmatore smanettando su un glorioso MOS 6510, è rimasto letteralmente folgorato (in tutti i sensi, dopo quello che avete appena letto) dal successivo microprocessore su cui ha lavorato (considerato da molti anche il successore).

E non credo di sbagliare se affermo che un posto nel cuore (e nella storia dell’informatica) l’ha sicuramente lasciato quel gioiello tecnologico che Motorola lanciò nel lontano 1979 e a cui diede il nome di 68000.

Questo, ovviamente, se vi sentite già con un piede nella fossa: chi è troppo giovane non ne ha mai sentito parlare e magari pensa che al mondo siano esistiti soltanto i Pentium di Intel

Intel che, col suo 8086 uscito appena un anno prima, aveva cominciato ad acquisire popolarità, ma letteralmente sfigurava di fronte a un 68000 che, da qualunque punto di vista lo si guardasse, era di classe nettamente superiore. Ma lo era anche nei confronti del resto della concorrenza.

D’altra parte era piuttosto imbarazzante confrontare dei processori a 8 o 16 bit con un “mostro” a 32 bit. Già, perché questa “bestiolina” permetteva di manipolare dati a 32 bit, e tali erano anche gli indirizzi (quindi la memoria teoricamente indirizzabile era pari a 4GB lineari, quindi senza paginazionesegmentazione).

Purtroppo Motorola presentò il 68000 con bus dati esterno dimezzato (16 bit; erano pertanto necessarie due operazioni per trasferire dati a 32 bit), mentre il bus indirizzi esterno fu brutalmente “troncato” a 24 bit (quindi la memoria massima indirizzabile scendeva a 16MB; quantità comunque enorme per quei tempi).

Tutto ciò si rese necessario per ridurre i costi del package, che già coi suoi 64 piedini era “mastodontico” paragonato ai 40 o 48 tipici dei prodotti della concorrenza. Questo perché Motorola non volle scendere a compromessi utilizzando soluzioni basate sul multiplexing delle linee dati e indirizzi, che avrebbe penalizzato ulteriormente i tempi d’interfacciamento con la memoria e le periferiche.

Sempre per cercare di economizzare (questa volta sul numero di transistor impiegati), l’ALU era a 16 bit, quindi le operazioni aritmetiche a 32 bit necessitavano internamente di due “passaggi” alla medesima per essere completate. Quindi le istruzioni di questo tipo risultavano più lente, anche se Motorola fornì delle versioni “quick” per somma e sottrazione (e per il caricamento di valori immediati) per cercare di “mitigarne” il decadimento prestazionale.

Finora abbiamo parlato esclusivamente di soluzioni tecniche che non riguardano direttamente l’ISA (Instruction Set Architecture), in quanto prescindono da essa e sono relative esclusivamente alla specifica implementazione. In parole povere, non si tratta di “difetti” che si porta dietro l’architettura, ma soltanto il singolo modello di processore. Altri processori della stessa famiglia elimineranno tutti questi problemi senza intaccarla minimamente.

Come ho affermato in un precedente articolo, l’ISA era fortemente ispirata a quella del PDP-11 di Digital, altro gioiello da cui hanno attinto molti, e di cui Motorola ha tratto a piene idee e soluzioni tecniche, seppur rielaborandole in base alle sue esigenze.

Vediamo, quindi, che ci troviamo davanti a un’architettura che è “abbastanza ortogonale”, cioé che buona parte delle istruzioni è in grado di sfruttare le stesse modalità d’indirizzamento. Questo facilita la scrittura dei compilatori, ma ovviamente sono presenti delle eccezioni di cui tener conto.

Infatti a differenza del PDP-11 e del TMS 9900, e a causa dell’organizzazione degli opcode all’interno della word principale a 16 bit, purtroppo l’unica istruzione che è in grado di utilizzare una qualunque modalità d’indirizzamento per l’operando sorgente e quello destinazione è la MOVE, che come dice il nome serve a “muovere” (in realtà copiare) dati da un posto a un altro.

Tutte le altre istruzioni a due operandi non godono di questa caratteristica, fatta eccezione per somma, sottrazione e confronto che possono accedere a entrambi gli operandi in memoria, ma soltanto per particolari modalità d’indirizzamento. Per il resto, l’accesso alla memoria è generalmente consentito a un solo operando, mentre l’altro dev’essere un registro. Alcune istruzioni, poi, prevedono soltanto l’impiego di registri.

Forti limitazioni? Non tanto, perché Motorola ha preferito tralasciare la piena ortogonalità e la simmetria, concentrandosi esclusivamente sui pattern più frequentemente utilizzati, e ciò le ha permesso di organizzare meglio i 16 bit dell’opcode principale, riuscendo anche a lasciare ampii spazi che in futuro verranno riempiti dai successori del 68000.

Potrebbe sembrare una difesa “a oltranza”, ma in realtà avendo lavorato per parecchi anni con svariate architetture, quante volte c’è capitato di dover eseguire lo XOR di due dati presenti in memoria? Evento molto raro, e infatti non è un caso che l’istruzione di gran lunga più utilizzata sia la MOVE, e che le operazioni aritmetico-logiche siano eseguite generalmente fra registri, al più andando a pescare un operando in memoria.

Pattern tipici che sono pienamente rispettati nell’ISA del 68000, che pur supportando anche diversi tipi di dati (fra cui gli allora famosi e utili numeri BCD packed), mettendo a disposizione comodissime istruzioni per manipolare i singoli bit, e addirittura fornendo un’istruzione per il controllo di entrambi i limiti di un array, contava stranamente soltanto 56 istruzioni.

Quindi un’architettura semplice da padroneggiare, per la quale era necessario conoscere il funzionamento di poche istruzioni, ma anche delle ben 14 modalità d’indirizzamento che annoveravano, tra l’altro, anche la possibilità di incrementare o decrementare automaticamente i registri indirizzo utilizzati (“prestito” anch’esso del PDP-11).

Sì, perché anche qui ci troviamo davanti a una pregevole trovata di Motorola: affiancare ai registri dati (8) che troviamo tradizionalmente, dei registri appositamente dedicati per gli indirizzi (altri 8, di cui uno, A7, dedicato allo stack) che in altre ISA o erano registri indice, oppure normalissimi registri.

In questo modo il 68000 si ritrova con 16 registri utilizzabili, sebbene pensati con scopi differenti, ma per i quali la codifica interna generalmente richiede 3 bit (per gli 8 valori) in quanto l’uso di un registro dipende generalmente dal contesto in cui viene utilizzato (operazioni aritmetiche -> registro dati; indirizzamento della memoria -> registro indirizzi).

Questo ha permesso a Motorola di sfruttare in maniera sapiente lo spazio a disposizione all’interno della word a 16 bit che mappa opportunamente gli opcode e i relativi parametri delle istruzioni. Infatti architetture che hanno 16 registri “general purpose” sono indubbiamente più generiche e flessibili (oltre che totalmente ortogonali), ma richiedono ben 4 bit per specificare un qualunque registro, e quando si ha a che fare con 2 di essi, ad esempio, si arriva a saturare velocemente lo spazio riservato all’opcode, lasciando poco spazio per specificare altre informazioni.

La separazione netta fra dati e indirizzi sicuramente può far storcere il naso ai “puristi”, ma nella pratica si rivela poco rilevante e, anzi, abbastanza comoda (leggendo il codice a colpo d’occhio si capisce su quali elementi si sta lavorando), oltre che efficiente (ed economico, in termini di transistor).

L’efficienza deriva anche dal fatto che è possibile specializzare il processore, riservando delle aree specifiche per il solo calcolo degli indirizzi (che in gergo tecnico si chiamano AGU, cioé Address Generation Unit), quindi delle “ALU” altamente specializzate e molto veloci, che possono anche non condividere le eventuali limitazioni dell’ALU “ufficiale” (quella che si occupa delle operazioni aritmetiche).

Infatti, sebbene l’ALU del 68000 fosse a 16 bit, il calcolo degli indirizzi non era particolarmente penalizzato, se consideriamo che anche il Program Counter, essendo anch’esso a 32 bit, richiedeva l’uso di un sommatore a 32 bit per il calcolo dell’istruzione successiva.

Andando a controllare la tabella dei tempi di esecuzione delle istruzioni troviamo conferma di ciò: mentre l’esecuzione di una somma a 32 bit richiede 2 cicli di clock aggiuntivi rispetto alla medesima operazione a 8 o 16 bit, l’uso della modalità di autoincremento di un registro indirizzo (che è sempre a 32 bit) non comporta nessuna penalizzazione.

Segno, questo, che non soltanto l’incremento viene effettuato parallelamente all’esecuzione dell’opcode “principale”, ma che non ci sono ricadute a causa sua. In sostanza si tratta di un’operazione aggiuntiva e… gratuita (l’autodecremento, invece, comporta una penalizzazione di 2 cicli di clock), abilmente sfruttata dai programmatori dell’epoca.

Altre caratteristiche interessanti del 68000 erano la possibilità di eseguire il tracing delle istruzioni (per il debugging), il supporto al multiprocessing (grazie alla presenza di una speciale istruzione atomica di “test-and-set“), e i ben 7 livelli di interrupt a disposizione per le periferiche.

Molto più interessante era, però, la presenza di una modalità utente e una supervisore (dotata di un suo stack), che consentiva quindi un’altra separazione: quella dell’esecuzione del codice del sistema operativo da quello delle normali applicazioni.

Purtroppo non c’era ancora il supporto alla gestione della memoria virtuale (che arriverà soltanto col 68010) né meccanismi di protezione della memoria per impedire l’accesso indicriminato alle strutture dati del s.o., ma volendo era possibile realizzare un sistema in cui codice e dati della modalità supervisore erano completamente isolati rispetto ai medesimi di quella utente, sfruttando particolari segnali presenti nel bus di controllo della CPU (i poco famosi “function code“).

Un microprocessore estremamente flessibile in diversi campi, quindi, che non a caso continua ad avere un posto d’onore nel cuore di chi ha avuto modo di poterci lavorare, generando schiere di appassionati e “fedeli”. Era, infatti, talmente comodo che l’uso dell’assembly per sviluppare applicazioni anche complesse era molto comune (quasi tutte le applicazioni che ho realizzato per l’Amiga erano scritte in questo linguaggio).

Purtroppo questo è stato anche il suo tallone d’Achille, perché a una grande facilità di fruttamento da parte dei programmatori s’è contrapposta un’architettura interna molto “pesante” e “complicata” (non è un caso se questa famiglia è considerata fra le “più CISC“), che col tempo ha limitato fortemente la possibilità di aumentarne le prestazioni, complice soprattutto la successiva estensione dell’ISA da parte di Motorola col 68020.

Il fallimento di Commodore prima, la chiusura della linea ST di Atari poi, e infine il colpo di grazia dell’abbandono di Apple (che s’è rivolta ai PowerPC) ha segnato la fine di una delle più “belle” architetture della storia dei microprocessori, che continua a vivere in nicchie di mercato dei dispositivi embedded / microcontrollori, ma soprattutto nel ricordo di chi ha avuto il piacere di conoscerla e poterci lavorare…

Press ESC to close