Programmare uno Z80 con Arduino: arriva la libreria ALEX80µ

Utilizzare un microprocessore Z80 insieme a una scheda Arduino può sembrare una combinazione insolita, ma è proprio alla base del progetto ALEX80µ, una shield per Arduino UNO pensata per sperimentare con uno dei microprocessori a 8 bit più conosciuti della storia dell’informatica.

La particolarità di questa soluzione è che Arduino non si limita a controllare lo Z80, ma si occupa anche di generare il clock e di gestire parte della memoria e dei segnali necessari al suo funzionamento.

Questo approccio permette di realizzare un sistema didattico relativamente semplice, nel quale è possibile osservare e comprendere il funzionamento di un microprocessore a basso livello.

Fino a oggi, però, sviluppare un programma Arduino per ALEX80µ richiedeva di conoscere diversi dettagli hardware della scheda e di utilizzare librerie specifiche per gestire i componenti collegati al bus SPI.

Grazie a una nuova libreria Arduino, sviluppata inizialmente da Flavio Carchedi e successivamente completata e ottimizzata, tutto questo diventa decisamente più semplice.

Nel video vediamo come funziona la libreria, quali ottimizzazioni sono state introdotte e come utilizzarla per eseguire programmi Assembly sullo Z80. Arriveremo anche a far funzionare un interprete Microsoft BASIC, utilizzando la porta seriale di Arduino come terminale.

Una libreria nata dalla collaborazione

L’idea della libreria è di Flavio Carchedi, che aveva acquistato un kit ALEX80µ durante la Maker Faire dell’anno scorso.

Flavio ha iniziato a sviluppare una libreria capace di semplificare la gestione della shield, evitando di dover utilizzare separatamente le librerie per gli I/O expander e per la memoria seriale.

Ho trovato l’idea particolarmente interessante e ho deciso di contribuire al progetto, lavorando soprattutto sull’ottimizzazione delle prestazioni e sulla riorganizzazione degli esempi.

Il risultato è una libreria open source che permette di utilizzare ALEX80µ senza dover conoscere tutti i dettagli della sua implementazione hardware.

La libreria mette a disposizione funzioni per:

  • Gestire i segnali di controllo dello Z80.
  • Leggere lo stato dei bus di indirizzi e controllo.
  • Gestire il bus dati.
  • Generare il clock del microprocessore.
  • Controllare il reset.
  • Leggere e scrivere la memoria.
  • Accedere ai dispositivi SPI presenti sulla shield.

Tutte queste operazioni vengono implementate cercando di ottenere le migliori prestazioni possibili, un aspetto particolarmente importante in un sistema nel quale Arduino deve simulare una parte consistente dell’hardware normalmente presente intorno a un microprocessore.

Perché le prestazioni sono così importanti?

ALEX80µ utilizza due I/O expander MCP23S17 per gestire i segnali dello Z80.

Questi componenti permettono di aggiungere linee di ingresso e uscita utilizzando il bus SPI, una soluzione necessaria perché Arduino UNO non dispone di un numero sufficiente di GPIO per collegare direttamente tutti i segnali del microprocessore.

Gli MCP23S17 sono dispositivi piuttosto versatili: possono funzionare con tensioni di alimentazione comprese tra 1,8 e 5,5 V e dispongono di registri interni per configurare la direzione dei pin, le resistenze di pull-up e lo stato delle uscite.

Nel nostro caso utilizziamo due dispositivi che permettono di controllare i segnali necessari al funzionamento dello Z80.

Anche la memoria seriale presente sulla shield comunica attraverso SPI.

Il problema è che ogni accesso ai dispositivi SPI richiede un certo tempo, e queste operazioni vengono ripetute continuamente durante il funzionamento del microprocessore.

Quando Arduino deve gestire gli accessi alla memoria dello Z80, anche pochi microsecondi risparmiati possono avere un impatto significativo sulle prestazioni complessive.

Per questo motivo avevo già dedicato un precedente video all’ottimizzazione della comunicazione SPI su Arduino.

La nuova libreria riprende e sviluppa ulteriormente quel lavoro.

Le ottimizzazioni introdotte

