Questo sito utilizza cookie per raccogliere dati statistici.
Privacy Policy
# 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:
1. **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.
2. **Accedere alla memoria all’indirizzo calcolato** e leggere il valore presente in quella posizione.
3. **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.