mirror of
https://github.com/Steffo99/unisteffo.git
synced 2024-11-21 23:44:22 +00:00
Complete Architettura dei Calcolatori
This commit is contained in:
parent
184885e3d8
commit
182eaceea0
17 changed files with 775 additions and 9 deletions
11
components/warnings.tsx
Normal file
11
components/warnings.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Panel } from "@steffo/bluelib-react"
|
||||
|
||||
export const Warning = (props) => {
|
||||
return (
|
||||
<Panel builtinColor="yellow">
|
||||
|
||||
<B>Attenzione:</B> questi file non sono stati ricontrollati da quando sono stati scritti, e potrebbero contenere errori!<br/>
|
||||
<small>Usali a tuo rischio e pericolo!</small>
|
||||
</Panel>
|
||||
)
|
||||
}
|
22
pages/_base.tsx
Normal file
22
pages/_base.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { Heading, Chapter, Box, Idiomatic as I, Anchor as A, ListUnordered, ListOrdered } from '@steffo/bluelib-react'
|
||||
import type { NextPage } from 'next'
|
||||
|
||||
const Page: NextPage = () => {
|
||||
return <>
|
||||
<Heading level={2}>
|
||||
Titolo
|
||||
</Heading>
|
||||
<Chapter>
|
||||
<Box>
|
||||
<Heading level={3}>
|
||||
Introduzione
|
||||
</Heading>
|
||||
<p>
|
||||
Cose
|
||||
</p>
|
||||
</Box>
|
||||
</Chapter>
|
||||
</>
|
||||
}
|
||||
|
||||
export default Page
|
|
@ -45,7 +45,7 @@ const Home: NextPage = () => {
|
|||
<ListUnordered>
|
||||
<ListUnordered.Item>
|
||||
<Link href="/year1/architettura">
|
||||
<A>Architettura dei calcolatori</A>
|
||||
<A href="#">Architettura dei calcolatori</A>
|
||||
</Link>
|
||||
</ListUnordered.Item>
|
||||
<ListUnordered.Item>
|
||||
|
@ -53,6 +53,11 @@ const Home: NextPage = () => {
|
|||
<A>Algoritmi e strutture dati</A>
|
||||
</Link>
|
||||
</ListUnordered.Item>
|
||||
<ListUnordered.Item>
|
||||
<Link href="/year1/programmazione2">
|
||||
<A>Programmazione 2</A>
|
||||
</Link>
|
||||
</ListUnordered.Item>
|
||||
</ListUnordered>
|
||||
</Box>
|
||||
<Box>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Heading, Chapter, Box, Idiomatic as I, Code, Anchor as A, Dialog, BringAttention as B, ListOrdered, ListUnordered} from '@steffo/bluelib-react'
|
||||
import type { NextPage } from 'next'
|
||||
|
||||
const Algebra: NextPage = () => {
|
||||
const Page: NextPage = () => {
|
||||
return <>
|
||||
<Heading level={2}>
|
||||
Analisi matematica
|
||||
|
@ -130,12 +130,10 @@ const Algebra: NextPage = () => {
|
|||
</ListUnordered.Item>
|
||||
</ListUnordered>
|
||||
<Dialog builtinColor='yellow'>
|
||||
<B>Attenzione:</B> questi file non sono stati ricontrollati da quando sono stati scritti, e potrebbero contenere errori!<br/>
|
||||
<small>Usali a tuo rischio e pericolo!</small>
|
||||
</Dialog>
|
||||
</Box>
|
||||
</Chapter>
|
||||
</>
|
||||
}
|
||||
|
||||
export default Algebra
|
||||
export default Page
|
||||
|
|
|
@ -7,7 +7,7 @@ const MaterialLi = ({children, file}) => {
|
|||
</ListOrdered.Item>
|
||||
}
|
||||
|
||||
const Analisi: NextPage = () => {
|
||||
const Page: NextPage = () => {
|
||||
return <>
|
||||
<Heading level={2}>
|
||||
Analisi matematica
|
||||
|
@ -103,4 +103,4 @@ const Analisi: NextPage = () => {
|
|||
</>
|
||||
}
|
||||
|
||||
export default Analisi
|
||||
export default Page
|
||||
|
|
100
pages/year1/architettura.tsx
Normal file
100
pages/year1/architettura.tsx
Normal file
|
@ -0,0 +1,100 @@
|
|||
import { Heading, Chapter, Box, Idiomatic as I, Anchor as A, UAnnotation as U, ListUnordered, BringAttention as B, ListOrdered, Definition, Code } from '@steffo/bluelib-react'
|
||||
import type { NextPage } from 'next'
|
||||
import Head from 'next/head'
|
||||
|
||||
|
||||
const MaterialLi = ({children, file}) => {
|
||||
return <ListOrdered.Item>
|
||||
{children} (<A href={`/materials/year1/architettura/${file}.md`}><Code>.md</Code></A>)
|
||||
</ListOrdered.Item>
|
||||
}
|
||||
|
||||
|
||||
const Page: NextPage = () => {
|
||||
return <>
|
||||
<Heading level={2}>
|
||||
Architettura dei calcolatori
|
||||
</Heading>
|
||||
<Chapter>
|
||||
<Box>
|
||||
<Heading level={3}>
|
||||
Introduzione
|
||||
</Heading>
|
||||
<p>
|
||||
Quando ho dato <I>Architettura dei Calcolatori</I>, a malapena si sentiva parlare di RISC-V, e non aveva <A href="https://trends.google.com/trends/explore?date=all&q=risc-v">tutta la popolarità che ha ora</A>.
|
||||
</p>
|
||||
<p>
|
||||
Penso si trovino risorse molto più utili per studiare il RISC-V adesso rispetto al passato!
|
||||
</p>
|
||||
</Box>
|
||||
</Chapter>
|
||||
<Chapter>
|
||||
<Box>
|
||||
<Heading level={3}>
|
||||
Materiale realizzato
|
||||
</Heading>
|
||||
<p>
|
||||
Ho glissato molto sulla parte teorica, in quanto le dispense forniteci dal prof. erano ottime.
|
||||
</p>
|
||||
<ListOrdered>
|
||||
<MaterialLi file="1_principi">
|
||||
Principi dell'architettura dei calcolatori
|
||||
</MaterialLi>
|
||||
<MaterialLi file="2_dentro_il_processore">
|
||||
Dentro il processore
|
||||
</MaterialLi>
|
||||
<MaterialLi file="3_assembly">
|
||||
Assembly
|
||||
</MaterialLi>
|
||||
</ListOrdered>
|
||||
<p>
|
||||
Quando ho studiato per questo esame non si trovava quasi nulla di RISC-V su Internet o libri di testo.
|
||||
</p>
|
||||
<p>
|
||||
Questo è quello che ero riuscito a capire dopo vari tentativi e approfondite ricerche.
|
||||
</p>
|
||||
<ListOrdered start="4">
|
||||
<MaterialLi file="4_hello_world">
|
||||
Hello World in RISC-V
|
||||
</MaterialLi>
|
||||
<MaterialLi file="5_primo_programma">
|
||||
Primo programma RISC-V
|
||||
</MaterialLi>
|
||||
<MaterialLi file="6_stack">
|
||||
Stack in RISC-V
|
||||
</MaterialLi>
|
||||
<MaterialLi file="7_prodotto_scalare">
|
||||
Prodotto scalare in RISC-V
|
||||
</MaterialLi>
|
||||
</ListOrdered>
|
||||
<p>
|
||||
Infine, un altro po' di appunti e teoria relativi all'ultima parte del corso.
|
||||
</p>
|
||||
<ListOrdered start="8">
|
||||
<MaterialLi file="8_appunti_e_deduzioni">
|
||||
Appunti e deduzioni
|
||||
</MaterialLi>
|
||||
<MaterialLi file="9_memorie">
|
||||
Memorie
|
||||
</MaterialLi>
|
||||
<MaterialLi file="10_meltdown">
|
||||
Meltdown
|
||||
</MaterialLi>
|
||||
</ListOrdered>
|
||||
</Box>
|
||||
<Box>
|
||||
<Heading level={3}>
|
||||
Estensione per Visual Studio Code
|
||||
</Heading>
|
||||
<p>
|
||||
Durante il corso ho anche realizzato un'estensione per Visual Studio Code che fa <I>syntax highlighting</I> dell'Assembly RISC-V.
|
||||
</p>
|
||||
<p>
|
||||
È possibile scaricarla <A href="https://marketplace.visualstudio.com/items?itemName=steffo.riscv-plus">sul Visual Studio Marketplace</A>, e il suo codice sorgente è disponibile <A href="https://github.com/Steffo99/riscv-plus/">su GitHub</A>.
|
||||
</p>
|
||||
</Box>
|
||||
</Chapter>
|
||||
</>
|
||||
}
|
||||
|
||||
export default Page
|
|
@ -14,7 +14,7 @@ import imgFjYpT1n from "../../public/images/year1/programmazione1/FjYpT1n.png"
|
|||
import imgklZQ9So from "../../public/images/year1/programmazione1/klZQ9So.png"
|
||||
import imgF6lBCqS from "../../public/images/year1/programmazione1/F6lBCqS.png"
|
||||
|
||||
const Programmazione1: NextPage = () => {
|
||||
const Page: NextPage = () => {
|
||||
return <>
|
||||
<Heading level={2}>
|
||||
Programmazione 1
|
||||
|
@ -110,4 +110,4 @@ const Programmazione1: NextPage = () => {
|
|||
</>
|
||||
}
|
||||
|
||||
export default Programmazione1
|
||||
export default Page
|
||||
|
|
21
public/materials/year1/architettura/10_meltdown.md
Normal file
21
public/materials/year1/architettura/10_meltdown.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Meltdown
|
||||
|
||||
Esempio circa comprensibile:
|
||||
|
||||
```c++
|
||||
int meltdown() {
|
||||
bool array[2] = {false, true};
|
||||
|
||||
if( qualcosa_che_restituisce_false() ) {
|
||||
//Questo viene predetto
|
||||
//Durante le predizioni non ci sono segfault!
|
||||
int protetto = *(indirizzo_bersaglio);
|
||||
//Se il primo bit di protetto è 1, verrà caricato "true" in cache, altrimenti, verrà caricato "false", ANCHE SE E' SOLO UNA PREDIZIONE!
|
||||
//Dopo essere stato caricato, NON VIENE RIMOSSO, anche se la predizione è sbagliata.
|
||||
int caricato = array[protetto & 1];
|
||||
}
|
||||
|
||||
if( in_cache(true) ) cout << "Il primo bit del bersaglio è 1.\n";
|
||||
else cout << "Il primo bit del bersaglio è 0.\n";
|
||||
}
|
||||
```
|
47
public/materials/year1/architettura/1_principi.md
Normal file
47
public/materials/year1/architettura/1_principi.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# I principi dell'architettura dei calcolatori
|
||||
|
||||
## Gli otto grandi principi
|
||||
|
||||
- Progetta per la **Legge di Moore**
|
||||
- **Astrai** per semplificare il design
|
||||
- Velocizza i **casi più comuni**
|
||||
- Sfrutta il **parallelismo**
|
||||
- Instruction level parallelism
|
||||
- In una sola CPU vengono realizzati più calcoli in parallelo
|
||||
- Sfrutta le **pipeline**
|
||||
- Pipelining
|
||||
- Separare le azioni del processore in fasi
|
||||
- Il fetch è separato dal decoding, mentre decodifico un'istruzione posso già fetchare quell'altra
|
||||
- **Prevedi** le istruzioni successive
|
||||
- **Gerarchizza** le memorie per velocità di accesso
|
||||
- La CPU cerca sempre di accedere alle memorie più veloci
|
||||
- Rendi affidabile con la **ridondanza**
|
||||
|
||||
### Parallelismo
|
||||
|
||||
> Chiedo a 100 persone di fare una moltiplicazione ciascuna invece che fare 100 moltiplicazioni io da solo
|
||||
|
||||
### Pipelining
|
||||
|
||||
![Senza](https://upload.wikimedia.org/wikipedia/commons/2/2c/Nopipeline.png)
|
||||
|
||||
![Con](https://upload.wikimedia.org/wikipedia/commons/2/21/Fivestagespipeline.png)
|
||||
|
||||
### Gerarchia delle memorie
|
||||
|
||||
> Hit or miss? I hope they never miss.
|
||||
|
||||
La CPU prova sempre ad accedere alle memorie più in alto di questa lista, effettuando un **hit** se trova i dati che le servono in una data memoria ed effettuando un **miss** se invece non trova i dati necessari e deve accedere a uno strato inferiore.
|
||||
|
||||
- [Cache](https://it.wikipedia.org/wiki/Cache) (piccolissima e velocissima)
|
||||
- [Random Access Memory](https://it.wikipedia.org/wiki/RAM) (piccola e veloce)
|
||||
- [Solid State Drive]() (medio e di media velocità)
|
||||
- [Hard Disk Drive](https://it.wikipedia.org/wiki/Disco_rigido) (grosso, ma lento)
|
||||
- [Tape storage](https://en.wikipedia.org/wiki/Magnetic_tape_data_storage) (enorme, ma lentissimo)
|
||||
|
||||
I _miss_ rallentano l'esecuzione dei programmi, in quanto causano ritardi nel ritrovamento dei dati, passando da _meno di 1 µs_ per le cache a _più di 1 ms_ per gli hard disk.
|
||||
|
||||
Inoltre, esistono due tipi di cache, anch'essi gerarchizzati:
|
||||
|
||||
- [SRAM](https://it.wikipedia.org/wiki/SRAM)
|
||||
- [DRAM](https://it.wikipedia.org/wiki/DRAM)
|
|
@ -0,0 +1,41 @@
|
|||
# Dentro il processore
|
||||
|
||||
## Come sono fatti i circuiti integrati?
|
||||
|
||||
Sono composti da un layer di silicio (semiconduttore), più delle maschere di conduttori (µfili metallici), isolanti (plastica e vetro) e transistor.
|
||||
|
||||
### Processo di produzione
|
||||
|
||||
- Lingotto di silicio
|
||||
- Tagliato in _wafer_ da 2mm
|
||||
- Creazione dei _patterned wafer_
|
||||
- Testing dei _patterned wafer_
|
||||
- Taglio i _tested wafers_
|
||||
- Creo un package con i _tested dies_
|
||||
- Testo i _packaged dies_
|
||||
- Spedisco i _tested packaged dies_ ai clienti.
|
||||
|
||||
### Lo yield
|
||||
|
||||
Lo yield è quanti _tested packaged dies_ riesco a produrre da un singolo lingotto di silicio.
|
||||
|
||||
## Come definiamo la performance di un processore?
|
||||
|
||||
Ci sono varie metriche per definirla:
|
||||
|
||||
- **Response time**: tempo impiegato a compiere un'operazione
|
||||
- **Throughput**: operazioni fatte in un'unità di tempo
|
||||
|
||||
### Il clock
|
||||
|
||||
Il clock della CPU è il timer che scandisce le operazioni della CPU.
|
||||
|
||||
Ha, ovviamente, un periodo e una frequenza costanti.
|
||||
|
||||
### Il CPU time
|
||||
|
||||
Il tempo impiegato da una CPU a compiere una determinata operazione è dato da `numero di cicli di clock richiesti * periodo di clock`, ed è detto **CPU time**.
|
||||
|
||||
### Il Cost per instruction (CPI)
|
||||
|
||||
Alcune istruzioni di una CPU potrebbero richiedere più di un ciclo di clock.
|
165
public/materials/year1/architettura/3_assembly.md
Normal file
165
public/materials/year1/architettura/3_assembly.md
Normal file
|
@ -0,0 +1,165 @@
|
|||
# Assembly
|
||||
|
||||
Useremo il RISC-V.
|
||||
Esso è little-endian, ed è indirizzato a gruppi di 8 bit.
|
||||
|
||||
## Registri
|
||||
|
||||
RISC-V ha a disposizione **32** registri da 64 bit, che vanno da `x0` a `x31`.
|
||||
|
||||
Un dato a 32 bit viene chiamato **word**, uno a 64 bit viene chiamato **doubleword**.
|
||||
|
||||
- `x0`: costante
|
||||
- `x1`: indirizzo risultato
|
||||
- `x2`: indirizzo della cima dello stack
|
||||
- `x3`: indirizzo dell'area di memoria con variabili globali
|
||||
- `x4`: indirizzo dell'area di memoria specifica del thread attivo
|
||||
- `x5`: registro temporaneo
|
||||
- `x6`: registro temporaneo
|
||||
- `x7`: registro temporaneo
|
||||
- `x8`: frame pointer
|
||||
- `x9`: registro salvato, può essere copiato in memoria
|
||||
- `x10`: argomento o risultato delle funzioni
|
||||
- `x11`: argomento o risultato delle funzioni
|
||||
- `x12`: argomento delle funzioni
|
||||
- `x13`: argomento delle funzioni
|
||||
- `x14`: argomento delle funzioni
|
||||
- `x15`: argomento delle funzioni
|
||||
- `x16`: argomento delle funzioni
|
||||
- `x17`: argomento delle funzioni
|
||||
- `x18`: registro salvato, può essere copiato in memoria
|
||||
- `x19`: registro salvato, può essere copiato in memoria
|
||||
- `x20`: registro salvato, può essere copiato in memoria
|
||||
- `x21`: registro salvato, può essere copiato in memoria
|
||||
- `x22`: registro salvato, può essere copiato in memoria
|
||||
- `x23`: registro salvato, può essere copiato in memoria
|
||||
- `x24`: registro salvato, può essere copiato in memoria
|
||||
- `x25`: registro salvato, può essere copiato in memoria
|
||||
- `x26`: registro salvato, può essere copiato in memoria
|
||||
- `x27`: registro salvato, può essere copiato in memoria
|
||||
- `x28`: registro temporaneo
|
||||
- `x29`: registro temporaneo
|
||||
- `x30`: registro temporaneo
|
||||
- `x31`: registro temporaneo
|
||||
|
||||
## Operazioni
|
||||
|
||||
### Operazioni aritmetiche
|
||||
|
||||
Sono sempre formate da tre operandi: registro a cui il risultato verrà assegnato e gli argomenti dell'operazione.
|
||||
|
||||
- `add`: addizione
|
||||
- `sub`: sottrazione
|
||||
- `addi`: addizione di costanti
|
||||
|
||||
#### Esempio
|
||||
|
||||
```assembly
|
||||
add a, b, c
|
||||
```
|
||||
|
||||
##### Equivalente Python
|
||||
|
||||
```python
|
||||
a = b + c
|
||||
```
|
||||
|
||||
### Operazioni di trasferimento dati
|
||||
|
||||
Permettono di caricre / scaricare dati dalla memoria.
|
||||
|
||||
### Operazioni logiche
|
||||
|
||||
Consentono di effettuare operazioni di logica.
|
||||
|
||||
- `and`
|
||||
- `or`
|
||||
- ...
|
||||
|
||||
### Operazioni di shift
|
||||
|
||||
Consentono di spostare i bit di un registro di alcune posizioni, moltiplicando o dividendo effettivamente per potenze di 2.
|
||||
|
||||
### Operazioni condizionali
|
||||
|
||||
Consentono di saltare ad un'altra serie di istruzioni se certe condizioni si verificano.
|
||||
|
||||
- `blt`: minore di, signed
|
||||
- `bge`: maggiore di, signed
|
||||
- `bltu`: minore di, unsigned
|
||||
- `bgeu`: maggiore di, unsigned
|
||||
|
||||
### Operazioni non-condizionali
|
||||
|
||||
Consentono di saltare ad un'altra serie di istruzioni in qualunque caso.
|
||||
|
||||
#### Chiamare una procedura
|
||||
|
||||
> `jal x1, ProcedureLabel`
|
||||
|
||||
Salva l'indirizzo dell'istruzione successiva in x1, poi salta a ProcedureLabel.
|
||||
|
||||
#### Ritornare da una procedura
|
||||
|
||||
> `jalr x0, 0(x1)`
|
||||
|
||||
Ritorna all'indirizzo puntato da `x1`.
|
||||
|
||||
## Memoria
|
||||
|
||||
Per accedere a una posizione in memoria, si usa `offset(indirizzo)`.
|
||||
|
||||
##### Esempio
|
||||
|
||||
`64(x22)` accede al 64° byte dopo la posizione di memoria archiviata in `x22`.
|
||||
|
||||
## Segni
|
||||
|
||||
E' possibile usare rappresentazione standard o a complemento-a-2.
|
||||
|
||||
Possiamo usare la **sign extension** quando abbiamo un dato che vogliamo portare a un numero di bit maggiore di quello che è.
|
||||
|
||||
##### Esempio
|
||||
|
||||
```
|
||||
[0]101 0101 --> 0000 0000 [0]101 0101
|
||||
[1]100 0000 --> 1111 1111 [1]100 0000
|
||||
```
|
||||
|
||||
### Operazioni di sincronizzazione
|
||||
|
||||
- `lr`: load reserved
|
||||
- `sc`: store conditional
|
||||
|
||||
#### Load reserved
|
||||
|
||||
```
|
||||
lr rd, (rs1)
|
||||
```
|
||||
|
||||
> Non ho la minima idea di come funzioni.
|
||||
|
||||
Controlla se `rs1` è bloccato; se sì, mette un valore != 0 in `rd`...?
|
||||
|
||||
> Forse... crea un lock in `rd`?
|
||||
|
||||
#### Store conditional
|
||||
|
||||
```
|
||||
sc rd, rs2, (rs1)
|
||||
```
|
||||
|
||||
> Non ho la minima idea di come funzioni.
|
||||
|
||||
Copia il dato da `rs2` a `rs1`, se non è bloccato, e metti `x0` in `rd`...?
|
||||
|
||||
> Carica un dato... se ho ancora il lock, altrimenti, metti `x0` in `rd`.
|
||||
|
||||
#### Unlock
|
||||
|
||||
```
|
||||
sd x0, 0(x20)
|
||||
```
|
||||
|
||||
## Operazioni floating point
|
||||
|
33
public/materials/year1/architettura/4_hello_world.md
Normal file
33
public/materials/year1/architettura/4_hello_world.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Hello world in RISC-V
|
||||
|
||||
```riscv
|
||||
# Definisci delle costanti
|
||||
.equ _SYS_EXIT, 93 # Syscall exit
|
||||
.equ _SYS_WRITE, 64 # Syscall write
|
||||
|
||||
# Inizio del programma
|
||||
.global _start
|
||||
|
||||
# Variabili statichie inizializzate a 0
|
||||
.section .bss
|
||||
|
||||
# Dati modificabili
|
||||
.section .data
|
||||
|
||||
# Dati in sola lettura
|
||||
.section .rodata
|
||||
msg: .string "Hello mondo!\n"
|
||||
|
||||
# Testo del programma
|
||||
.section .text
|
||||
_start:
|
||||
# Chiamata a WRITE(stream, primocarattere, lunghezza)
|
||||
li a0, 0 # Print to stdout
|
||||
la a1, msg # Stampa il messaggio in msg
|
||||
li a2, 13 # Stampa 13 caratteri dopo msg
|
||||
li a7, _SYS_WRITE # Seleziona la syscall WRITE
|
||||
ecall
|
||||
|
||||
li a7, _SYS_EXIT
|
||||
ecall
|
||||
```
|
37
public/materials/year1/architettura/5_primo_programma.md
Normal file
37
public/materials/year1/architettura/5_primo_programma.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Primo programma in RISC-V
|
||||
|
||||
```riscv
|
||||
# Che bello! Adoro l'assembly!
|
||||
# Questo programma funziona, è verificato!
|
||||
.global _start
|
||||
|
||||
# La sezione .data contiene i dati del programma
|
||||
.section .data
|
||||
|
||||
# Creo una variabile con etichetta "ciao"
|
||||
ciao: .string "0\n\0"
|
||||
|
||||
# La sezione .rodata contiene i dati del programma in sola lettura
|
||||
.section .rodata
|
||||
|
||||
# La sezione .text contiene il testo del programma
|
||||
.section .text
|
||||
|
||||
# Creo una label _start che funzionerà da entrypoint
|
||||
_start:
|
||||
li t1, 10 # Voglio ripetere il ciclo 10 volte
|
||||
li a7, 64 # PRINT(stream, indirizzo, numerobytes) è la syscall 64
|
||||
li a0, 0 # stream è il primo argomento: vogliamo scrivere su stdout (0)
|
||||
la a1, ciao # indirizzo è il secondo argomento: partiamo dall'etichetta ciao
|
||||
li a2, 2 # numerobytes è il terzo argomento: vogliamo stampare 2 bytes
|
||||
print:
|
||||
ecall # PRINT(a0, a1, a2)
|
||||
lbu t0, 0(a1) # Carica il byte con il 0
|
||||
addi t0, t0, 1 # Aggiungici 1
|
||||
sb t0, 0(a1) # Ricaricalo in memoria
|
||||
addi t1, t1, -1 # Togli 1 dal numero di cicli rimasti
|
||||
bne t1, zero, print # Se rimangono dei cicli, torna indietro e falli!
|
||||
end:
|
||||
li a7, 93 # Tutti i programmi terminano chiamando la syscall 93, EXIT()
|
||||
ecall # EXIT()
|
||||
```
|
44
public/materials/year1/architettura/6_stack.md
Normal file
44
public/materials/year1/architettura/6_stack.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Stack in RISC-V
|
||||
|
||||
```riscv
|
||||
# Che bello! Adoro l'assembly!
|
||||
# Funziona!
|
||||
.global _start
|
||||
|
||||
# La sezione .data contiene i dati del programma
|
||||
.section .data
|
||||
|
||||
# La sezione .rodata contiene i dati del programma in sola lettura
|
||||
.section .rodata
|
||||
|
||||
# La sezione .text contiene il testo del programma
|
||||
.section .text
|
||||
|
||||
# Creo una label _start che funzionerà da entrypoint
|
||||
_start:
|
||||
li s0, 5 # Scrivi il numero 5
|
||||
li s3, 3 # COSTANTE: 3
|
||||
|
||||
# Pushing phase
|
||||
pushing:
|
||||
sb s0, 0(sp) # Metti nello stack s0
|
||||
addi sp, sp, 1 # Aumenta di 1 lo stack pointer
|
||||
addi s2, s2, 1 # Aumenta di 1 la dimensione dello stack
|
||||
addi s0, s0, -1 # Diminuisci di 1 il numero da fattorializzare
|
||||
bgeu s0, s3, pushing # Continua a pushare finchè non arrivi a 2
|
||||
li s1, 2
|
||||
|
||||
# Popping phase
|
||||
popping:
|
||||
addi sp, sp, -1 # Diminuisci di 1 lo stack pointer
|
||||
# Attenzione: diminuisco lo stack pointer PRIMA di caricare dallo stack, altrimenti caricarei il nulla
|
||||
lb s0, 0(sp) # Prendi dallo stack il prossimo numero
|
||||
addi s2, s2, -1 # Diminuisci di 1 la dimensione dello stack
|
||||
mul s1, s1, s0 # Effettua la moltiplicazione
|
||||
bne s2, zero, popping # Se ci sono altri valori nello stack, continua a moltiplicare
|
||||
|
||||
# Ending phase
|
||||
ending:
|
||||
li a7, 93
|
||||
ecall
|
||||
```
|
52
public/materials/year1/architettura/7_prodotto_scalare.md
Normal file
52
public/materials/year1/architettura/7_prodotto_scalare.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Prodotto scalare in RISC-V
|
||||
|
||||
```riscv
|
||||
# Che bello! Adoro l'assembly!
|
||||
# Ommioddiofunzionawowimawizard
|
||||
.global _start
|
||||
|
||||
# La sezione .data contiene i dati del programma
|
||||
.section .data
|
||||
|
||||
primo: .word 1, 2, 3, 4, 5
|
||||
secondo: .word 1, 2, 3, 4, 5
|
||||
|
||||
# La sezione .rodata contiene i dati del programma in sola lettura
|
||||
.section .rodata
|
||||
|
||||
# La sezione .text contiene il testo del programma
|
||||
.section .text
|
||||
|
||||
# s0: primo[s0]
|
||||
# s1: secondo[s0]
|
||||
# s2: monomio
|
||||
# s3: indirizzo da cui prendere il valore
|
||||
# s4: indice
|
||||
# s5: dimensione array
|
||||
# a0: somma
|
||||
|
||||
_start:
|
||||
li s2, 0
|
||||
li a0, 0
|
||||
li s4, 0
|
||||
li s5, 5
|
||||
|
||||
somma:
|
||||
la s3, primo
|
||||
add s3, s3, s4
|
||||
lw s0, 0(s3)
|
||||
|
||||
la s3, secondo
|
||||
add s3, s3, s4
|
||||
lw s1, 0(s3)
|
||||
|
||||
mulw s2, s1, s0
|
||||
add a0, a0, s2
|
||||
addi s4, s4, 4
|
||||
addi s5, s5, -1
|
||||
bne zero, s5, somma
|
||||
|
||||
_end:
|
||||
li a7, 93
|
||||
ecall
|
||||
```
|
57
public/materials/year1/architettura/8_appunti_e_deduzioni.md
Normal file
57
public/materials/year1/architettura/8_appunti_e_deduzioni.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Appunti
|
||||
|
||||
## Registri
|
||||
|
||||
I registri sono divisi in tre tipi: di **proprietà del chiamante**, di **proprietà del chiamato** (anche se in realtà è solo una convenzione) e... gli **altri**.
|
||||
|
||||
Tutti i registri sono grandi 64 bit: possono quindi contenere una _doubleword_.
|
||||
|
||||
### Proprietà del chiamante
|
||||
|
||||
Questi registri **non devono essere sovrascritti** quando viene chiamata una funzione, o se vengono sovrascritti, **devono essere ripristinati** prima che la funzione restituisca.
|
||||
|
||||
Essi sono:
|
||||
- `s1..s11`: **Saved** registers, registri generici che possono essere usati per qualsiasi cosa.
|
||||
- `sp`: **Stack Pointer**, il primo indirizzo dello stack disponibile per la scrittura. Va _decrementato_ quando si aggiunge qualcosa allo stack.
|
||||
- `fp`: **Frame Pointer**, punta all'inizio dello stack.
|
||||
|
||||
### Proprietà del chiamato
|
||||
|
||||
Questi registri **possono essere sovrascritti** quando viene chiamata una funzione: bisogna salvarli in memoria prima di chiamarla!
|
||||
|
||||
Essi sono:
|
||||
- `t0..t6`: **Temporary** registers, registri generici che possono essere usati per qualsiasi cosa.
|
||||
- `ra`: **Return Address**, l'indirizzo a cui continuare l'esecuzione del programma dopo aver terminato una funzione. _Solitamente si usa solo con `jal` e `jalr`!_
|
||||
- `a0..a7`: Function **Arguments**. Se all'interno di una funzione, contengono gli argomenti che sono stati passati. Se all'esterno di una funzione, contengono i valori restituiti dall'ultima funzione chiamata.
|
||||
|
||||
### Altri
|
||||
|
||||
- `zero`: **Zero**, registro che vale sempre 0, anche dopo essere stato sovrascritto da altro. Come `/dev/null` su Linux.
|
||||
- `gp`: **Global Pointer**, punta a un indirizzo _[(?)](https://groups.google.com/a/groups.riscv.org/forum/#!topic/sw-dev/60IdaZj27dY)_
|
||||
- `tp`: **Thread Pointer**, punta al thread-local storage _[(?)](https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/cov47bNy5gY/zLnlKkw9CQAJ)_
|
||||
- `pc`: **Program Counter**, punta all'istruzione che sta venendo eseguita.
|
||||
|
||||
## Comandi preprocessore
|
||||
|
||||
Scrivendo file assembly per RISC-V, è possibile aggiungere direttive per il preprocessore.
|
||||
|
||||
Per ora ho scoperto queste:
|
||||
|
||||
- `.global INDIRIZZO`: definisce l'indirizzo a cui inizia il programma. _(Forse setta il `gp` a quell'indirizzo?)_
|
||||
- `.equ NOME, VALORE`: definisce una costante con uno specifico nome. _Il nome delle costanti dovrebbe iniziare sempre con un underscore per convenzione._
|
||||
- `.section [.data|.rodata|.bss|.text]`: marca l'inizio di una specifica sezione del programma. Le sezioni sono:
|
||||
- `.data`: Variabili del programma
|
||||
- `.rodata`: Variabili sola lettura del programma
|
||||
- `[.bss](https://en.wikipedia.org/wiki/.bss)`: Variabili statiche non costanti non inizializzate a nessun valore. _A volte, vengono inizializzate a 0. Solo a volte. Dipende dall'OS._
|
||||
- `.text`: Il testo del programma, con le istruzioni in assembly.
|
||||
- `.TIPOVARIABILE`: crea una variabile di quel tipo e la inizializza a qualcosa.
|
||||
|
||||
# Link utili
|
||||
|
||||
- [algo.ing.unimo.it](http://algo.ing.unimo.it/people/andrea/Didattica/Architetture/index.html)
|
||||
- [wikichip.org](https://en.wikichip.org/wiki/risc-v)
|
||||
- [en.wikiversity.org](https://en.wikiversity.org/wiki/Computer_architecture)
|
||||
- [it.wikiversity.org](https://it.wikiversity.org/wiki/Materia:Architetture_degli_elaboratori)
|
||||
- [stackoverflow.com](https://stackoverflow.com/questions/tagged/riscv)
|
||||
- [softwareengineering.stackexchange.com](https://softwareengineering.stackexchange.com/questions/tagged/assembly)
|
||||
- [rv8.io](https://rv8.io/isa.html)
|
133
public/materials/year1/architettura/9_memorie.md
Normal file
133
public/materials/year1/architettura/9_memorie.md
Normal file
|
@ -0,0 +1,133 @@
|
|||
# Memorie
|
||||
|
||||
La _memoria_ di un calcolatore solitamente è composta da molteplici strati, realizzati per velocizzare gli accessi.
|
||||
|
||||
Ogni strato offre lettura più veloce, ma è più costoso da realizzare e ha consumi più alti.
|
||||
|
||||
In ordine di velocità, sono:
|
||||
|
||||
- Registers
|
||||
- Cache L1
|
||||
- Cache L2
|
||||
- Cache L`X`
|
||||
- Random Access Memory
|
||||
- Solid State Drive
|
||||
- Hard Disk Drive
|
||||
|
||||
## Cache
|
||||
|
||||
### Cache L1
|
||||
|
||||
Piccola, ma miss penalty bassa
|
||||
|
||||
### Cache L2
|
||||
|
||||
Molto grande, ma miss penalty alta
|
||||
|
||||
### Direct mapping
|
||||
|
||||
Una cache _direct mapped_ associa a ogni indirizzo di RAM un **indice** uguale agli **N bit meno significativi** dell'indirizzo dell'inferiore, e un **tag** uguale agli **N bit più significativi**.
|
||||
|
||||
Se durante un accesso _il tag di un blocco è diverso dal tag dell'indirizzo a cui vogliamo accedere_, si ha un cache miss.
|
||||
|
||||
> Il dato di cui abbiamo bisogno è contenuto nell'indirizzo `0x0ABC` della RAM.
|
||||
> Il suo indice sarà `0xBC`, e il suo tag sarà `0x0A`.
|
||||
> Essendo la cache vuota all'inizio, viene immediatamente caricato.
|
||||
>
|
||||
> Voglio poi accedere all'indirizzo `0x0BBC` della RAM.
|
||||
> Controlliamo il blocco con indice `0xBC`: il suo tag è `0x0A`, ma noi stiamo cercando `0x0B`! Si ha quindi un cache miss, e devo andare a prendere dalla memoria il dato che sto cercando e scriverlo sulla RAM.
|
||||
|
||||
Inoltre, in ogni blocco di memoria della cache è presente **un bit di validità**, che rappresenta se il dato in cache è stato inizializzato o no: parte da `0` e viene impostato a `1` quando viene caricato dalla RAM un dato nel relativo blocco.
|
||||
|
||||
> Un esempio potrebbe essere un processore con blocchi di memoria da 32 bit e indirizzi a 64 bit: la cache, contenente 1024 blocchi di memoria, avrà index a 12 bit, e di conseguenza il tag sarà grande 52 bit.
|
||||
|
||||
#### Dimensione blocchi
|
||||
|
||||
Fare blocchi grandi o fare blocchi piccoli ha significative differenze sulla velocità della cache:
|
||||
|
||||
Avere blocchi più grandi significa che ci saranno meno blocchi in tutta la cache, quindi:
|
||||
|
||||
```diff
|
||||
+ Riduce il miss rate per il principio di località spaziale
|
||||
- Avendo una quantità minore di blocchi, aumenta la possibilità di conflitto
|
||||
- La miss penalty è più alta
|
||||
# La miss penalty è compensabile con tecniche come early restart o critical-word-first
|
||||
```
|
||||
|
||||
Con blocchi più piccoli, invece
|
||||
```diff
|
||||
+ Miss penalty minore
|
||||
+ Più blocchi significa meno conflitti
|
||||
- E' possibile che abbia bisogno di fare più di una richiesta alla cache, rallentandola significativamente
|
||||
```
|
||||
|
||||
#### Scrittura tramite cache
|
||||
|
||||
Quando scrivo in memoria un dato presente nella cache, l'informazione presente nella cache diventa errata.
|
||||
|
||||
Si può risolvere questo problema con una politica di riscrittura:
|
||||
- Write-through
|
||||
- Write-back
|
||||
|
||||
##### Write-through
|
||||
|
||||
_Quando **viene scritto** su dato in cache_, aggiorna tutte le memorie che lo contengono.
|
||||
|
||||
```diff
|
||||
+ Non necessita di ulteriore memoria di cache
|
||||
+ Caricare dati è veloce
|
||||
+ Se si verifica un write miss non ha per forza bisogno di portare in cache il dato da scrivere
|
||||
- I write richiedono molto più tempo, soprattutto se ripetuti
|
||||
```
|
||||
|
||||
|
||||
##### Write-back
|
||||
|
||||
Scrivi la modifica di dato solo nella cache, e _marca il blocco come **dirty**_.
|
||||
|
||||
Quando un blocco dirty viene **sovrascritto**, aggiorna le memorie che lo contengono.
|
||||
|
||||
```diff
|
||||
+ I write richiedono poco tempo, anche se ripetuti
|
||||
- Caricare dati dalla RAM è più lento
|
||||
- Necessita di memoria da dedicare al dirty bit
|
||||
- Devo fetchare obbligatoriamente i dati da sovrascrivere
|
||||
```
|
||||
|
||||
##### Miglioramenti alle policy
|
||||
|
||||
E' possibile utilizzare un **write buffer** invece che fare attendere il tempo di scrittura alla CPU. I dati saranno scritti successivamente, ma prima che questi vengano utilizzati.
|
||||
|
||||
```diff
|
||||
+ Il processore non ha bisogno di fermarsi per le write
|
||||
- Il buffer potrebbe riempirsi, neganode i vantaggi
|
||||
- Il buffer utilizza memoria che forse sarebbe stata più utile come cache
|
||||
```
|
||||
|
||||
### Fully associative
|
||||
|
||||
Ogni dato può essere messo in qualunque indirizzo della cache.
|
||||
|
||||
Richiede che l'indirizzo di origine venga salvato assieme al dato, e tanti comparatori.
|
||||
|
||||
### Set associative
|
||||
|
||||
Divido tutti i blocchi di cache in vie.
|
||||
|
||||
Ogni via può contenere `n` dati.
|
||||
|
||||
Un set è l'insieme dei dati che hanno lo stesso index ma sono in vie diverse.
|
||||
|
||||
Ogni dato può essere messo in qualunque indirizzo del set a cui appartiene.
|
||||
|
||||
Identifico il numero di set di appartenenza facendo `indirizzo % numerodiset`.
|
||||
|
||||
Una cache `1`-way Set Associative è una cache Direct Mapped, mentre una cache `numeroentries`-way Set Associative è una cache Fully Associative.
|
||||
|
||||
Quando non c'è spazio in un set, rimpiazzo un dato secondo la politica **Least Recently Used**, rimuovendo il dato usato meno recentemente. Posso usare anche la politica **Random**, se ho un'alta associatività.
|
||||
|
||||
#### Performance
|
||||
|
||||
Più una cache è associativa, più il miss rate sarà ridotto, ma l'associatività richiede un maggior numero di comparatori e potenzialmente più ritardi nella restituzione del dato.
|
||||
|
||||
Inoltre, la percentuale di miss non diminuisce linearmente con il numero di vie: dopo un certo numero di vie, i guadagni sono molto ridotti.
|
Loading…
Reference in a new issue