La libreria è stata progettata specificamente per ALEX80µ, senza cercare di realizzare un’interfaccia generica utilizzabile con qualsiasi hardware.

Questa scelta permette di sfruttare alcune caratteristiche note della scheda per ridurre il numero di operazioni necessarie.

Accesso diretto all’hardware SPI

Una delle ottimizzazioni riguarda l’accesso al bus SPI.

Invece di affidarsi sempre alle funzioni della libreria SPI standard di Arduino, vengono utilizzate, dove opportuno, operazioni a basso livello per comunicare direttamente con le periferiche hardware.

Lo stesso approccio viene adottato per il controllo dei segnali Chip Select, utilizzando l’accesso diretto ai GPIO.

L’obiettivo è ridurre il tempo necessario per ogni operazione.

Gestione ottimizzata degli MCP23S17

Gli I/O expander vengono utilizzati continuamente per leggere e modificare i segnali di controllo dello Z80.

La libreria sfrutta la struttura dei registri interni degli MCP23S17, utilizzando la configurazione BANK 0, che permette di accedere in modo efficiente ai registri delle porte A e B.

Ottimizzare queste operazioni è particolarmente importante perché influiscono direttamente sulla velocità con cui Arduino riesce a gestire il ciclo di funzionamento dello Z80.

Cache per la memoria seriale

Un’altra ottimizzazione importante riguarda la gestione della RAM seriale.

Invece di effettuare necessariamente una transazione SPI per ogni singolo byte letto o scritto, la libreria utilizza una cache che permette di raggruppare gli accessi alla memoria.

Questo riduce il numero di operazioni SPI e soprattutto la necessità di riconfigurare continuamente la periferica quando si passa dalla memoria agli I/O expander.

Le due tipologie di dispositivi possono infatti utilizzare frequenze SPI differenti.

La libreria cerca quindi di limitare le operazioni di configurazione del bus, che rappresentano un ulteriore costo in termini di tempo.

Supporto per Arduino UNO R3 e R4

Una novità importante rispetto al software che avevo sviluppato in precedenza riguarda la compatibilità.

La libreria funziona sia con Arduino UNO R3 sia con Arduino UNO R4.

In particolare, Arduino UNO R4 permette di sfruttare una maggiore quantità di RAM e prestazioni superiori.

La velocità SPI utilizzata dipende dalla scheda:

Scheda MCP23S17 RAM seriale
Arduino UNO R3 8 MHz 8 MHz
Arduino UNO R4 10 MHz 20 MHz

Nei test ho utilizzato Arduino UNO R3 e Arduino UNO R4 WiFi.

La libreria prevede anche il supporto per Arduino UNO R4 Minima, che però non ho avuto modo di provare direttamente.

Installazione della libreria

La libreria ALEX80µ è disponibile su GitHub come progetto open source.

L’installazione è piuttosto semplice: basta scaricare il repository, estrarre l’archivio e copiare la cartella nella directory delle librerie di Arduino.

Se Arduino IDE è già aperto, è necessario chiuderlo e riavviarlo affinché riconosca la nuova libreria.

A questo punto, nel menu degli esempi, compare una nuova sezione dedicata ad ALEX80µ.

Gli esempi disponibili non sono soltanto brevi dimostrazioni delle singole funzioni, ma veri e propri programmi completi che permettono di utilizzare la shield.

Vediamone alcuni.

Il primo esempio: un contatore sui LED

Il primo esempio è probabilmente il più semplice per iniziare a sperimentare.

Si tratta di un piccolo programma Assembly per Z80 che incrementa continuamente un contatore e ne visualizza il valore sugli otto LED presenti sulla shield.

Il funzionamento è molto semplice:

  1. Inizializziamo lo Stack Pointer.
  2. Azzeriamo l’accumulatore.
  3. Inviamo il valore dell’accumulatore a una porta di uscita.
  4. Incrementiamo l’accumulatore.
  5. Introduciamo un piccolo ritardo.
  6. Ripetiamo il ciclo.

Su ALEX80µ, una scrittura verso una porta di uscita viene intercettata dai flip-flop presenti sulla scheda e visualizzata sui LED.

In questo modo possiamo osservare direttamente il conteggio binario.

