
Emulatore PDP-11/34 a livello di circuito
ll/34 è un emulatore a livello circuitale per il PDP-11/34A (1976), che esegue una CPU virtuale ricostruita a partire dagli schemi, dal microcodice e dalle acquisizioni logiche di un vero PDP-11/34A.
Fu originariamente progettato come replica digitale della vera CPU per assistere nella risoluzione dei problemi a livello di segnale. La CPU virtuale KD11-EA consiste essenzialmente in una traduzione in C degli schemi e in ricerche nelle tabelle ROM. Tutte le ROM combinatorie sono state reverse-engineered e il generatore di clock è modellato con precisione.
È stato scelto il livello circuitale (tabelle di verità ROM + logica combinatoria) invece del livello gate (Verilog) perché è sufficientemente a basso livello per riprodurre i bug hardware, ma abbastanza veloce da eseguire programmi.
Tutti i dispositivi sono collegati al backplane UNIBUS (unibus.c), che esegue la decodifica degli indirizzi, la temporizzazione e i cicli di bus.
Internamente, la CPU è composta dai seguenti componenti:
| File | Descrizione |
|---|---|
ucode_rom.h | Memoria di microcodice 512x48 bit (PROM bipolari), basata sul Verilog e sui dump di Bitsavers. Ogni micro-parola controlla l'ALU, il scratchpad, l'interfaccia di bus e il branching per un micro-ciclo. |
combo_roms.h | ROM combinatorie (E51-E83, E107), decodifica IR (E59/E60/E63/E69/E70/E71/E74), selezione funzione ALU (E61/E82/E83), priorità trap/servizio (E52/E53) e logica dei codici di condizione (E68/E107), tutte ricostituite dagli schemi e dalle acquisizioni logiche. Le ROM a collettore aperto fanno un wire-OR sul bus MPC. |
kd11ea.c | Motore del datapath. Avanza nel microcodice un micro-parola per ciclo. I gate 74xx di base sono simulati usando operatori logici C (!, &&, >> ecc.). L'ALU bit-slice 74S181 è completamente modellata (4 slice, 16 bit). |
mmu.c | Gestione della memoria. Spazi di indirizzi kernel/utente, rilocazione a 18 bit (3 sommatori 74S283), 16 coppie PAR/PDR, registri di abort SR0/SR2 con logica di freeze. |
clockgen.c | Generatore di clock. Modella la linea di ritardo E106 (feedback TAP 30/90/120, bus di attesa TRAN INH). Cicli brevi: 180 ns, cicli lunghi: 240 ns, i trasferimenti di bus si allungano fino al ritorno di SSYN. |
clock.c | Temporizzazione in tempo reale. Mantiene il tempo simulato sincronizzato con il tempo reale. |
int.c | Arbitro degli interrupt. Coda di priorità BR4-BR7, approssima l'ordine di concessione a catena di margherita del UNIBUS. |
Emula gli interruttori e gli indicatori del pannello frontale del PDP-11/34A. Attiva quando la CPU è in arresto (accensione, istruzione HALT o Ctrl-P).
Permette di inizializzare il bus, avviare la CPU, eseguire passo-passo il codice, esaminare e depositare dati a indirizzi arbitrari e uscire dall'emulatore.
Il frontend è disaccoppiato dal motore, quindi è disponibile anche una GUI del pannello frontale fotorealistica in WebAssembly.
La console di debug fornisce un debugger interattivo sia a livello di microcodice che a livello di istruzioni:
s [n]: esegue passo-passo n micro-istruzioni con dump completo dello stato (MPC, ALU, bus, registri)b addr: imposta un breakpoint sul PC (ottale), bl per elencare, bd n per eliminareg: riprende l'esecuzioneu [addr] [n]: disassembly delle istruzionic [addr] [n]: dump della memoria (ottale)mmu: mostra lo stato della MMU (PAR/PDR kernel e utente, modalità corrente marcata)r: dump dei registriLa risoluzione dei problemi di ll-34 durante il suo sviluppo si è rivelata così simile alla risoluzione dei problemi sul hardware reale che è stato implementato un analizzatore logico interno per tracciare i segnali e sondare il datapath. Questo si è dimostrato determinante per scovare sottili bug nelle ROM e nella temporizzazione della CPU virtuale. Può anche essere utilizzato come riferimento per risolvere problemi sul hardware reale, proprio come l'hardware funzionante ha aiutato a sviluppare l'emulatore.
L'analizzatore logico permette di sondare 102 punti sui principali segnali della CPU, mappati a pin fisici dei chip (notazione KD1:Exx:pin corrispondente agli schemi DEC K1-5 fino a K2-9). Gli alias logici (MPC, ALU_OUT, IR, PSW…) sono forniti per comodità.
La frequenza di campionamento è il clock reale della CPU (5.555.556 Hz) con una risoluzione di 180 ns per campione. Un divisore configurabile riduce la frequenza di campionamento per finestre di acquisizione più lunghe.
Le acquisizioni usano un buffer circolare (fino a 64K campioni) con trigger configurabile su qualsiasi segnale, posizione del trigger regolabile (rapporto pre/post) ed esportazione CSV per analisi offline.
Le acquisizioni logiche sono state ampiamente utilizzate durante il progetto per mappare e fare debug di percorsi di multiplexing poco compresi.
ll-34 viene fornito con alcuni programmi e sistemi da provare: un Game of Life, V6 UNIX, RT-11 V4 con il gioco originale Tetris e ATTN/11, un piccolo Transformer addestrabile con self-attention.
./ll-34 --rk ./wasm/demos/rtv4_rk.dsk
La ROM di boot caricherà automaticamente dal RK11 e avvierà il sistema operativo. DIR elencherà i file, HELP stamperà l'aiuto, RUN TETRIS avvierà il demo Tetris (anche se probabilmente $TERM sarà sbagliato?). RUN ADVENT avvierà Colossal Cave Adventure, costruito su un vero PDP-11/34.
./ll-34 --rk ./wasm/demos/v6bin.rk
Il bootloader stamperà un minimo prompt @. Digita rkunix e premi invio, e dopo qualche secondo dovresti ottenere un prompt login:. Inserisci il nome utente root senza password e sei dentro! Una nota: cd si chiama chdir nei primi Unix.
make + un compilatore C11, non ci sono altre dipendenze.
Verificato che si compila senza warning su Linux (x86_64 e aarch64) sia con musl che con glibc, macOS aarch64 e NetBSD 10 aarch64.
Oltre alla CLI, è disponibile una versione WebAssembly autonoma con una GUI fotorealistica qui: https://dbrll.github.io/ll-34.
Nota: ll-34 è un emulatore ad alta intensità di risorse. A differenza degli emulatori a livello di istruzioni, esegue il microcodice un ciclo alla volta e ad ogni passo esegue l'ALU, le ROM combinatorie, lo scratchpad, il generatore di clock e la temporizzazione del bus. L'host deve sostenere continuamente il ritmo del generatore di clock a 5.5 MHz per rimanere accurato a livello di ciclo.
All'avvio, l'emulatore si autovaluta e riporta la sua velocità relativa a un vero KD11-EA. Un rapporto inferiore a 1x significa che l'host non riesce a tenere il passo e l'accuratezza della temporizzazione non è garantita. Il benchmark non è disponibile nella versione WebAssembly, dove la risoluzione del timer del browser lo rende inaffidabile. Poiché la build WASM è più lenta di quella nativa, eseguirla su uno smartphone sarà generalmente troppo lento.