National Semiconductor 16032: il perfetto (e sconosciuto) CISC a 32 bit?

Un noto proverbio afferma che fra due litiganti, che ovviamente cercano di primeggiare, il terzo goda. Accade però tante volte che i due litiganti, pur litigando, rimangono sulla cresta dell’onda e il terzo, che non è stato in grado di darsi da fare e approfittare della situazione, sparisca nell’oblio.

Anche nel campo dell’informatica capitano situazioni del genere, e quello dei microprocessori non è da meno. Per anni la lotta per primeggiare è stata sempre dominio di due soli nomi: Intel e Motorola, che con le rispettive famiglie 80×86 e 680×0 si sono contese il mercato dei computer “casalinghi” (e non) per una quindicina d’anni (fra gli ’80 e la seconda metà dei ’90).

Queste famiglie, è bene ricordarlo, non nascono casualmente, ma sono frutto dell’evoluzione di precedenti processori (8080 e 6800 rispettivamente), che ne hanno influenzato anche molto il design.

Partire da un progetto ex-novo permette di superare certi schemi, e gli ingegneri in questi casi sono capaci di tutto: dal realizzare soluzioni “originali” (leggi: talmente “avanzate” da rivelarsi delle immani ciofeche) a degli autentici capolavori a cui porgere tanto di cappello.

Il problema poi rimane sempre il solito: essere altrettanto bravi da riuscire a venderli e imporsi sul mercato, magari dominandolo. E’ questo il caso del 16032 di National Semiconductor: una CPU a 32 bit dal design spettacolare che, però, è riuscita a malapena a far capolino, rimanendo poi nel dimenticatoio e relegando i suoi successori a piccole nicchie di mercato nel settore embedded…


Nato pochi mesi dopo il 68000 (che già all’epoca portò una grande nonché gradevolissima ventata di novità), questo microprocessore ha ben poco da invidiargli se non, anzi, da farsi invidiare grazie alle pregevolissime soluzioni adottate per la definizione della sua architettura.

Definirlo “spettacolare” (e addirittura avanzare un “perfetto” nel titolo) può sembrare azzardato, o causato da un eccesso di zelo, ma vi posso assicurare che non si tira fuori un vocabolo come questo semplicemente per fare un po’ di scena o buttare un po’ di fumo negli occhi.

Quali, dunque, le caratteristiche che possono giustificare tanta ammirazione? Parecchie. Cominciamo col dire che difficilmente si trovano in giro ISA talmente simmetriche / ortogonali, specialmente quando parliamo di processori CISC: praticamente tutte le istruzioni possono utilizzare indifferentemente una qualunque modalità d’indirizzamento.

Cosa significa? Che dalla più semplice istruzione MOV (per copiare dati da una locazione a un’altra) fino alla decisamente più complessa EXT (per estrarre campi di bit), per indirizzare una qualunque locazione di memoria (per sorgente e/o destinazione) si può specificare la modalità d’indirizzamento che si desidera.

Questa è sicuramente una manna dal cielo per i compilatori (e in particolare per chi li sviluppa), perché consente di semplificare molto il back-end che si occupa della generazione del codice binario per l’architettura.

E’ anche molto comodo per i programmatori assembly, perché non sono costretti a ricordarsi di eventuali eccezioni (“con questa istruzione non si può usare questa modalità, mentre con quest’altra sono disponibili solo queste due”, ecc.), sebbene sia abbastanza raro l’uso di modalità “complesse”, in quanto la tendenza rimane sempre quella di operare per lo più coi registri, sfruttando gli accessi alla memoria quasi sempre per singole “load” o “store” dei dati che interessano.

C’è, però, da dire che questa CPU, similmente al PDP-11, mette a disposizione soltanto 8 registri general purpose (fortunatamente Program Counter e Stack Pointer risiedono su registri dedicati), per cui si può arrivare abbastanza facilmente a impegnarli tutti.

Quindi poter sfruttare una qualunque modalità sia per la locazione sorgente che per quella di destinazione consente di poter eseguire operazioni tranquillamente senza costringere a salvare e poi recuperare qualche registro usando lo stack come memoria “di transito”.

Le modalità d’indirizzamento sono ben nove, e coprono le esigenze più comuni: dall’utilizzo di un registro fino alla specifica di un indirizzo assoluto. Particolarmente degno di menzione è, però, la possibilità di sfruttare un registro indice opportunamente “scalato” (moltiplicato per 1, 2, 4 o 8) da aggiungere a una qualunque altra modalità d’indirizzamento. Roba che si vedrà soltanto anni dopo nelle CPU più blasonate.

