Larc Computer e Linguaggio Macchina
"Larc" o "little architecture", è un modello di computer molto semplice con assieme l'ISA (Instruction Set Architecture), set di istruzioni per quel computer. Fu sviluppato una dozzina di anni fa da Marc Collins quando era professore al Hobart and William Smith Colleges. E' un primo esempio di ISA su cui lavoreremo.
Questo documento descrive il modello di computer Larc e il suo linguaggio macchina. Anche viene presentato un semplice assembler Larc che è solo una notazione alternativa per il linguaggio macchina. senza tutte le utili possibilità di un normale linguaggio assembler. Poi presenteremo un programma che è in grado di simulare un Larc computer.
Il computer Larc
La Larc CPU contiene 16 registri general-porpouse, in aggiunta al registro PC (Program Counter). Ogni registro contiene un numero binario di 16-bit. I registri generali sono numerati da 0 a 15, o da 0b0000
a 0b1111
in binario; quindi, il numero del registro è un numero binario di quattro bit. Il registro numero 0 ha la particolare proprietà che contiene il valore sempre di zero.
La memoria principale, o RAM, per Larc ha 65536, o , locazioni, e ogni locazione contiene un numero binario di 16 bit. La locazioni sono numerate da 0 a 65535, o da 0b0000000000000000
a 0b1111111111111111
in binario. Il numero della locazione è chiamato il suo indirizzo. Nota quindi che l'indirizzo di una locazione in memoria è un numero di 16 bit.
Un'istruzione del linguaggio macchina (machine languagge, ML) per Larc è un numero di 16 bit. La struttura del linguaggio macchina è discussa sotto. Ogni locazione della RAM può contenere una istruzione, ma i contenuti delle locazioni di memoria possono essere anche interpretati in altri modi, come ad esempio un intero che significa un dato per il programma. Il significato del numero dipende da come il numero è utilizzato.
Il funzionamento del computer è il ciclo fetch-and-execute di base. Il numero a 16 bit nel PC indica l'indirizzo della locazione di memoria che contiene la successiva istruzione in linguaggio macchina da eseguire. Il computer carica l'istruzione da quell'indirizzo, aggiunge uno al PC, e poi esegue l'istruzione. Ripete questo ciclo indefinitamente, finché uno è fermato in qualche modo. Alcune istruzioni modificano il PC quando sono eseguite; queste sono le istruzioni di "branch" o "jump".
Il linguaggio macchina di Larc
Una istruzione è un numero di 16 bit. I primi quattro bit dell'istruzione sono l'opcode (codice dell'operazione) the specificano il codice che corrisponde all'istruzione, e i rimanenti dodici bit contengono i dati dell'operazione. Ci sono diversi formati dei dati nell'istruzione, in base al opcode dell'istruzione.
Le seguenti tabelle descrivono le 16 tipi di istruzioni del linguaggio macchina. Reg[n] rappresenta il valore contenuto nel registro numero n. La funzione sext(x)
estende x a un numero a 16 bit conservando il segno. Il mnemonico per una istruzione è utilizzato nella notazione assembler per quella istruzione.
Istruzioni aritmetiche
I dodici bit dei dati in un'istruzione, contengono tre numeri di registri di 4 bit, che sono riferiti qua come ra, rb e rc.
0000
add
Reg[ra] = Reg[rb] + Reg[rc]
0001
sub
Reg[ra] = Reg[rb] - Reg[rc]
0010
mul
Reg[ra] = Reg[rb] * Reg[rc]
0011
div
Reg[ra] = Reg[rb] / Reg[rc], ma se Reg[rc] è zero, il computer si ferma per errore divisione per 0.
0100
sll
Reg[ra] = Reg[rb] << (Reg[rc] & 15); shift a sinistra (con riempimento di zeri)
0101
srl
Reg[ra] = Reg[rb] >>> (Reg[rc] & 15); shift a destra (con riempimento di zeri)
0110
nor
Reg[ra] = ~(Reg[rb] | Reg[rc]); operazione logica NOR bit a bit.
0111
slt
Reg[ra] = (Reg[rb] < Reg[rc]) ? 1 : 0;
Intruzioni immediate
I primi quattro bit, ra, rappresentano il numero di un registro. I successivi otto bit, indicati come limm, rappresentano un numero intero a 8 bit con segno. "limm" sta a significare "long immediate" e un "immediate" è un campo in un'istruzione che rappresenta una costante invece di un numero di registro.
1000
li
Reg[ra] = sext(limm); load immediate
1001
lui
Reg[ra] = limm << 8; load upper immediate
1010
beqz
if (Reg[ra] == 0) PC = PC + sext(limm); diramazione se uguale a zero
1011
bnez
if (Reg[ra] != 0) PC = PC + sext(limm); diramazione se diverso da zero
Istruzioni memoria
I bit dei dati sono due numeri di registri di 4 bit, ra e rb, e un numero con segno di 4 bit, simm. "simm" significa "short immediate".
1100
lw
Carica (load) il contenuto dalla locazione di memoria Reg[rb] + sext(simm) nel registro Reg[ra]
1101
sw
Salva (store) il valore di Reg[ra] nella locazione di memoria a indirizzo Reg[rb] + sext(simm)
Istruzioni salto (Jump)
Due campi da 4 bit, ra e rb; gli ultimi 4 bit sono ignorati.
1110
jalr
Jump-and-link-register: salva il valore di PC in Reg[ra] e setta il valore di PC con il valore di Reg[rb]
Istruzione di chiamate a sistema (Syscall)
Tutti i bit della parte dati sono ignorati.
1111
syscall
Chiamata di sistema numero Reg[1].
Per esempio, il numero a 16-bit 0b00010011001001111
rappresenta una operazione di sottrazione (codice 0001) applicata ai numeri di registro 3, 2 e 7 (numeri binari 0011
, 0010
e 0111
). Cioè, quando viene eseguita, i valori contenuti nei registri 2 e 7 sono aggiunti, e il risultato è copiato nel registro 3.
il numero 0b0000100011110000
significa aggiungere il valore del registro 15 e 0, e copiare il risultato nel registro 8. Poiché il valore nel registro 0 è sempre zero, questo ha l'effetto di copiare il valore dal registro 15 nel registro 8.
O consideriamo 0b1100000100100011
. Questo è il comando "load" con argomenti 1, 2 e 3. Prende il valore dal registro 2 e aggiunge il numero 3 a quel valore, e utilizza il risultato come indirizzo di una locazione di memoria. Il valore contenuto in quella locazione è copiato nel registro 1. (Il valore SIMM nell'istruzione sarà molte volte zero. Valori non zero sono delle volte utili quando vogliamo caricare una sequenza di valori da locazioni di memoria consecutive.)
Il comando load-upper-immediate (lui
) esiste perché un limm è un valore a 8 bit, ma il registro contiene valori a 16 bit. Il comando lui
carica una valore a 8 bit nella parte più a sinistra, o superiore, degli otto bit di un registro, e riempie con zeri gli altri otto bit più bassi del registro. Nota che può essere difficile avere una costante arbitraria di 16 bit all'interno di un registro; richiede una combinazione di lui
, li
e altri comandi.
Il comando jalr
può essere utilizzato per "saltare" a qualsiasi indirizzo di memoria. Prima di saltare, salva il valore corrente del PC in un registro per rendere possibile poi tornare indietro a quell'indirizzo in seguito; questo può essere fatto per invocare e ritornare da una subroutine. Le istruzioni di selezione, beqz
e bnez
, possono essere utilizzate per saltare e indirizzi vicini. Esse aggiungono un certo valore al valore del PC. La costante è trattato come valore con segno a 8 bit quindi nel range da -128 a 127. Da notare che la costante è aggiunta al valore del PC che è già stato incrementato come parte del ciclo fetch-and-execute, quindi la costante da una differenza (offset) rispetto l'istruzione che segue l'istruzione di branch in memoria.
L'istruzione syscall
ha bisogno di maggiori spiegazioni. Esso ha senso se un programma è in esecuzione sotto il controllo di un sistema operativo. In un computer normale, il sistema operativo ha accesso completo a tutti gli aspetti del computer, mentre gli altri programmi hanno un accesso limitato. L'istruzione syscall
è utilizzata per chiamare subroutine del sistema operativo. Questo è diverso rispetto al chiamare una normale subroutine perché significa rimuovere le restrizioni che si applicano ai normali programmi. Noi non implementeremo un sistema operativo, ma il simulatore simula alcune subroutine di sistema per dare a syscall
qualcosa di utile da fare. Nota che in un computer reale, un errore di sistema, come la divisione per zero, anche trasferisce il controllo al sistema operativo.
Il linguaggio macchina Larc come istruzioni del Linguaggio Assembly
Una istruzione in linguaggio macchina è un numero binario di 16 bit. Ma per i nostri scopi, possiamo anche rappresentare le istruzioni del linguaggio macchina in forma testuale, utilizzando i mnemonici dalla tabella qui sopra. Una istruzione è rappresentata dai codici mnemonici seguita dai suoi argomenti, separati da spazi.
In un comando in linguaggio assembler, un argomento che è un numero di registro è rappresentato da un $ seguito da un numero decimale nel range da 0 a 15: $0, $1, $2, $3, ..., $15. Un valore immediato limm, che è un numero binario a 8 bit può essere rappresentato da una costante decimale nel ragne -128 a 255, da una costante esadecimale nel range da 0x00 a 0xFF, da una costante binaria da 0b00000000 a 0b11111111. Similmente, il valore simm in una istruzione di memoria, che è un numero binario a 4 bit, può essere rappresentato da una costante decimale nel range da -8 a 7, da una costante esadecimale nel range da 0x0 a 0xF, o da una costante binaria nel range da 0b0000 a 0b1111.
Alcuni esempi: add $2 $2 $3
, beqz $2 -13
, li $1 0xF3
, sw $3 $2 0
, jalr $11 $6
, syscall
La seguente tabella mostra la sintassi del linguaggio assembler per le istruzioni in linguaggio macchina del Larc computer. Qui ra, rb e rc rappresentano i registri con numeri che vanno da 0 a 15. LIMM e SIMM rappresentano costanti con il numero appropriato di bit. Ci nono due possibili istruzioni per quelle di tipo memoria, perché il valore SIMM può essere omesso dall'istruzione in linguaggio assembler se il valore è zero.
add $ra $rb $rc
Reg[ra] = Reg[rb] + Reg[rc]
sub $ra $rb $rc
Reg[ra] = Reg[rb] - Reg[rc]
mul $ra $rb $rc
Reg[ra] = Reg[rb] * Reg[rc]
div $ra $rb $rc
Reg[ra] = Reg[rb] / Reg[rc]
sll $ra $rb $rc
Reg[ra] = Reg[rb] << Reg[rc]
srl $ra $rb $rc
Reg[ra] = Reg[rb] >>> Reg[rc]
nor $ra $rb $rc
Reg[ra] = ~(Reg[rb] | Reg[rc])
slt $ra $rb $rc
Reg[ra] = (Reg[rb] < Reg[rc])? 0 : 1
li $ra LIMM
Reg[ra] = sext(LIMM)
lui $ra LIMM
Reg[ra] = LIMM << 8
beqz $ra LIMM
if Reg[ra] == 0, then PC = PC + sext(LIMM)
brnez $ra LIMM
if Reg[ra] != 0, then PC = PC + sext(LIMM)
lw $ra $rb
Reg[ra] = Mem[ Reg[rb] ]
sw $ra $rb
Mem[ Reg[rb] ] = Reg[ra]
lw $ra $rb SIMM
Reg[ra] = Mem[ Reg[rb] + sext(SIMM) ]
sw $ra $rb SIMM
Mem[ Reg[rb] + sext(SIMM) ] = Mem[ra]
jalr $ra $rb
temp = PC; PC = Reg[rb]; Reg[ra] = temp
syscall
call system subroutine number Reg[1]
Tabella di riepilogo istruzioni e chiamate di sistema
Last updated