Computer / Programmazione / Z80 · 11 febbraio 2019 0

LM80C: aggiungiamo uno Z80 CTC

Dopo le ultime modifiche, il nostro prototipo comincia a prendere (molto alla lontana) l’apparenza di un vero computer. Abbiamo un’unità di elaborazione centrale che esegue il codice, abbiamo una memoria non volatile dove abbiamo memorizzato il nostro programma, abbiamo una RAM da cui la CPU legge e su cui scrive i dati, ed abbiamo anche una periferica che interagisce con il mondo esterno. Oggi andremo ad aggiungere un altro chip periferico, uno Z80 CTC, un contatore/timer programmabile che può rivelarsi utile in molte situazioni.

Un contatore/timer è una periferica che può contare segnali esterni (“contatore”) o misurare un tempo (“timer”). Possiamo usare un timer per far eseguire alla CPU una specifica sub-routine dopo un certo periodo di tempo. Oppure per sollevare un segnale di interrupt dopo uno specifico numero di impulsi arrivati al chip. Possiamo istruire il CTC per generare un segnale su un pin ad una specifica frequenza. La misurazione del tempo è un compito importante di ogni computer: un/una programmatore/trice può usare il tempo trascorso per impostare dei ritardi nel suo software, pianificare dei compiti da eseguire a orari fissati o dopo un certo lasso di tempo, per tenere un semplice calendario e così via. Alcuni progettisti di computer del passato, per contenere il più possibile i costi, non usavano nessun hardware specifico per questi compiti, perciò i programmatori/trici dovevano usare ciò che era incluso nel sistema: ad esempio, gli utenti MSX utilizzavano l’interrupt sollevato dal segnale di rinfresco verticale del processore video, che si verificava per 50 o 60 volte al secondo (a seconda del tipo di chip montato sul computer, se PAL o NTSC), mentre i sistemi Commodore avevano questa funzione di serie. I moderni microcontrollori di solito integrano uno o più contatori/timer che possono essere programmati per un saco di compiti: ma le vecchie CPU non avevano tali periferiche integrate perciò dovevano affidarsi ad hardware esterno. Zilog realizzò veramente un buon chip, lo Z80 CTC. Ha 4 timer programmabili che possono essere pilotati da un clock interno o esterno: in quest’ultimo caso lavorano come contatori, contando quanti impulsi ricevono sui loro pin. Questa è la piedinatura del chip:

Z80 CTC

Lo Z80 CTC

Come si può vedere questo è un altro membro della famiglia Z80, perciò può essere collegato direttamente al nostro Z80 senza nessun componente addizionale. Necessita soltanto del collegamento dei signali principali dello Z80 (come IORQ, M1, ecc..) e di essere connesso al bus dati. Ecco i collegamenti:

  • D0..D7: al bus dati
  • /RD: da collegare ad un selettore per scegliere fra lettura e scrittura
  • /IORQ, /M1 e CLK: questi vanno connessi ai corrispondenti pin della CPU
  • /RESET: alla linea di reset del sistema
  • CS0 e CS1: usati per selezionare il timer con cui interagire – di solito si collegano ai pin A0 e A1 della CPU
  • /CE: il pin di abilitazione del chip – questo pin lo colleghiamo al nostro decoder delle periferiche 74139

I pin di interrupt (/INT, IEI, and IEO) sono usati soltanto se viene implementata la catena di interrupt dello Z80: in caso negativo, potete lasciarli disconnessi o usare soltanto la linea /INT se pensate di usare l’interrupt generato dal CTC.

Come lavora il CTC? Esso ha 4 timer interni (dal Timer 0 al Timer 3) che possono essere programmati come timer o contatori: possono essere temporizzati dal clock di sistema oppure da un segnale di clock esterno sul corrispondente pin CLK/TRG. Quando il registro del timer raggiunge lo 0, il timer manda un segnale esterno sul suo pin ZC/TO e, nello stesso tempo, ricarica il valore iniziare (questa caratteristica può essere attiva oppure no). Il timer può anche sollevare un segnale di interrupt: se il chip è inserito in una catena di gestione degli interrupt Z80 e la CPU sta operando con la modalità interrupt 2, allora la CPU può eseguire una routine di gestione dell’interrupt ad uno specifico indirizzo. Altrimenti, verrà sollevato un segnale di interrupt generico sul pin INT e sarà compito del programmatore/trice gestire questi interrupt nella maniera corretta. Come si vede dalla figura, il Timer 3 non possiede il pin TO: questo significa che questo timer non può inviare segnali esterni quando il suo registro raggiunge lo 0. I timer hanno un divisore di frequenza (prescaler) così che il clock di sistema può essere ridotto se servono frequenze basse: inoltre, si possono collegare in cascata più timer, se servono frequenze molto basse. Quest’ultimo è il nostro caso: metteremo infatti in cascata 2 timer per ottenere un segnale ad 1 Hz. Stiamo infatti procedendo per realizzare un semplice “blinker” che farà lampeggiare un LED per mostrare che siamo stati in grado di programmare il nostro CTC.

Cominciamo con il progetto dell’LM80C con PIO e RAM che è già pronto e funzionante e aggiungiamo il nostro CTC. Andremo perciò a realizzare questo circuito:

LM80C: PIO, RAM & CTC

LM80C: PIO, RAM e CTC

Utilizzeremo l’unità libero del flip-flop di tipo D 7474 che abbiamo usato per il nostro divisore di clock come il segnale alternato che piloterà il LED. Useremo anche l’altra unità del decoder 74139 che abbiamo usato per selezionare il PIO: come detto nel precedente articolo, avremmo usato questo chip molto presto. Per usare il 74139 per selezionare fra i 2 chip periferici dobbiamo solo collegare il pin /CE del CTC al pin 11 del decoder: grazie a questo semplice collegamento saremo in grado di scegliere fra il PIO o il CTC semplicemente impostando il pin A4 rispettivamente a 0 oppure 1. Poi dovremo collegare i pin di controllo ai corrispondenti pin della CPU. I pin CS0 e CS1 saranno connessi ai pin A0 e A1 e saranno usati per selezionare il timer interno con cui comunicheremo. Come si vede dallo schema sopra, c’è un collegamento fra TO0 e TRG1: come detto in precedenza, possiamo collegare in cascata più timer se abbiamo bisogno di un conteggio più grande di 256×256. Questo è il nostro caso: dobbiamo raggiungere un valore di clock di 1 Hz per cui dobbiamo usare 2 timer. Infatti andremo a dividere il nostro clock di sistema con un fattore di divisione di 256 che, con il registro ad 8 bit del contatore, ci da un clock risultante di circa 56,16 Hz: 3.686.400 / 256 / 256 = 56,15 Hz. Questo non è abbastanza, per cui dobbiamo usare il segnale sul pin di output come un segnale di trigger per il pin di input del secondo timer: dato che il clock di input è di circa 56 Hz, andremo ad istruire il timer per contare proprio da 56 a 0, ottenendo un clock di output di 1,002 Hz, molto molto vicino a 1 Hz (1 secondo).

Per vedere che il CTC lavora come previsto, collegheremo il pin di output del secondo timer usato all’input non usato del nostro flip-flop di tipo D e andremo a far lampeggiare un LED (in questo caso la frequenza di output sarà di 0,5 Hz perché il flip-flop dimezza il clock in input). Facciamo l’upload del codice e poi osserviamo il LED che lampeggia indipendentemente dai LED pilotati dal PIO:

Come sempre, lo schema completo ed il codice sono sul mio repository GitHub.