Simulatore ed ambiente di sviluppo per il processore G80 (compatibile Z80), pensato per
imparare il linguaggio assembly e l'interfacciamento con le periferiche.
| Modalità | Come | Note |
|---|---|---|
| File singolo (consigliata) | doppio clic su G80Lab.html | funziona offline, non serve installare nulla |
| Intranet / PWA | apri web/index.html da un indirizzo http(s):// | si può installare come app e resta offline |
| Server del docente | node servi.mjs → http://localhost:8080/web/index.html | per la classe, stessa rete |
Serve solo un browser moderno (Chrome, Edge, Firefox). Nessuna installazione.
Colonna sinistra
preimpostati, Apri .asm… per caricare un file dal disco e Salva .asm… per scaricare
il sorgente sull'ultimo file (o su un nome nuovo).
(istruzioni per fotogramma, con i preset 🐢 lenta / ▶ normale / ⚡ veloce) e il
prescaler del CTC. Sotto: registri e flag
(clic su un registro per modificarne il valore, come il menu *Registers* del G80Sim).
clic su un byte per modificarlo. Sotto, tre linguette: Dis-assembly (16 istruzioni),
Instruction Trace (istruzioni eseguite, con dettaglio a scelta) e Listing (.lst)
(il listato dell'assembler, come *View assembly listing*).
Colonna destra
IX/IY/SP/PC, MAR) e i segnali di bus dell'ultima operazione
(MEMRQ/RD/WR/IORQ). Pulsante ⛶ modalità LIM per proiettare a schermo intero.
istruzione** (fetch, ALU, memoria, I/O) con il messaggio in stile simulatore originale;
▶ micro-passo scorre la sequenza, ↻ riparte.
interruttori, tastiera, keypad, motore, kiln, beeper.
valore letto/scritto e conteggi.
ld a, 0x55 ; A = 0101 0101
ciclo:
out (0x20), a ; mostra A sugli 8 LED
inc a ; A = A + 1
jp ciclo ; ripeti
Suggerimento: usa Passo con la velocità al minimo per *vedere* come cambiano i registri.
; commento fino a fine riga
LEDS = 0x20 ; costante (equate)
inizio: ; etichetta (indirizzo)
out (LEDS), a
127 (decimale) · 0x1F (esadecimale) · "a" (carattere) · -1
Espressioni: + - * / & | ^ << >> ~ ( ) e differenze fra etichette (fine - inizio = lunghezza).
| Direttiva | Uso | Esempio | |
|---|---|---|---|
.org | indirizzo di partenza | .org 0x0100 | |
| `.seg NOME (abs\ | rel)` | segmento assoluto o rilocabile | .seg CODE (rel) |
.db | byte | .db 0x0A | |
.dw | parola a 16 bit (indirizzo) | .dw servizio | |
.ds | riserva N byte | .ds 6 | |
.ascii | stringa | .ascii /Ciao/ oppure .ascii "a" | |
.globl | esporta un simbolo (per il linking) | .globl valore | |
.if / .else / .endif | assembly condizionale | .if VERSIONE |
Tutte le istruzioni Z80 documentate (LD, ADD, JP, CALL, RST, IN/OUT, LDIR, …) e i prefissi
CB/ED/DD/FD (indici IX/IY, indirizzamento (IX+5)).
| Comando | Cosa fa | |
|---|---|---|
| Reset | ricarica il programma dall'inizio | |
| **Passo ▶︎\ | ** | esegue una istruzione |
| ⌁ ciclo | avanza di una micro-operazione (pannello Micro-operazioni); a fine sequenza esegue la prossima istruzione | |
| Esegui ▶ / Pausa ⏸ | esegue in continuazione | |
| velocità | quante istruzioni per fotogramma (più alto = più veloce); preset 🐢 300 / ▶ 5000 / ⚡ 20000, la scelta viene ricordata | |
| breakpoint | campo indirizzo + *Imposta/Rimuovi*, oppure clic su una riga del disassemblaggio |
Il programma si ferma quando: arriva a HALT, incontra un breakpoint, o esegue un'istruzione
illegale per il G80 (compare un messaggio nel log).
Per togliere un breakpoint: clic di nuovo sulla riga rossa, oppure ✕ Togli breakpoint,
oppure rimetti lo stesso indirizzo e premi *Imposta/Rimuovi*. C'è un solo breakpoint alla volta.
| Registro | Significato |
|---|---|
A | accumulatore (risultati, I/O) |
F | flag |
B C D E H L | registri generali (a coppie: BC, DE, HL) |
PC | prossima istruzione |
SP | puntatore allo stack |
IX, IY | registri indice |
I | byte alto dei vettori di interrupt (IM2) |
R | contatore di refresh (solo in modalità Z80) |
Flag mostrati come S Z 5 H 3 V N C:
S segno · Z zero · H half-carry · V overflow/parità · N sottrazione · C carry.
(Verde = flag attivo.)
◀ 256 / 256 ▶; scrivi un indirizzo nel campo per saltare; Vai al PC.visualizzato — clic su una riga = imposta/togli breakpoint.
istruzione: indirizzo, byte, disassemblaggio, registri (A, BC, DE, HL, F) e
T-state consumati. Per capire *come* funziona un'istruzione: mettila in un programma,
premi Passo e leggi la riga. Il trace si riempie usando Passo o quando la linguetta
è attiva; pulisci trace lo svuota (massimo 500 righe, le più vecchie escono).
Con messaggi si sceglie il dettaglio: *solo istruzioni*, *+ fetch*, *+ micro-operazioni*.
come *View assembly listing* del G80Sim; con il multi-file mostra la link map.
plancia del simulatore originale:
- IR = opcode dell'istruzione in esecuzione; A e i flag; le coppie
BC/DE/HL; IX/IY/SP/PC; MAR = ultimo indirizzo comparso sul bus;
- i segnali di bus (MEMRQ, RD, WR, IORQ) si accendono secondo l'ultima
operazione: *fetch istruzione*, *lettura/scrittura memoria*, *IN/OUT*;
- sotto il riquadro: l'ultima operazione di bus, la prossima istruzione (a PC) e
lo stato (IM, IFF1, R, HALT);
- ⛶ modalità LIM: ingrandisce il pannello a tutto schermo (per proiettare) e mostra una
barra di comandi integrata: *Reset*, *Passo*, *⌁ ciclo*, *Esegui/Pausa*, *micro-passo*,
*chiudi*. Scorciatoie da tastiera in modalità LIM: Spazio = Passo, C = ciclo,
R = Esegui/Pausa, Esc = chiudi.
il messaggio Execute instruction with op code 3E: LD A, n e la **sequenza delle
micro-operazioni**: fetch (PC → MAR, M[MAR] → MDR, MDR → IR, PC + 1 → PC) seguita
dai passi di esecuzione (operando, ALU, scritture in memoria, I/O). Con ▶ micro-passo si
evidenzia una micro-operazione per volta; ↻ torna all'inizio. È la vista per spiegare
*come* la CPU decodifica ed esegue una singola istruzione.
| Porta | Periferica | Direzione | Note |
|---|---|---|---|
0x20 | 8 LED | OUT | 1 bit = 1 LED |
0x30 | Chart recorder (canale 0) | OUT | una scrittura = un campione |
0x31 | Chart — marker rosso | OUT | |
0x32, 0x33 | Chart — marker verde/blu | OUT | |
0x40 | Potenziometro | IN | slider (0‑255) |
0x60 | Beeper | OUT | segnala un beep |
0x70 | Timer (CTC): costante | OUT | |
0x71 | Timer: vettore/controllo | OUT | vettore (<0x80) poi 0x83 |
0x80 | Keypad: lettura | IN | bit7 = dato pronto, bit0‑3 = tasto 0‑F |
0x81 | Keypad: vettore/controllo | OUT | vettore poi 0x83 |
0x90 | 8 interruttori | IN | |
0xA0, 0xA1 | 2 display 7 segmenti | OUT | |
0xB0 | Motore stepper | OUT | impulso 0→1 = un passo |
0xC0 | Tastiera ASCII | IN | 0 = nessun tasto |
0xD0 | LCD 20×10 | OUT | 0x0A = nuova riga |
0xE0 | Counter/nastro: costante | OUT | |
0xE1 | Counter: vettore/controllo | OUT | vettore poi 0x83 |
0xF0 | Kiln: temperatura | IN | |
0xF1 | Kiln: controllo/stato | OUT/IN | OUT: bit0 = riscaldatore · IN: bit7 = dato pronto |
0x01, 0x03 | vettori device A/B | OUT | per gli interrupt |
out (0x20), a ; accendi i LED secondo A
in a, (0x90) ; leggi gli interruttori
out (0xD0), a ; scrivi un carattere sul LCD
in a, (0x40) ; leggi il potenziometro
costante × prescaler, dove il prescaler si sceglie dalla tendina CTC (16/64/256).Schema tipico (usato dal timer, dal counter e dal keypad):
.org 0x0010
VTab: .dw servizio ; tabella dei vettori (indirizzo pari)
.org 0x0100
inizio:
ld a, 0x08
out (0x70), a ; costante del timer
ld a, VTab
out (0x71), a ; byte basso del vettore
ld a, 0x83
out (0x71), a ; abilita (bit0 run, bit1 interrupt)
ld a, 0
ld i, a ; byte alto della tabella
im 2
ei
ciclo:
jp ciclo ; programma principale
servizio:
push af
; ... fai qualcosa ...
pop af
ei
reti
Regole utili:
< 0x80), poi 0x83 per abilitare;I fornisce il byte alto dell'indirizzo della tabella;EI e RETI.Nell'editor puoi scrivere più file separati da una riga marcatore:
;=== FILE: main.asm ===
.globl valore
.seg CODE (rel)
ld a, 7
ld (valore), a
.seg RAM (rel)
valore: .ds 1
;=== FILE: extra.asm ===
.globl valore
.seg CODE (rel)
ld a, (valore)
add a, 2
ld (valore), a
halt
Premendo Assembla & Carica l'app assembla ogni file e poi linka: i segmenti con lo stesso
nome vengono uniti, i simboli .globl risolti (la link map compare nel log).
Il G80 è compatibile Z80, ma non implementa:
DAALD R,A e LD A,RIXH/IXL/IYH/IYLSLL (CB 00110xxx)Se usi queste istruzioni, il programma si ferma con "opcode illegale" (nel log).
L'hardware di interrupt dei device supporta solo IM1 e IM2.
esempi/ — 12 programmi commentati (LED, LCD, tastiera, keypad, timer+interrupt, motore, kiln, multi-file, progetti di riferimento del finale) + esempi/README.md.
esercizi/ — 6 esercizi con consegna, file di partenza (TODO) e soluzioni; leggi esercizi/README.md.
| Sintomo | Causa / soluzione |
|---|---|
| "Errori: N (riga X: …)" | errore di sintassi a quella riga: controlla mnemonic e virgole |
| Il programma non fa nulla | manca un ciclo o un HALT; verifica con Passo |
| "Opcode illegale" | hai usato un'istruzione non supportata dal G80 (vedi §11) |
| I LED non cambiano | controlla di aver scritto sulla porta 0x20 |
| Il LCD resta vuoto | scrivi sulla porta 0xD0; la stringa deve arrivare lì (OTIR) |
| Il programma è lentissimo | aumenta la velocità (istruzioni per fotogramma, preset ⚡ veloce) |
| I LED (o un conteggio) cambiano troppo in fretta | non è un difetto: a ⚡ 20000 il programma avanza di milioni di istruzioni al secondo. Usa 🐢 lenta (300) oppure Passo |
| Il breakpoint non si toglie | clic sulla riga rossa oppure ✕ Togli breakpoint |
| Non vedo il mio programma dopo il riavvio | il sorgente si salva in automatico; se hai aperto un altro file, ricaricalo con Apri .asm… |
| Non si installa come app | l'installazione (PWA) funziona solo aprendo da http/https, non da file |
| L'app installata mostra una versione vecchia | apri l'app con la rete attiva e ricarica: il service worker è *network-first* e si aggiorna da solo (al massimo riapri una volta). In casi ostinati: ricarica forzata (Ctrl+F5) o reinstalla la PWA |
.ihx).IN/OUT).abs) o rilocabile (rel).*G80 Lab — manuale per studenti. Aggiornato al 27/09/2026.*