Dopo aver esplorato le logiche programmabili combinatorie, è finalmente arrivato il momento di fare un passo avanti e affrontare i dispositivi logici programmabili di tipo sequenziale. In questo articolo vi racconterò come funzionano, qual è la differenza rispetto alle logiche combinatorie, e come ho implementato un contatore sincrono a 4 bit su un ATF16V8B usando WinCUPL.
Combinatorio vs Sequenziale: il concetto chiave
Il punto di partenza è la distinzione fondamentale che abbiamo già incontrato nel corso di elettronica digitale: nelle logiche combinatorie, le uscite dipendono esclusivamente dal valore corrente degli ingressi. Nelle logiche sequenziali, invece, le uscite dipendono anche dalla storia passata — dagli stati precedenti degli ingressi o delle uscite stesse. C’è, in altre parole, un effetto di memoria.
L’elemento cardine di una logica sequenziale è il flip-flop: un componente che memorizza un valore e lo mantiene fino al successivo impulso di clock. I PLD sequenziali integrano flip-flop al loro interno, affiancandoli alla rete combinatoria (matrice AND–OR) che già conosciamo.
La struttura interna di un PLD sequenziale
In un PLD sequenziale troviamo sempre la classica struttura AND–OR, ma le uscite della rete combinatoria possono ora essere collegate a flip-flop prima di uscire dal dispositivo. Il clock di questi flip-flop è tipicamente in comune a tutti e portato su un pin esterno — una scelta che, come vedremo, ha importanti implicazioni.
Le uscite possono assumere diverse configurazioni:
- Solo retroazione interna: l’uscita combinatoria non è accessibile dall’esterno, ma viene riportata all’ingresso della matrice AND.
- Flip-flop in retroazione, senza pin esterno: il flip-flop memorizza e retroazione, ma non è visibile all’esterno.
- Flip-flop con uscita esterna e retroazione: la configurazione più comune e flessibile.
- Flip-flop con uscita esterna, senza retroazione.
- Uscita puramente combinatoria: senza flip-flop, come in un PLD tradizionale.
Questa varietà di configurazioni ci consente di implementare entrambi i grandi modelli di macchine sequenziali: il modello di Moore e il modello di Mealy.
Moore vs Mealy
Nel modello di Moore, le uscite dipendono esclusivamente dallo stato corrente: sono sincrone con il clock, immuni ai glitch sugli ingressi, ma rispondono con un ritardo di un ciclo di clock rispetto a una variazione degli ingressi.
Nel modello di Mealy, le uscite sono invece una combinazione diretta degli ingressi e dello stato attuale: la risposta è immediata e asincrona, ma proprio per questo i glitch sugli ingressi si propagano immediatamente alle uscite.
I PLD sequenziali permettono di implementare entrambi i modelli, sfruttando rispettivamente le uscite dei flip-flop (Moore) o le uscite combinatorie dirette (Mealy).
I dispositivi: PLS, PAL registro e ATF16V8B
Storicamente, i dispositivi sequenziali programmabili si dividono in due famiglie:
- PLS (Programmable Logic Sequencer): evoluzioni della PLA con matrici AND e OR entrambe programmabili, a cui sono stati aggiunti flip-flop.
- PAL registro: PAL classiche con flip-flop di tipo D collegati alle uscite. Ne sono un esempio la PAL16R8 e la PAL16R4, dove la “R” indica appunto la presenza di registri.
Questi componenti vintage — programmabili una sola volta — sono praticamente scomparsi dal mercato. Al loro posto utilizzo l’ATF16V8B, un dispositivo riprogrammabile che emula diverse varianti di PAL, incluse quelle con registri.
L’ATF16V8B dispone di otto macro-celle, una per ogni uscita. Ogni macro-cella contiene un flip-flop di tipo D ma offre anche la possibilità di bypassarlo, scegliendo tra modalità combinatoria e sequenziale. In modalità registered, il pin 1 diventa l’ingresso di clock e il pin 11 diventa l’output enable globale.
Il progetto: contatore sincrono a 4 bit
Con questi dispositivi è impossibile realizzare un contatore asincrono (quello con la cascata di clock), perché il clock è in comune a tutti i flip-flop. Si tratta però di una limitazione tutto sommato vantaggiosa: i contatori sincroni non soffrono del ritardo di propagazione tipico dei contatori asincroni, e tutte le uscite cambiano contemporaneamente all’impulso di clock.
La tavola di transizione
Per progettare il contatore, devo costruire la tavola di transizione: devo cioè stabilire, per ogni stato delle uscite Q3–Q0, qual è il valore che devono avere gli ingressi D dei flip-flop affinché al colpo di clock successivo si passi allo stato corretto.
Le uscite Q diventano, dal punto di vista della logica combinatoria, gli ingressi della rete AND–OR. Il problema sequenziale si trasforma così in un problema combinatorio: trovare le funzioni D0, D1, D2, D3 in funzione di Q0, Q1, Q2, Q3.
Le mappe di Karnaugh e il pattern Exor
- D0 si ricava immediatamente a occhio: il bit meno significativo deve alternare a ogni colpo di clock, quindi
D0 = /Q0. - D1, attraverso la mappa di Karnaugh, si semplifica in
D1 = Q1 $ Q0(dove$è l’operatore XOR di CUPL). - D2 richiede qualche passaggio algebrico in più, applicando il teorema di De Morgan, e porta a
D2 = Q2 $ (Q1 & Q0). - D3 segue lo stesso schema e diventa
D3 = Q3 $ (Q2 & Q1 & Q0).
Il pattern è chiaro: ogni bit Di è l’XOR tra Qi e il prodotto AND di tutti i bit meno significativi. Questo significa che per estendere il contatore a 8 bit non devo ricalcolare nulla: aggiungo semplicemente D4 = Q4 $ (Q3 & Q2 & Q1 & Q0) e così via.
Implementazione in WinCUPL
Il codice CUPL per il contatore a 4 bit è il seguente:
Device G16V8R;
Pin 1 = CLK;
Pin 2 = RESET;
Pin 19 = Q3;
Pin 18 = Q2;
Pin 17 = Q1;
Pin 16 = Q0;
Q0.D = RESET & /Q0;
Q1.D = RESET & (Q1 $ Q0);
Q2.D = RESET & (Q2 $ (Q1 & Q0));
Q3.D = RESET & (Q3 $ (Q2 & Q1 & Q0));
La notazione Q0.D indica l’ingresso D del flip-flop associato all’uscita Q0 — è il modo in cui CUPL distingue il segnale che entra nel flip-flop dall’uscita del flip-flop stesso. Il reset è sincrono e attivo basso: quando RESET = 0, la porta AND forza a zero l’ingresso D indipendentemente dallo stato attuale; quando RESET = 1, il segnale passa trasparente.
Simulazione
Per verificare il funzionamento prima di programmare il chip, uso il simulatore integrato di WinCUPL. Definisco i vettori di test con il simbolo C per i colpi di clock e * per le uscite che il simulatore deve calcolare autonomamente. Dopo aver risolto un piccolo errore sintattico (mancava un punto e virgola), la simulazione conferma il corretto funzionamento: reset porta tutto a zero, poi il contatore avanza correttamente fino a 1111 e poi ritorna a 0000.
Programmazione e test su hardware
Con il file .jed generato da WinCUPL, passo alla programmazione del chip usando la shield per Arduino che ho costruito in un video precedente (in alternativa si può usare un programmatore universale).
Il procedimento è:
- Verificare la comunicazione con il dispositivo (
i ATF16V8B) - Cancellare il chip (
e) - Scrivere e verificare il file (
wv -f contatore4bit.jed)
Sul banco di prova, inserisco l’ATF16V8B in una breadboard con:
- Pin 20 a +5V, pin 10 a GND
- Resistenza di pull-up da 10 kΩ sul pin 2 (RESET), con un cavetto verso massa per azzerare il contatore quando serve
- Pin 11 (Output Enable) collegato a massa per abilitare permanentemente le uscite
- Segnale di clock fornito da un generatore di funzioni a 16 kHz (onda quadra 0–5V)
Collegando tutti e quattro i canali dell’oscilloscopio alle uscite Q0–Q3, si vede chiaramente la divisione in frequenza: partendo da 16 kHz su Q0, si arriva a 1 kHz su Q3, esattamente come atteso. La cosa più bella da osservare è la sincronicità: zoomando fino a 10 nanosecondi per divisione, tutte le uscite variano nello stesso istante, senza alcun ritardo di propagazione. Questo è il vantaggio concreto del contatore sincrono rispetto a quello asincrono.
Ho poi spinto il clock fino a 1,6 MHz: anche a questa frequenza il contatore funziona correttamente, con Q3 che mostra 100 kHz come da attesa.
Conclusioni
Implementare un contatore sincrono su PLD sequenziale è un ottimo esercizio per capire come la logica sequenziale si traduca concretamente in hardware programmabile. Il punto chiave è la trasformazione del problema: invece di “pensare sequenzialmente”, si definisce la rete combinatoria che calcola lo stato futuro a partire dallo stato presente.
Il pattern XOR che emerge dalle mappe di Karnaugh è elegante e scalabile: aggiungere bit al contatore non richiede di rifare i calcoli, ma solo di estendere la regola già trovata. L’ATF16V8B, con le sue otto macro-celle riprogrammabili, è lo strumento ideale per sperimentare questi concetti su hardware reale.
Nel prossimo video del corso vedremo come sfruttare ulteriormente le potenzialità di questi dispositivi per implementare macchine a stati più complesse.
