Implementazioni di costrutti ad alto livello in Assembly RISC-V

Istruzioni RISC-V

Com’è fatta un’istruzione?

Ogni istruzione ha una lunghezza totale fissa di 32 bit, e in linea di massima (ma ci sono diversi formati delle istruzioni) ha come campi:

  • OpCode (7 bit)(operation code): l‘“etichetta” che codifica il tipo di operazione da eseguire,
  • funct3 (3 bit): una parte aggiuntiva dell’OpCode nel caso esso non sia sufficiente a specificare l’operazione, non è adiacente all’OpCode,
  • funct7 (7 bit): un’altra parte aggiuntiva dell’OpCode, non è adiacente all’OpCode,
  • rs1 (5 bit): (first register source): l’indirizzo del registro in cui è memorizzato il primo argomento dell’istruzione,
  • rs2 (5 bit): (second register source): l’indirizzo del registro in cui è memorizzato il secondo argomento dell’istruzione,
  • rd (5 bit): (register destination): l’indirizzo del registro in cui va scritto il risultato dell’operazione.

Formati delle istruzioni

Non tutte le istruzioni necessitano degli stessi campi, quindi si usano diversi formati per diverse categorie di istruzioni.

Pseudoistruzioni

Sono istruzioni non implementate in hardware, ma che possono essere tradotte in istruzioni macchina, un modo compatto ed intuitivo per specificare un insieme di istruzioni o istruzioni ricorrenti.

La traduzione in linguaggio macchina è effettuata dall’assemblatore.

mv x10, x11 → addi x10, x11, 0
li, x9, 123. → addi x9, x0, 123

Modi di indirizzamento delle istruzioni

I modi di indirizzamento sono le tecniche utilizzate dai processori per determinare il dato da utilizzare (contenuto in memoria o in un registro o immediato), dato un indirizzo e spesso anche un’offset (spiazzamento).

Etichette (label)

Gli indirizzi di salto sono noiosi da calcolare e possono indurre in facili errori, quindi esistono le etichette per semplificare il lavoro ai programmatori:

L’etichetta associa alla parola l’indirizzo dell’istruzione dove è scritta, potrà essere usata nel codice assembly al posto dell’indirizzo della memoria (RAM) che rappresenta (cioè alla riga del programma in esecuzione), come se fosse una costante numerica nei linguaggi ad alto livello.

  • L’assemblatore converte le etichette in salti o in indirizzi
  • Le pseudoistruzioni possono usare come argomenti le etichette

Esempio: etichetta per una funzione

sum:                # Etichetta "sum"
    add a0, a0, a1  # Somma a0 + a1 e salva in a0
    ret             # Ritorna (usa ra per tornare)

Esempio: etichetta per un ciclo

loop:           
    addi t0, t0, 1  # Incrementa t0 di 1
    blt t0, t1, loop # Se t0 < t1, salta a "loop"

Esempio: etichetta per dati in memoria

.data
message: .asciz "Hello, RISC-V!\n"

.text
    la a0, message  # Carica l'indirizzo base di "message" in a0

Direttive per l’assemblatore

Indicano lo scopo delle varie sezioni del programma (quindi della parte della RAM che contiene le istruzioni del programma da eseguire).

nomesezione
.datadefinizione dei dati statici
.textdefinizione del programma
.asciizstringa terminata da \0
.bytesequenza di byte
.doublesequenza di double
.floatsequenza di float
.halfsequenza di half words
.wordsequenza di words

System Calls

Sono delle richieste che il programma in esecuzione fa al sistema operativo.

Si preparano:

  • mettendo nel registro a7 il numero che identifica la chiamata
  • Gli eventuali argomenti da mettere in a0 e a1.

Si eseguono con l’istruzione senza argomenti ecall: l’eventuale risultato andrà in a0.

Alcune SysCalls importanti

Syscall (a7)DescrizioneArgomenti (a0…)Risultato
1Stampa interoIntero in a0-
5Leggi intero-in a0
4Stampa stringaIndirizzo base della stringa in a0-
8Leggi stringaindirizzo buffer in a0
e numero di caratteri in a1
in a0
11Stampa carattereCarattere in a0-
12Leggi carattere-in a0
10exit con code 0--