---
title: "CPUSim: il simulatore di CPU che ho costruito per Zanichelli"
description: "Oggi mi è tornato in mente CPUSim, il simulatore di CPU nel browser creato per Zanichelli nel 2020 per mostrare agli studenti come gira il codice macchina."
author: Federico Meini
date: 2026-06-17
tags: [freelance, education, computer-architecture, typescript]
language: it
url: https://fedme.dev/it/blog/cpusim-a-cpu-simulator-for-zanichelli
---

# CPUSim: il simulatore di CPU che ho costruito per Zanichelli

Oggi mi è tornato in mente un mio vecchio progetto, [CPUSim](https://github.com/fedme/cpusim), e non ho resistito alla tentazione di riaprirlo. Nell’estate del 2020 l’ho costruito per Zanichelli, la casa editrice scolastica: un piccolo simulatore che mostra agli studenti come una CPU esegue il codice macchina. Scrivi qualche riga in un linguaggio assembly giocattolo, premi play e guardi l’istruzione viaggiare dalla memoria ai registri, mentre ogni pezzo dello schema si accende di rosso. Lavorarci è stato divertentissimo, e rileggere il codice sei anni dopo mi ha fatto sorridere più di una volta.

## In breve

- CPUSim è uno strumento didattico, descritto nel repo come “a CPU simulator used in schools to teach machine code”.
- Anima il ciclo fetch–decode–execute su uno schema con registri, ALU, bus e 1.000 celle di RAM.
- Il set di istruzioni ha una ventina di mnemonici, tre modalità di indirizzamento e uno stack.
- L’ho costruito tra maggio e luglio 2020 con React, TypeScript, Redux Toolkit, l’editor Monaco e una grammatica Ohm, e l’ho impacchettato per Windows con Electron.

## Cosa mostra il simulatore

Su un lato dello schermo c’è un editor per il programma, più due editor più piccoli per i dati e per lo stack. Sull’altro c’è un disegno SVG della CPU: i registri operandi R0 e R1, l’accumulatore A, il registro indice IX, lo stack pointer SP, il program counter PC, il registro istruzioni IR, un decoder, una ALU, i registri MAR e MDR, e i bus indirizzi e dati che collegano tutto alla RAM.

La memoria è un unico spazio di indirizzi diviso in tre sezioni: le celle da 0 a 99 contengono il codice, quelle da 100 a 499 i dati e quelle da 500 a 999 lo stack. Ogni registro è cliccabile, così lo studente può impostarne il valore a mano prima di far partire il programma. C’è uno slider per la velocità, pausa e ripresa, un pulsante per eseguire un’istruzione alla volta, e puoi salvare un programma su file e riaprirlo in seguito.

Le specifiche da cui sono partito sono un PDF, ancora presente nel repo. Descrivono l’architettura, elencano tutte le istruzioni e per ognuna dicono esattamente quali componenti si devono accendere, e in che ordine. Un dettaglio che adoro: una nota a piè di pagina precisa che MAR e MDR sono “presenti solo nella grafica”, perché la RAM in realtà è solo un array.

## Il set di istruzioni

Il linguaggio è abbastanza piccolo da imparare in una lezione:

- `SET R0 #5` carica una costante in un registro.
- `ADD`, `SUB`, `MUL` e `DIV` calcolano sempre `R0 op R1` e mettono il risultato in `A`.
- `MOV R0` copia `A` in un registro, e `INC IX` / `DEC IX` fanno avanzare o arretrare il registro indice.
- `LOD R0 120` e `STO 120` leggono e scrivono in memoria. `LOD R0 @3` somma IX all’indirizzo, e `$` rende l’indirizzo relativo a SP.
- `JMP`, `JMZ`, `JML` e `JMG` saltano sempre, oppure solo quando `A` è zero, negativo o positivo.
- `PSH`, `POP`, `CAL` e `RET` lavorano con lo stack, e `HLT` ferma la macchina.

La sintassi sta in una grammatica scritta con [Ohm](https://ohmjs.org/), che analizza ogni riga mentre scrivi e segnala gli errori nell’editor. Si legge quasi come le specifiche:

```
Set = "SET" SetRegister "#"Integer

Lod = "LOD" LodBody
```

## Fetch, decode, execute

Il programma predefinito nell’editor è lungo cinque righe:

```
SET R0 #1
SET R1 #2
ADD
STO 100
HLT
```

Prendi l’`ADD`, che si trova all’indirizzo 2 (l’editor numera le righe da 0, proprio come la memoria). Nella fase di **fetch** PC vale 2. Si accendono PC, il bus indirizzi e MAR, poi la cella di memoria 2, poi MDR, il bus dati e IR. PC si accende ancora una volta mentre viene incrementato a 3, pronto per il giro successivo. Nella fase di **decode** si accendono IR e il decoder. Nella fase di **execute** si accendono R0 e R1, poi la ALU, poi A, che adesso contiene 3. L’istruzione successiva, `STO 100`, manda quel 3 sul bus dati fino alla cella 100, la prima della sezione dati, e `HLT` chiude il programma.

Il codice che fa tutto questo è piacevolmente letterale. Ogni istruzione è un thunk Redux asincrono che accende e spegne le luci con una pausa in mezzo. Questa è la fase di fetch, leggermente accorciata:

```ts
const instruction = cpu.codeMemory[cpu.pc]
const animationInterval = computeAnimationInterval(cpu.executionSpeed)

dispatch(setLightsFetchStart(true)) // PC, address bus, MAR
await sleep(animationInterval)

dispatch(setLightsFetchStart(false))
dispatch(lightRamAddress({ address: cpu.pc, light: true }))
await sleep(animationInterval)

dispatch(setLightsFetchEnd(true)) // MDR, data bus, IR
await sleep(animationInterval)

dispatch(setLightsFetchEnd(false))
dispatch(lightPc(true))
dispatch(incrementPc())
```

Se guardi bene, il simulatore bara un po’. L’istruzione viene letta dall’array già alla prima riga, prima che si accenda una sola luce. Tutto il resto è teatro per gli studenti. Per uno strumento didattico è il compromesso giusto: i cambi di stato sono semplici reducer, e lo sforzo va tutto nel rendere ogni passo visibile e abbastanza lento da poterlo seguire.

## Com’è fatto

La storia completa è in git: 114 commit tra il 22 maggio e il 28 luglio 2020, fino alla versione 1.0.0. È un progetto Create React App in TypeScript, con Redux Toolkit per lo stato della CPU, Tailwind per il layout e l’editor Monaco (quello dentro VS Code) con evidenziazione della sintassi e autocompletamento per le istruzioni. Lo schema della CPU è un grande SVG inline i cui colori e valori arrivano dritti dallo stato Redux, e buona parte della storia è fatta di commit come “Align address bus label” e “Draw lines between ALU and registers”. Negli ultimi commit ho aggiunto Electron e la build di un installer per Windows, così da poterlo usare anche come app desktop.

## Perché ci ripenso ancora

Oggi passo le mie giornate su sistemi real-time e agenti AI, molto lontano da R0 e R1. Eppure dover rendere visibile ogni passo del ciclo fetch–decode–execute è stato un ottimo esercizio, e l’abitudine di chiedermi cosa succede davvero sotto è rimasta utile. Quando una query Postgres è lenta, spesso la risposta sta in come le righe vengono lette dal disco. Quando un modello è lento da servire, spesso sta in come si muove la memoria sulla GPU. Le astrazioni sono fantastiche, fino al momento in cui hai bisogno di guardarci attraverso.

Se ti incuriosisce quello su cui ho lavorato da allora, trovi di più [su di me qui](https://fedme.dev/it/about). E se insegni informatica e vuoi giocare con CPUSim, il codice è [su GitHub](https://github.com/fedme/cpusim).