Come viene caricato il programma?

Il codice macchina dello Z80 viene inserito in un array all’interno dello sketch Arduino.

Questo array rappresenta il contenuto della ROM che Arduino presenta allo Z80.

È importante ricordare che, a differenza del sistema ALEX80 completo, in questo caso non abbiamo un firmware iniziale che prepara l’ambiente di esecuzione.

Il programma parte dall’indirizzo zero e dobbiamo occuparci personalmente di tutte le inizializzazioni necessarie, compreso lo Stack Pointer se utilizziamo istruzioni come CALL.

Nell’esempio viene definito anche l’indirizzo a partire dal quale la memoria deve essere considerata RAM.

Gli indirizzi precedenti vengono invece trattati come ROM: possono essere letti, ma non modificati dallo Z80.

La libreria si occupa di gestire tutti gli accessi alla memoria, nascondendo allo sketch la complessità delle transazioni SPI e della cache.

Quanto è veloce?

Una volta caricato lo sketch su Arduino UNO R4, il contatore inizia immediatamente a funzionare.

Utilizzando un oscilloscopio possiamo osservare il clock generato da Arduino.

In questo primo esempio il clock viene gestito direttamente nel ciclo principale del programma, senza cercare di ottenere una frequenza precisa.

Il risultato è un segnale piuttosto asimmetrico, perché Arduino esegue un numero diverso di operazioni durante le due fasi del clock.

Nonostante questo, lo Z80 riesce a funzionare correttamente.

Con Arduino UNO R4 abbiamo misurato una frequenza di clock di circa 42 kHz.

Non è certo una frequenza elevata per uno Z80, ma dobbiamo considerare che Arduino sta gestendo anche la memoria e i segnali di controllo.

Inoltre, lo scopo di questo esempio è ottenere un programma semplice, facilmente comprensibile e modificabile.

Scrivere programmi Assembly con ALEX80 IDE

Per sperimentare con lo Z80 è necessario poter scrivere e assemblare programmi.

Naturalmente possiamo utilizzare un assemblatore esterno e copiare manualmente i codici macchina nell’array dello sketch Arduino.

Ho però introdotto in ALEX80 IDE una funzione che semplifica questa operazione.

ALEX80 IDE è un ambiente di sviluppo che sto realizzando per i progetti della famiglia ALEX80.

È scritto in C# utilizzando Avalonia ed è pensato per funzionare su macOS, Windows e Linux.

Anche questo progetto è open source e su GitHub è possibile trovare sia i sorgenti sia le versioni compilate per le diverse piattaforme.

L’IDE permette di scrivere programmi Assembly, assemblarli e visualizzare il codice macchina generato.

Tra le funzionalità disponibili c’è anche la possibilità di esportare direttamente il programma sotto forma di array utilizzabile in uno sketch Arduino.

Nel video mostro questa funzione modificando il programma del contatore.

Invece di incrementare un valore sui LED, realizziamo un semplice lampeggio che alterna il valore zero a 255.

Dopo aver assemblato il programma, esportiamo l’array e lo inseriamo nello sketch.

Una volta caricato il nuovo codice su Arduino, i LED iniziano a lampeggiare.

È un metodo semplice per modificare il comportamento dello Z80 senza doversi occupare direttamente della gestione dell’hardware.

Un secondo esempio: ALEX80µ Manager Terminal

Il metodo appena visto funziona, ma presenta una limitazione: ogni volta che modifichiamo il programma Assembly dobbiamo aggiornare lo sketch Arduino e caricarlo nuovamente sulla scheda.

Per evitare questa operazione ho aggiunto un secondo esempio, chiamato ALEX80µ Manager Terminal.

Questo programma riprende alcune funzionalità del software che avevo sviluppato in precedenza per comunicare con ALEX80µ.

La differenza principale è che ora tutta la gestione hardware viene affidata alla nuova libreria.

Lo sketch implementa un’interfaccia seriale che permette di:

  • Leggere il contenuto della memoria.
  • Scrivere dati nella memoria.
  • Caricare programmi.
  • Gestire il reset.
  • Avviare e fermare il clock.
  • Impostare la frequenza del clock.
  • Ottenere informazioni sul sistema.

