Assembly
Introduzione
Nei computer, le CPU possono basarsi su diverse architetture, ognuna con il proprio modo di interpretare e gestire le istruzioni. Le architetture più comuni includono CISC (Complex Instruction Set Computing), che utilizza un ampio set di istruzioni complesse, e RISC (Reduced Instruction Set Computing), che privilegia un set di istruzioni più semplice e standardizzato per ottimizzare la velocità di esecuzione. In questa sezione, esploreremo un’architettura semplice come quella RISC, che permette di comprendere chiaramente come funzionano le istruzioni e i registri.
I registri della CPU
In un’architettura semplice, il processore dispone solitamente di 32 registri generali di grandezza 32 bit (4 byte), utilizzati per contenere temporaneamente dati durante l’esecuzione delle operazioni. I registri sono piccole unità di memoria interne alla CPU, estremamente veloci, che permettono di caricare, memorizzare e manipolare rapidamente i dati necessari.
Alcuni registri hanno funzioni specifiche; uno dei più importanti è il Program Counter (PC), che contiene l’indirizzo della prossima istruzione da eseguire. Il PC permette alla CPU di mantenere la posizione corrente nel programma e avanzare alla prossima istruzione a ogni ciclo di fetch-decode-execute.
Struttura delle istruzioni
In un’architettura di tipo RISC, ogni istruzione è composta da 32 bit suddivisi in campi specifici, ognuno con un ruolo preciso. La suddivisione tipica dei 32 bit è:
- 6 bit per l’opcode: identifica l’operazione da eseguire (ad esempio, somma, carica, confronto).
- 5 bit per il registro di destinazione: specifica dove salvare il risultato.
- 5 bit per il primo registro sorgente: indica uno dei registri da cui prendere i dati.
- 5 bit per il secondo registro sorgente o registro base: indica un secondo registro per operazioni aritmetiche o logiche oppure il registro base per accesso alla memoria.
- 11 bit rimanenti: utilizzati per valori immediati o offset, necessari in operazioni come salti condizionati o accesso alla memoria.
Esempio di istruzioni e suddivisione dei bit
Vediamo ora alcuni esempi di istruzioni e come sono strutturati i loro 32 bit. Ogni esempio include una tabella che mostra la suddivisione dei bit.
1. Esempio: ADD R1, R2, R3
Questa istruzione somma i valori contenuti nei registri R2 e R3 e salva il risultato nel registro R1. La struttura dei bit è la seguente:
| Campo | Bit | Descrizione |
|---|---|---|
| Opcode | 6 bit | Codice dell’operazione (ADD) |
| Destinazione | 5 bit | Registro di destinazione (R1) |
| Registro Sorgente 1 | 5 bit | Primo registro sorgente (R2) |
| Registro Sorgente 2 | 5 bit | Secondo registro sorgente (R3) |
| Non utilizzati | 11 bit | Non utilizzati per questa istruzione |
Rappresentazione in binario (esempio):
- Opcode (ADD):
000001 - R1:
00001 - R2:
00010 - R3:
00011 - Non utilizzati:
00000000000
Totale: 000001 00001 00010 00011 00000000000
2. Esempio: LOAD R1, 16(R2)
Questa istruzione, LOAD R1, 16(R2), esegue un’operazione di caricamento (o load) di un valore dalla memoria RAM al registro R1. Vediamo in dettaglio come funziona e perché un’operazione di questo tipo è importante.
In molti programmi, i dati che il processore deve elaborare sono troppo numerosi per essere memorizzati interamente nei registri, che sono pochi e di dimensione limitata. Per questo motivo, i dati sono spesso conservati nella memoria di lavoro (RAM), una memoria più grande ma più lenta rispetto ai registri. Tuttavia, per elaborare questi dati, la CPU deve caricarli nei registri, ed è qui che entra in gioco un’istruzione come LOAD.
Cosa fa l’istruzione LOAD R1, 16(R2)?
L’istruzione LOAD R1, 16(R2) specifica alla CPU di:
-
Calcolare un indirizzo di memoria sommando l’offset 16 al valore contenuto nel registro R2. In questo contesto, il registro R2 è usato come registro base, il che significa che contiene un indirizzo di memoria di riferimento. L’offset 16 indica una posizione di memoria relativa a questo indirizzo base.
-
Accedere alla memoria all’indirizzo calcolato e leggere il valore presente in quella posizione.
-
Copiare il valore letto dalla memoria nel registro R1, che fungerà da spazio di lavoro temporaneo in cui la CPU può manipolare i dati.
| Campo | Bit | Descrizione |
|---|---|---|
| Opcode | 6 bit | Codice dell’operazione (LOAD) |
| Destinazione | 5 bit | Registro di destinazione (R1) |
| Registro Base | 5 bit | Registro base per l’indirizzo (R2) |
| Offset | 16 bit | Valore immediato o offset (16) |
Rappresentazione in binario (esempio):
- Opcode (LOAD):
000010 - R1:
00001 - R2:
00010 - Offset (16):
0000000000010000
Totale: 000010 00001 00010 0000000000010000
3. Esempio: BEQ R1, R2, 8
Questa è un’istruzione di salto condizionale. La CPU verifica se i valori di R1 e R2 sono uguali. Se lo sono, la CPU salta a un’istruzione situata a 8 posizioni di distanza. Questo significa che se i due valori sono uguali l’esito dell’operazione sarà l’incremento del Program Counter di 8 unità. La struttura dei bit è:
| Campo | Bit | Descrizione |
|---|---|---|
| Opcode | 6 bit | Codice dell’operazione (BEQ) |
| Registro 1 | 5 bit | Primo registro per confronto (R1) |
| Registro 2 | 5 bit | Secondo registro per confronto (R2) |
| Offset | 16 bit | Offset per il salto (8) |
Rappresentazione in binario (esempio):
- Opcode (BEQ):
000011 - R1:
00001 - R2:
00010 - Offset (8):
0000000000001000
Totale: 000011 00001 00010 0000000000001000
Riassunto tabellare delle istruzioni di esempio
| Istruzione | Opcode | Destinazione | Sorgente 1 | Sorgente 2 / Base | Offset/Immediato |
|---|---|---|---|---|---|
| ADD R1, R2, R3 | 000001 | 00001 | 00010 | 00011 | 00000000000 (11 bit) |
| LOAD R1, 16(R2) | 000010 | 00001 | 00010 | - | 0000000000010000 |
| BEQ R1, R2, 8 | 000011 | 00001 | 00010 | - | 0000000000001000 |
Conclusione
In un’architettura di tipo RISC, ogni istruzione occupa sempre 32 bit e segue una struttura regolare e uniforme. Questo design rende più veloce e prevedibile la decodifica delle istruzioni, consentendo alla CPU di eseguire un numero elevato di operazioni per secondo.