Ogni dispositivo digitale, è basato su elementi fondamentali chiamate porte logiche, in inglese logic gates. Una porta logica non è altro che un’implementazione fisica delle funzioni booleane.

In questo articolo, comincia il viaggio che ci porterà allo sviluppo di un semplice computer. In particolare, oggi vedremo come costruire le porte logiche essenziali per poi poter sviluppare una ALU e una memoria RAM funzionante, partendo dalla porta primitiva NAND.

Prima di cominciare, facciamo però un minimo di introduzione sui concetti e gli strumenti principali di cui faremo uso.

Porta Logica

Una porta logica non è altro che un dispositivo fisico che implementa una funziona booleana.

La prima cosa importante da sottolineare è che da un punto di vista informatico, non ci interessa come la logica venga realizzata. Il concetto di astrazione ci permette di concentrarci unicamente su cosa viene fatto da una determinata porta.

Come ogni altra funzione, una porta logica può realizzare funzioni complesse, partendo da composizioni di porte logiche più semplici.

Ad esempio, consideriamo la porta AND che realizza la seguente funzione:

Volendo adesso realizzare una porta che prenda in input 3 bit anzichè 2 e ne restituisca l’AND, possiamo pensare ad una soluzione di questo tipo in cui utilizziamo 2 porte AND base per raggiungere l’obiettivo prefisso:

Ovviamente, trattandosi di una nuova porta logica, come mostrato nella parte sinistra della figura in alto, possiamo rappresentarla a sua volta come un dispositivo primitivo riusabile per logiche ancora più complesse.

Hardware Description Language

Oggigiorno i progettisti hardware che si occupano di sviluppare nel dettaglio dispositivi elettronici di questo tipo, utilizzano dei linguaggi formali strutturati chiamati in gergo HDL (Hardware Description Language).

Tramite linguaggi di questo tipo è possibile disegnare, debuggare e ottimizzare chip di complessità variabile direttamente dal proprio PC e a costo 0.

Ciò è reso possibile grazie all’uso di un simulatore che sia in grado di tradurre quanto descritto attraverso il linguaggio usato e testarlo in accordo alle specifiche descritte.

Poichè il nostro obiettivo è quello di sviluppare le porte logiche base da usare poi per sviluppi più complessi, abbiamo bisogno di uno di questi simulatori; in commercio ne esistono diversi ma a un costo!

In questo caso, andremo ad usare un simulatore gratuito, il quale fornisce tutti i tool necessari a supporto di quanto ci siamo prefissati.

Il Simulatore

Raggiungi questo sito e scarica la suite di software contenuta nell’archivio nand2tetris.zip.
Una volta fatto, scompatta l’archivio in una cartella a piacere.

Il software che ci interessa è contenuto nella cartella tools e prende il nome di HardwareSimulator.

All’interno della cartella troverai una versione compatibile per tutti i principali sistemi operativi.
Lanciando l’eseguibile dovresti ritrovarti una finestra simile a questa:

Per come è pensato, il simulatore prende in pasto principalmente 3 tipologie di file:

  • .hdl: l’implementazione logica del circuito a cui lavoriamo.
  • .tst: test case su cui testare il circuito sviluppato per valutarne la correttezza.
  • .cmp: risultati che ciascun test descritto nel file precedente, deve produrre per poterne giudicare la correttezza.

I file su cui dovremo lavorare sono solamente i .hdl, le altre 2 tipologie, come vedremo, vengono già fornite complete così da poter controllare la bontà del nostro operato.

Se vuoi approfondire in maniera sistematica il tipo di linguaggio usato e come funziona il simulatore, puoi fare riferimento alle prime 3 sezioni di questo PDF.

Il Progetto

Come accennato all’inizio, il PC che andremo a costruire si basa per scelta sull’utilizzo della porta NAND:

Nella nostro lavoro implementativo considereremo quindi questa porta come primitiva e non avremo bisogno di realizzarla.

Quello che invece dobbiamo andare a fare è, partendo dalla porta NAND, realizzare tutte le altre porte logiche principali.

Partendo dall’archivio nandt2tetris.zip scompattato in precedenza, nella cartelle projects, troverai una serie di sottocartelle numerate. Per questa lezione ci concentriamo sulla cartella 01, al cui interno troverai una serie di questi file pronti ad essere caricati nel simulatore.

L’obiettivo, come riportato in questa pagina dedicata, è realizzare nell’ordine proposto le porte logiche le cui specifiche verranno presentate più avanti:

  • NOT, AND, OR, XOR;
  • MUX, DMUX, NOT16;
  • AND16, OR16, MUX16;
  • OR8WAY, MUX4WAY16;
  • MUX8WAY16, DMUX4WAY, DMUX8WAY.