Possiamo utilizzare questi comandi attraverso un normale terminale seriale, ma la possibilità più interessante è quella di collegarci direttamente con ALEX80 IDE.

Controllare lo Z80 da ALEX80 IDE

Una volta caricato lo sketch Manager Terminal, possiamo aprire ALEX80 IDE e collegarci alla porta seriale di Arduino.

L’IDE riconosce il sistema e permette di interagire con la memoria e con il controllo del clock.

A questo punto possiamo scrivere un programma Assembly, assemblarlo e trasferirlo direttamente nella memoria vista dallo Z80.

Non è più necessario creare manualmente un array né ricaricare lo sketch Arduino.

Nel video utilizzo questa possibilità per caricare il programma che fa lampeggiare i LED.

L’IDE permette anche di leggere la memoria e verificare che il programma sia stato effettivamente trasferito.

Lo sketch Manager Terminal non implementa tutte le funzioni disponibili nell’ambiente ALEX80 completo, come il debug passo passo, ma offre quanto serve per iniziare a sperimentare.

Un clock più regolare

Rispetto al primo esempio, Manager Terminal utilizza una gestione differente del clock.

In questo caso possiamo richiedere una frequenza e il software cerca di generare un segnale con un duty cycle del 50%.

La gestione è non bloccante, in modo da permettere ad Arduino di continuare a eseguire le altre operazioni necessarie.

Naturalmente esiste un limite alla frequenza ottenibile, perché il microcontrollore deve gestire contemporaneamente la comunicazione seriale, la memoria e tutti i segnali dello Z80.

Durante le prove con Arduino UNO R4 abbiamo osservato che, aumentando progressivamente la frequenza richiesta, il sistema raggiunge circa 12 kHz effettivi.

Una frequenza inferiore a quella ottenuta con l’esempio del contatore, ma comprensibile considerando la maggiore complessità del programma.

L’obiettivo, del resto, non è ottenere uno Z80 particolarmente veloce, ma realizzare un ambiente nel quale sia facile scrivere programmi e osservare il funzionamento del microprocessore.

Microsoft BASIC su ALEX80µ

L’ultimo esempio è probabilmente il più interessante.

Flavio ha avuto l’idea di far funzionare un interprete Microsoft BASIC per Z80 utilizzando ALEX80µ.

Avevo già mostrato in passato come utilizzare Microsoft BASIC sul sistema ALEX80 completo, dove la comunicazione con il terminale viene gestita attraverso un’interfaccia seriale SIO.

Su ALEX80µ possiamo adottare una soluzione diversa.

Poiché Arduino controlla gli accessi dello Z80 ai dispositivi esterni, possiamo intercettare determinate operazioni e utilizzarle per scambiare caratteri attraverso la porta seriale di Arduino.

In pratica realizziamo una sorta di interfaccia seriale virtuale.

Come funziona la comunicazione seriale?

Per ricevere i caratteri utilizziamo due indirizzi di ingresso:

  • 0xFF: permette di leggere il carattere ricevuto.
  • 0xFE: permette di verificare se è disponibile un carattere da leggere.

Per l’invio dei caratteri ho adottato una soluzione leggermente diversa.

Inizialmente la comunicazione seriale utilizzava un’istruzione OUT, ma questo entrava in conflitto con il controllo dei LED, che su ALEX80µ vengono pilotati proprio attraverso le operazioni di uscita.

Per risolvere il problema ho utilizzato l’indirizzo di memoria 0x1FFF, corrispondente all’ultima locazione della ROM utilizzata dal BASIC.

Quando lo Z80 esegue una scrittura verso questo indirizzo, Arduino intercetta l’operazione e interpreta il dato come un carattere da inviare sulla propria porta seriale.

In questo modo possiamo continuare a utilizzare le istruzioni OUT all’interno del BASIC per pilotare i LED della shield.

È un piccolo accorgimento che permette di sfruttare le caratteristiche particolari di ALEX80µ senza modificare l’hardware.

Preparare il BASIC

Il codice del Microsoft BASIC non è distribuito insieme alla libreria.