Anche per i tipi di dato questo microprocessore si mostra particolarmente dotato: oltre che operare indifferentemente con interi a 8, 16 e 32 bit, supporta anche i BCD, la manipolazione di singoli bit come pure di campi di bit (caratteristica, anche questa, che si vedrà ben più avanti in altri processori), controllo e calcolo degli indici degli array (anche multidimensionali), e addirittura la manipolazione di stringhe con eventuale utilizzo di tabelle di traslazione dei byte letti.

Particolaremente interessante è anche il concetto di modulo, che è assimilabile a quello di call gate e task gate degli x86 (dal 286 in poi), e che serve a individuare un blocco di dati e di codice similmente allo stato di un processo, dando anche la possibilità di effettuare chiamate a precise porzioni di codice di altri moduli (oltre a quello associato al codice in esecuzione). Usato, com’è facile intuire, anche per implementare librerie di codice globalmente condivise.

A completare l’opera, fra il centinaio di istruzioni messe a disposizione, ne troviamo anche di molto utili per salvare e ripristinare elenchi di registri, saltare alle varie parti di codice generate dal costrutto ad altro livello “switch/case”, costruire e distruggere lo stack frame quando si chiama una subroutine, e altro ancora.

Similmente al 68000 e ad altre avanzate CPU, il 16032 presenta una modalità supervisore nella quale far girare il codice di un eventuale kernel, una utente per il codice delle applicazioni, ed è dotato di un apposito stack per ognuna delle due. Consente anche di spostare la tabella degli interrupt in una qualunque locazione, e ha pieno supporto anche per il tracing delle istruzioni e l’uso dei breakpoint.

Last but not least, fin da subito ha offerto la possibilità di utilizzare coprocessori esterni (mentre per il 68000 arriverranno ben dopo, anche se già previsti a livello di ISA) per il calcolo di valori in virgola mobile, per la paginazione della memoria, e implementa una generica interfaccia verso altre tipologie di coprocessori.

Per riprendere la domanda posta come titolo dell’articolo, è realmente un microprocessore perfetto? Sembrerebbe di sì, a giudicare di quanta carne al fuoco è riuscita a mettere National, ma sappiamo bene che qualunque soluzione, per quanto “bella”, è pur sempre frutto di compromessi.

In questo caso, e come già detto prima, è da sottolineare la presenza di 8 soli registri general purpose, che arrivano a essere sfruttati tutti abbastanza in fretta, costringendo a ricorrere alla memoria o allo stack.

Altro svantaggio è rappresentato dall’assenza di modalità indirizzamento di autoincremento e autodecremento, che sono utili quando si ha a che fare con operazioni che coinvolgono blocchi di dati su cui agire sequenzialmente. Il 16032 è dotato di istruzioni per la manipolazione di stringhe, ma non sono sempre sfruttabili per questo scopo.

L’uso di opcode a 8 bit (costituiti da singoli byte) sembrerebbe un bel vantaggio (codice più compatto), ma andando a controllare la loro codifica si scopre che soltanto poche (e anche rare) istruzioni occupano un solo byte, mentre per quelle più comuni (anche queste poche: una decina in tutto) sono necessari due byte, e addirittura per tutte le altre (comprese, incredibile a dirsi, anche roba come NOT, ABS, shift, ecc. che sono abbastanza usate) il minimo è rappresento da tre byte.

Quindi il codice ottenuto occupa un po’ di spazio in più rispetto ad architetture dotate di un’ISA più compatta, sebbene per cercare di mitigare siano state introdotte alcune istruzioni “quick“, che permettono di specificare piccoli valori immediati a 4 bit. Ma più spazio significa anche un maggior consumo di banda di memoria e un maggior impegno per la logica di decodifica delle istruzioni.

A parte questo, è difficile trovare altre pecche in quest’ISA: è davvero molto ben fatta. Perché allora non è emersa, addirittura imponendosi nel mercato? Innanzitutto c’è da dire che è arrivata dopo i suoi naturali concorrenti, e sappiamo bene quanto questo possa significare in un mercato abbastanza giovane in cui i pioneri molto facilmente possono arrivare a “monopolizzarlo”.

La causa più importante, però, è da ricercarsi nei numerosi bug presenti, a cui si aggiunse anche la scarsa resa produttiva (molte CPU non funzionavano, o non funzionavano correttamente), che portò velocemente National a conquistarsi una cattiva fama, a cui non seppe far fronte e che la portò ad abbassare di molto il prezzo di questi prodotti, non riuscendo comunque a impedire di finire relegata in una piccola nicchia di mercato.

Come capita spesso, le soluzioni più “belle” difficilmente prendono piede, specialmente quando è la stessa casa produttrice a metterci i mezzi e i bastoni fra le ruote per non farle sfondare…

Press ESC to close