E’ mandatorio partire usando soltanto la NAND. Mano a mano poi che si riesce a implementare le porte proposte, è possibile riusarle per realizzarne di altre.

Considera che il modo migliore per imparare è risolvere in autonomia questi esercizi.

Ad ogni modo, di seguito analizziamo passo-passo la soluzione per la porta NOT, tutte le altre porte le puoi trovare risolte a questo indirizzo.

Porta Not

La porta NOT è un operatore unario che ha come obiettivo quello di invertire (da 1 a 0 e viceversa) il bit passato in ingresso:

Per poterne realizzare una partendo dalla porta NAND, apriamo con un editor di testo il file Not.hdl presente nella cartella nand2tetris/projects/01, ci ritroveremo un codice di questo tipo:
Copy to Clipboard

Al di là delle prime 4 righe iniziali commentate, riportate in rosso, il file è così composto:

  • Specifiche della porta Not
    Qui trovi la descrizione del funzionamento che la porta dovrà avere, in particolare vediamo come il segnale in uscita, out, non è altro che la negazione, not, del segnale in ingresso, in.
    Per tutte le altre porte che andranno realizzate, fai riferimento a questa sezione per capire cosa fare.
  • Parola chiave CHIP
    seguita dal nome del componente (Not in questo caso).
  • Corpo
    delimitato da parentesi graffe.
  • Parola chiave IN
    seguita da una lista di segnali da considerare come in ingresso alla porta. Nel caso specifico, essendo un operatore unario abbiamo un unico segnale denominato in.
  • Parola chiave OUT seguita da una lista di segnali in uscita, anche in questo caso ne abbiamo uno solo, chiamato out.

Il punto dove dobbiamo andare a specificare l’implementazione della porta è dopo la parola chiave PARTS in cui vanno listate le componenti che compongono il gate in oggetto insieme alle relazioni tra segnali coinvolti.

La Soluzione

Bene, abbiamo cominciato questo articolo ponendoci l’obiettivo di usare la porta NAND, ma come facciamo ad importarla in questo script?

Per chiarire questo aspetto, raggiungi la cartella nand2tetris/tools/builtInChips qui puoi trovare una serie nutrita di porte già implementate. Apriamo il file Nand.hdl:

Copy to Clipboard

Questa volta al posto della parola chiave PARTS, troviamo la parola chiave BUILTIN che sta ad indicare come questa porta logica abbia una sua implementazione primitiva richiamabile in altri file.

Tutte le porte contenute in questa specifica cartella ne hanno una, c’è anche la porta NOT se guardi bene, ma noi vogliamo cimentarci nel costruirne una tutta nostra quindi torniamo al nostro file iniziale e completiamolo in questo modo:

Copy to Clipboard

Bene, abbiamo realizzato una porta NOT partendo dalla primitiva NAND. Dal file Nand.hdl aperto in precedenza abbiamo visto che la suddetta porta ha 2 variabili in ingresso denominate a e b e una variabile di uscita denominata out.

A tal proposito la nostra porta NOT non è altro che una porta NAND che prende in ingresso sia in a che in b il segnale in e salva in uscita il risultato nella variabile out.

Così facendo le uniche configurazioni in input possibili sono quelle in cui entrambi i segnali in ingresso sono contemporaneamente 0 o 1. Se guardiamo la tabella di verità della porta NAND, ci accorgiamo che quando entrambi gli input sono 0, la porta NAND restituisce 1. Viceversa quando sono 1, restituisce 0.

Questo è proprio il comportamento di cui abbiamo bisogno.

Testiamo la Soluzione

Ok, adesso abbiamo una possibile soluzione al nostro problema. Non ci resta che valutarne la correttezza.

Per fare questo, lanciamo il simulatore dalla cartella nand2tetris/tools e clicchiamo su File -> Load Chip. Carichiamo il file Not.hdl che abbiamo appena modificato.

Clicchiamo poi su File -> Load Script e selezioniamo il file Not.tst contenuto nella cartella nand2tetris/projects/01.

A questo punto, lanciamo il test cliccando Run -> Run e attendiamo che la procedura termini.

Se tutto è andato a buon fine dovremmo vedere un messaggio del tipo: End of script – comparison ended successfully.

Conclusioni

Ottimo, in questo articolo abbiamo visto come realizzare una porta NOT e come testarla utilizzando il simulatore e il linguaggio fornito gratuitamente.

Le altre porte richieste dal progetto le puoi scaricare da questo link.

Sulla base di questa libreria di dispositivi, nei prossimi articoli andremo a realizzare ciò che manca per sviluppare in ambiente simulato componenti complessi quali ALU e RAM.