L’esempio contiene le istruzioni per scaricarlo separatamente e apportare le modifiche necessarie alla comunicazione seriale.

Nel repository della libreria è disponibile anche uno script Python che permette di effettuare alcune trasformazioni richieste per assemblare il codice con gli strumenti utilizzati.

In alternativa possiamo usare ALEX80 IDE, che è in grado di assemblare direttamente anche alcune delle particolarità sintattiche presenti nei sorgenti originali.

Le modifiche relative alla comunicazione seriale rimangono comunque necessarie.

Nel video mostro l’intera procedura, partendo dai sorgenti del BASIC fino alla generazione dell’array che viene utilizzato dallo sketch Arduino.

ALEX80 IDE permette anche di gestire più sorgenti all’interno dello stesso progetto, una funzionalità utile proprio in questo caso.

BASIC in esecuzione sullo Z80

Una volta preparato il programma e caricato lo sketch su Arduino, possiamo aprire un terminale seriale configurato a 115200 baud.

Il BASIC si avvia e presenta la consueta richiesta di inizializzazione della memoria.

A questo punto abbiamo un vero interprete BASIC che viene eseguito dallo Z80 presente sulla shield.

Possiamo scrivere ed eseguire programmi utilizzando il terminale del computer.

Nel video provo anche l’istruzione OUT, verificando che sia possibile accendere i LED direttamente dal BASIC.

Ad esempio, scrivendo:

OUT 0,1

accendiamo il primo LED.

Con:

OUT 0,3

accendiamo i primi due LED, perché il valore 3 corrisponde a 00000011 in binario.

Possiamo quindi realizzare anche il classico programma di conteggio utilizzando il BASIC invece dell’Assembly.

È interessante osservare che il programma viene eseguito senza introdurre ritardi artificiali: l’interprete BASIC richiede già un numero significativo di operazioni allo Z80 e quindi ad Arduino, che ne gestisce il funzionamento.

Durante questa prova il clock generato da Arduino varia indicativamente tra 30 e 60 kHz.

Il risultato è comunque un sistema perfettamente utilizzabile per semplici esperimenti di programmazione.

Un ambiente completo per sperimentare con lo Z80

La nuova libreria rappresenta un passo avanti importante per ALEX80µ.

L’obiettivo del progetto non è mai stato quello di ottenere le massime prestazioni possibili da uno Z80.

Per questo esistono soluzioni hardware differenti, compreso il sistema ALEX80 completo.

Con ALEX80µ l’idea è invece avere un microprocessore collegato a una scheda Arduino, con la possibilità di osservare direttamente i segnali di controllo, il clock e le operazioni di lettura e scrittura.

È un modo per sperimentare con l’architettura di un microprocessore, capire il ruolo della memoria e delle periferiche e scrivere programmi che interagiscono direttamente con l’hardware.

La nuova libreria rende tutto questo più accessibile.

Possiamo partire da un semplice contatore, utilizzare ALEX80 IDE per scrivere e caricare programmi Assembly oppure arrivare a eseguire un interprete BASIC.

E soprattutto possiamo farlo senza dover ogni volta riscrivere il codice necessario per gestire gli I/O expander, la memoria seriale e i segnali dello Z80.

La libreria è disponibile su GitHub, insieme agli esempi e ai sorgenti. Anche ALEX80 IDE è un progetto open source.

Per chi fosse interessato alla parte hardware, la shield ALEX80µ è disponibile su shopalexacademy.it.

Ringrazio ancora Flavio Carchedi per aver dato il via a questo lavoro e per le idee che hanno portato alla realizzazione della libreria.

Nel video trovate tutti i passaggi mostrati direttamente su Arduino IDE e ALEX80 IDE, comprese le prove con l’oscilloscopio e l’esecuzione del Microsoft BASIC.

Se vi interessa sperimentare con lo Z80, vi consiglio di guardarlo: può essere un buon punto di partenza per utilizzare ALEX80µ e sviluppare i vostri programmi.

Per chi sarà alla Maker Faire Rome dal 23 al 25 ottobre 2026, sarà anche un’occasione per incontrarci allo stand Alexa Academy, vedere i progetti dal vivo e fare due chiacchiere.

Avatar Paolo Godino