Ecco, a gran richiesta, il mio computer Z80!
Il computer completo: è formato da due schede, la inferiore è la scheda madre, la superiore è solo un supporto per l'Arduino e per una porta XOR (nascosta sotto l'Arduino).
L'Arduino Mega 2560 è usato come interfaccia per collegarsi all'USB (e prendere energia da essa) e usare un emulatore di terminale sul PC.
Questa è la scheda madre; il computer è tutto qui!
In alto a sinistra abbiamo il grande chip, lo Z80, un Z84C0010 versione CMOS che può andare a 10MHz, ma che ora è controllato da un clock di 8MHz (scatolina argentata in basso). Ho anche un generatore da 20MHz, e penso che lo Z80 non abbia problemi ad andare a quella velocità
.
Alla sua sinistra il bus di espansione che fornisce tutti i 40 segnali dello Z80. A destra abbiamo nell'ordine UVEPROM (da 32KiB ma solo 8KiB mappabili) che contiene i circa 700 byte di monitor (se non sapete cos'è chiedete a TheKaneB
), e i due chip da 32 KiB di SRAM.
Attraverso i circuiti di decodifica (5 dei 6 chip sotto) posso decidere (da programma) se mostrare allo Z80 8KiB di ROM e 56KiB di RAM, o tutti i 64 KiB di RAM.
L'ultimo chip è un demultiplexer per l'I/O, che fornisce 7 linee già decodificate per le periferiche (attraverso la striscia di contatti più esterna in basso a sinistra; la più interna è un'estensione del registro a 4 bit di cui già uso un bit per configurare la ROM).
Lato saldature, con brevettato cable management system!
Esempio di sessione del terminale: Il primo messaggio è del firmware dell'Arduino, dopo ci sono messaggi generati solo dallo Z80, passati all'Arduino, e quindi trasmessi all'emulatore di terminale.
Ci sono 5 comandi del Monitor: "d" per "dump", visualizza il contenuto della memoria delimitato dai due indirizzi indicati; "s" per "set", carica all'indirizzo indicato come primo parametro la lista di byte che segue (il limite è dato solo dal buffer di input di 256 byte); "e" per "esegui", salta all'indirizzo indicato, mantenendo nello stack l'indirizzo di ritorno così si può tornare con un semplice RET.
Il programma che ho inserito nell'immagine è: 0x3e, 0x41 per LD A, 0x41, carica l'accumulatore con il valore ASCII della A maiuscola; 0xd3, 0x20 per OUT (0x20), A, invia il contenuto dall'accumulatore alla porta di I/O 0x20 (la porta dell'Arduino); 0xc9 per RET, ritorna al Monitor.
Gli ultimi comandi sono "o" per "output", che invia alla porta indicata il valore indicato, e "i" per "input", che legge il valore della porta di I/O indicato.
Nell'esempio, dopo il "i 20", ho premuto shift+a e quindi lo Z80 ha letto dall'Arduino (che a sua volta lo ha ricevuto dal PC), il valore 0x41.
E' da precisare che l'Arduino, in caso non abbia dati da fornire allo Z80, lo blocca con un WAIT, ma basta modificare il firmware dell'Arduino per fargli ritornare 0, e lo Z80 lo ignora tranquillamente.
Schemi:
Schema principale, con Z80 e memorie;
Schema della decodifica degli indirizzi.
Se vi serve posso fornire gli schemi in formato Kicad.
Qui il sorgente del monitor: come si vede c'è una jump table all'inizio, che punta alle routine di input e di output, di cui sono abbastanza orgoglioso: ci sono molti controlli sull'input, e gli errori vengono comunicati attraverso i flag.
Sto già pensando di espanderlo, con un'interfaccia VGA ad esempio, e una tastiera, in modo da renderlo indipendente da un PC; successivamente posso mettere una interfaccia IDE per i dischi fissi/Compact Flash, e altra memoria. CP/M sarebbe carino da portare, ma un bel sistemino multitasking fatto da me è molto più nerdoso!
Fatemi sapere cosa ne pensate!