Le istruzioni: il linguaggio dei calcolatori

Transcript

Le istruzioni: il linguaggio dei calcolatori
Le istruzioni: il linguaggio dei
calcolatori
Luigi Palopoli Insieme delle Istruzioni
•  Per impar.re istruzioni al computer bisogna parlare il suo linguaggio •  Il linguaggio si compone di un vocabolario di istruzioni de7o instruc0on set (IS) •  I vari .pi di processore hanno ciascuno il proprio IS. •  Tu7avia le differenze non sono eccessive §  Un u.le esempio e’ quello delle inflessioni regionali di un’unica radice linguis.ca Instruction Set
•  Come osservato da Von Nueman le istruzioni: “cer0 [insiemi di istruzioni] che in linea di principio si prestano a controllare l’Hardware” •  Egli stesso osservava che le considerazioni davvero decisive sono di natura pra.ca: §  semplicita’ dei disposi.vi richies. §  chiarezza delle applicazioni §  velocita’ di esecuzionei •  Queste considerazioni scri7e nel 1947 sono straordinariamente valide anche oggi In queste lezioni…
•  Questa serie di lezioni vuole mostrare degli IS (in modo da vedere in seguito la realizzazione) •  Studieremo il conce7o di programma memorizzato: Istruzioni e da0 sono memorizza0 come numeri •  Studieremo due IS: •  MIPS •  INTEL Perche’ il MIPS
•  Il mo.vo per cui mostreremo e faremo esercizi con INTEL e’ abbastanza chiaro (qualche milione di PC sono basa. su Intel o Intel compa.bili) •  L’archite7ura MIPS e’ invece un’archite7ura RISC (in verita’ non diffusissima) •  Tu7avia §  E’ molto simile ad altre archite7ure RISC diffusissime (esempio ARM) §  L’archite7ura INTEL fa una traduzione on the fly del proprio IS che viene trado7a internamente in un linguaggio RISC Incominciamo…..
•  Inzieremo dall’IS MIPS •  A cominciare da Von Neuman si diceva che all’interno di un IS: Devono necessariamente essere previste istruzioni per il calcolo delle operazioni aritme0che fondamentali Operazioni artimetiche
•  E’ dunque naturale che l’archite7ura MIPS suppor. le operazioni aritme.che •  Per proge7are un IS come quello del MIPS terremo conto di vari principi ispiratori Principio di Proge/azione n. 1: La semplicita’ favorisce la regolarita’ Istruzioni aritmetiche
•  Il modo piu’ semplice di immaginare una istruzione aritme.ca e’ a tre operandi: a = b + c!
•  Quindi l’archite7ura del MIPS prevede soltanto istruzioni aritme.che a tre operandi add a, b, c!
Istruzioni piu’ complesse
•  Istruzioni piu’ complesse si o7engono a par.re dalla combinazione di istruzioni semplici. •  Es. a = b + c;!
d = a – e;!
•  Diventa add a, b, c!
sub d, a, e!
Esempio
•  Nei linguaggi ad alto livello possiamo scrivere espressioni complesse a piacimento: f = (g+h) – (i+j);!
•  Quando si traduce a basso livello bisogna per forza usare sequenze di istruzioni elementari Esempio
•  Ad esempio la nostra espressione verra’ trado7a come mostrato di seguito add t0, g, h; #la variabile temp.!
# t0 = g + h!
add t1, i, j; #la variabile temp.!
# t1 = i + j!
sub f, t0, t1; # f = t0 – t1!
!
Un po’ di commenti
•  Nell’assembler MIPS §  i commen. iniziano con # e con.nuano fino alla fine della linea §  l’operando “des.natario” dell’operazione e’ sempre il primo •  Questo non vale per tuX gli assemblatori. •  Ad esempio se si usa gcc come assemblatore questo segue la sintassi AT&T per la quale: §  I commen. si fanno a la C /* commento */ §  L’operando des.natario dell’operazione e’ messo in fondo Operandi
•  Fino ad ora abbiamo usato gli operandi piu7osto allegramente (come se fossero “normali” variabili di un linguaggio ad alto livello) •  In realta’ nel MIPS gli operandi di operazioni aritme.che sono vincola0 ad essere registri •  Un registro e’ una par.colare locazione di memoria che e’ interna al processore e quindi puo’ essere reperita in maniera velocissima (un ciclo di clock) Registri del MIPS
•  Il MIPS con.ene 32 registri a 32 bit (64 nel caso di MIPS – 64) •  Il vincolo di operare solo tra registri semplifica di molto il proge7o dell’hardware •  Ma perche’ solo 32 registri? Principio di Proge/azione n. 2: minori sono le dimensioni, maggiore la velocita’ •  Avere mol. registri obbligherebbe I segnali a spostarsi su distanze piu’ lunghe all’interno del processore •  Quindi per effe7uare uno spostamento all’interno di un ciclo di clock saremmo costreX a rallentare il clock Esempio (Ripreso)
•  Torniamo al nostro esempio: f = (g+h) – (i+j);!
•  Il codice con I registri diviene: add $t0, $s1, $s2; #Il registro temporaneo!
# t0 viene settato = ! ! ! ! ! !# regist. s1+s2 !
add $t1, $s3, $s4; !
sub $s0, $t0, t1; # f = t1 – t0!
!
Osservazioni
•  Nell’assembler MIPS per indicare che un operando e’ un registro lo si fa precedere da $ •  Come abbiamo de7o le operazioni aritme.che e logiche si effe7uano solo tra registri •  Il problema e’ che I registri non bastano •  Ci occorrono istruzioni di trasferimento che §  prelevino locazioni di memoria e li me7ano nei registri (load) §  salvino il contenuto dei registri in memoria La memoria
•  La memoria e’ una sequenza di bit organizza. in gruppi di 8 (byte). Ciascun byte e’ associato ad un indirizzo lineare progressivo tramite il quale e’ possibile prelevarlo Word
•  Per quanto la maggior parte delle archite7ure perme7ano l’accesso a ciascun byte la maggior parte delle volte si trasferiscano parole di dimensioni uguali ai registri Vincolo di allineamento: e’ possibile accedere solo a parole poste a indirizzi mul.pli dell’ampiezza della parola Trasferimento
•  Per caricare una word (o un byte) devo specificarne l’indirizzo •  Nell’assembler MIPS l’indirizzo si specifica tramite una base (in un registro) e uno spiazzamento o offset (costante) •  Come vedremo in altre archite7ure (esempio INTEL) c’e’ molta piu’ flessibilita’ nello specificare l’indirizzo Load
•  Il caricamento di una parola contenuta in indirizzo in un registro avviene tramite la seguente istruzione: lw $t0, 4($s3)!
Si sta operando su una parola Registro in cui si vuole caricare Base Spiazzamento •  L’effe7o di questa istruzione e’ di caricare in t0 la word all’indirizzo dato da s3 + 4 Esempio
•  Supponiamo di volere effe7uare l’istruzione A[12] = h + A[8]!
•  La traduzione in assembler MIPS lw $t0, 32($s3); # La parola 8 comincia !
! ! ! ! ! ! !#all’indirizzo 32 e il!
! ! ! ! ! ! !#puntatore A e’ in s3!
add $t0, $s2, $t0; #h e’ in s2 !
sw $t0, 48($s3); # memorizzo il contenuto del!
# registro temp. in A[12]!
!
Register Spilling
•  Tipicamente I programmi contengono piu’ variabili che registri :=) •  Quello che si fa e’ caricare le variabili in uso in un dato momento nei registri e scaricare quelle che non si usano piu’ in quel momento •  Questa operazione e’ chiamata register spilling ed e’ eseguita dal compilatore che s.ma il working set ed inserisce nel codice I carichi/scarichi appropria. •  Nell’esempio precedente,magari l’indirizzo di A serve ancora in s3 nelle istruzioni successive mentre forse h si puo’ scaricare da s2 Operandi immediati o
costanti
•  Molto spesso nelle operazioni aritme.che almeno uno dei due operandi e’ costante •  Un possibile approccio puo’ essere di memorizzare la costante in un qualche indirizzo •  Esempio: f = f + 4;!
lw $t0, IndCost4($s1);# la costante 4!
! !#e’ all’indirizzo s1 + IndCost4
add $s3, $s3, $t0; !
Operandi Immediati
•  La soluzione che abbiamo visto e’ piu7osto inefficiente Principio di Proge/azione n. 3: rendi piu’ veloci possibile le operazioni comuni •  Per questo mo.vo esistono istruzioni che perme7ono di operare con costani f = f + 4;!
addi $s3, $s3, 4!
Immediate La costante 0
•  Esistono alcune costan. che possono essere di grande u.lita’ per semplificare alcune operazioni •  Ad esempio per spostare un registro in un altro posso renderlo des.natorio della somma del sorgente con 0 •  Per questo mo.vo il MIPS dedica un registro $zero a contenere la costante 0 Numeri
•  Prima di parlare del modo in cui le istruzioni sono codificate a7raverso numeri (rappresentate) ricordiamo: §  Nei calcolatori l’unita’ base di informazione e’ il bit §  Un gruppo di 4 bit puo’ essere associato ad un numero fino a 16 che rappresenta una cifra nella notazione esadecimale §  Quindi un byte viene rappresentato da due cifre esadecimali (ciascuna corrispondente a 4 bit) §  Ad esempio 1001 1101!
9D!
Cifre esadecimali
Little e big endian
•  Quando si memorizza una parola di qua7ro byte (o di 8) in una sequenza di byte pos. a indirizzi progressivi va capito dove va il byte piu’ significa.vo e quello meno significa.vo. •  Esempio (esadecimale) 0XEA01BD1C!
Byte piu’ significa.vo Byte meno significa.vo Little e big endian
•  Big endian (Archite7ure Motorola, Protocolli Internet) EA01BD1C!
Addr 3 EA Addr 2 01 Addr 1 BD Addr 0 1C •  Li7le Endian (Intel) EA01BD1C!
Addr 3 1C Addr 2 BD Addr 1 01 Addr 0 EA Rappresentazione delle
istruzioni
•  Come I da., anche un programma deve essere memorizzato in forma numerica •  Questo vuol dire che le istruzione che abbiamo introdo7o simbolicamente (assembler) devono essere conver.te in dei numeri (codice macchina) •  Cominciamo con un esempio Esempio
•  Consideriamo l’istruzione add $t0, $s1, $s2 •  Per rappresentarla tramite un codice numerico univoco ci occorre: •  Un codice numerico che ci dica che si tra7a di un add •  Altri codici numerici che ci dicano quali sono gli operandi… •  il tu7o in 32 bit Risultato
•  Il risultato rappresentato in decimale e’ il seguente: 6 bit 5 bit 5 bit 5 bit 5 bit 6 bit 000000 10001 10010 01000 00000 100000 (0) I primi e gli ul.mi bit codificano l’istruzione (17) (18) Primo operando (8) Secondo operando (0) (32) Risultato •  I registri sono numera. (es. s1 = 17, s2 = 18) e quindi possono essere specifica. come operandi all’interno del codice dell’istruzione Campi delle istruzioni MIPS
•  In generale, e’ u.le dare un nome ai vari campi rela.ve al codice macchina di un’istruzione 6 bit 5 bit 5 bit 5 bit OP rs rt rd •  op: codice opera.vo dell’istruzione •  rs: primo operando sorgente •  rt: secondo operando sorgente •  rd: operando des.nazione 5 bit 6 bit shamt funct •  shamt: shio amount (lo vedremo per alcune istuzioni) •  funct: definisce la funzionalita’ specifica dell’istruzione (insieme a op). Ad esempio la so7razione e’ un par.colare .po di addizione Tradeoff
Principio di Proge<azione n. 4: un buon proge<o richiede buoni compromessi •  Nel nostro caso il buon compromesso e’ di far stare le istruzioni in 32 bit •  Ci costa §  limite al numero di istruzioni §  limite al numero di registri §  limite alle modalita’ di indirizzamento •  … ma ci perme7e di guadagnare molto in efficienza Istruzioni Immediate
•  Abbiamo visto che ci sono istruzioni di caricamento/salvataggio e somma con costan. che non possono ovviamente stare nel formato che abbiamo visto (de7o R, da registro) •  Per questo mo.vo esiste anche un formato per l’indirizzamento immediato (de7o I) Istruzioni Immediate
•  Il formato e’ il seguente 6 bit 5 bit 5 bit OP rs rt 16 bit costante o indirizzo •  Ad esempio: 35!
lw $t0, 32($s3) $s3 19!
$t0 8!
32!
Esempio
•  Supponiamo di vole tradurre in linguaggio macchina le seguen. istruzioni: A[300] = h + A[300];!
•  La traduzione e’ la seguente: lw $t0, 1200($t1)!
add $t0, $s2, $t0!
sw $t0, 1200($t1)!
!
in codice macchina….
•  Cominciamo con il guardare i codici decimali: lw
Istruzione op rs rt $t0, 1200($t1)!
35 9 8 0 18 8 43 9 8 add $t0, $s2, $t0!
sw
$t0, 1200($t1)!
rd Ind/Shamt Funct 1200 8 0 32 1200 •  In binario op rs rt 100011 01001 01000 000000 10010 01000 101011 01001 01000 rd Ind/Shamt Funct 0000 0100 1011 0000 01000 00000 0000 0100 1011 0000 100000 Riassumendo
•  Ciascuna istruzione viene espressa come un numero di 32bit •  Un programma consiste dunque in una sequenza di numeri •  Tale sequenza viene scri7a in locaziomi consecuitve di RAM •  In momen. diversi, nella stessa RAM, possiamo rappresentare programmi diversi Codici delle istruzioni viste
fino ad ora
Elenco (quasi completo)
delle istruzioni MIPS
Elenco (quasi completo)
delle istruzioni MIPS
Operazioni Logiche
•  I primi calcolatori operavano solo su parole intere •  Molto presto si manifesto’ la necessita’ di operare su porzioni di parole o addiri7ura sul singolo bit •  Il MIPS fornisce alcune istruzioni che perme7ono di fare questo in maniera semplificata (rispe7o ad altre archite7ure) ma efficace Shift logico
•  La prima operazione che andiamo a vedere e’ il coside7o shio logico a sinistra •  L’idea e’ di inserire degli zeri nella posizione meno significa.va e traslare tu7o a sinistra perdendo I bit piu’ significa.vi •  Esempio consideriamo: s0 = 0000 0000 0000 0000 0000 0000 0000 1001 !
•  eseguiamo: sll $t2, $s0, 4!
0000 0000 0000 0000 0000 0000 0000 1001 !
0000!
•  L’effe7o e’ di memorizzare in t2 144 (da 9 inizialmente presente in s0) Il codice operativo
•  Il codice opera.vo dell’istruzione: sll $t2, $s0, 4!
•  e’: op rs rt rd Ind/Shamt Funct 0 0 16 10 4 0 Da qui si comprende l’u.lita’ del campo “shio amount” Effetto “collaterale”
•  Un effe7o collaterale di questa istruzione e’ mol.plicare il numero operando per 2^I, dove I e’ il numero di elemen. di cui si fa lo shio •  Questo funziona sempre? •  Esempio: s0 = 10000000000000000000000000000100 !
(dec.-2147483644)!
•  Cosa succede se noi effe7uiamo: sll $t2, $s0, 1!
•  O7eniamo: t2 = 00000000000000000000000000001000 !
(dec. 8)!
•  Il problema e’ semplicemente che il numero non e’ rappresentabile. Un caso diverso
•  Se invece prendiamo: s0 = 11111111111111111111111111111110 !
(dec.-2)!
•  Se effe7uiamo: sll $t2, $s0, 1!
•  O7eniamo: s0 = 11111111111111111111111111111100 !
(dec.-4)!
•  Se rimaniamo nel range di rappresentabilita’ la mol.plicazione per potenze di 2 tramite shio funziona bene. Shift a destra
•  Analogamente allo shio logico a sinistra si puo’ avere uno shio logico a destra •  Esempio: s0 = 0000 0000 0000 0000 0000 0000 0000 1001 !
•  Se effe7uiamo: srl $t2, $s0, 1!
0!
0000 0000 0000 0000 0000 0000 0000 1001 !
Effetti collaterali
•  Generalizzando il ragionamento che abbiamo fa7o prima, ci verrebbe di dire che lo shio a destra di I unita’ corrisponde a dividere per 2^I •  E’ corre7o? •  Nell’esempio fa7o prima facendo lo shio a destra di 1 sul numero 9 abbiamo o7enuto 4 (che e’ il risultato della divisione intera) •  Consideriamo un altro esempio: s0 = 11111111111111111111111111111100 !
(dec.-4)!
srl $t2, $s0, 1!
•  Quello che si oXene e’ un numero posi.vo e questo nonostante il risultato dell’operazione sia perfe7amente rappresentabile :=( Shift aritmetico
•  Per risolvere il problema evidenziato si risolve con lo shio aritme.co a destra. •  In sostanza quello che si inserisce a destra non sono bit uguali a 0 ma uguali al bit di segno •  Nel nostro esempio s0 = 11111111111111111111111111111100 !
sra $t2, $s0, 1!
11111111111111111111111111111100 !
•  Risultato (corre7o): 11111111111111111111111111111110 !
Shift aritmetico
•  Notare che lo shio aritme.co non ha nessun senso fa7o a sinistra §  In quel caso o il risultato e’ rappresentabile e lo shio logico funziona come ar.me.co o non lo e’ e non c’e’ molto che si possa fare. •  Altre archite7ure offrono entrambi I .pi di shio §  MIPS essendo RISC fornisce solo l’essenziale :=) Altre operazioni logiche
•  Il MIPS offre in aggiunta a quelle viste altre operazioni logiche •  Alcune di queste sono elencate di so7o: AND bit a bit
•  Le operazioni logiche operano su ciascun bit •  Esempio: t1 = 0000 0000 0000 0000 0000 1101 0000 0000 !
t2 = 0000 0000 0000 0000 0011 1100 0000 0000 !
and $t0, $t1, $t2!
•  Risultato: t0 = 0000 0000 0000 0000 0000 1100 0000 0000 !
•  L’operazione and forza alcuni bit a 0 usando come operando una maschera (I cui bit corrisponden. a quelli che si vogliono annullare siano 0) OR bit a bit
•  Analogamente e’ possibile se7are a 1 alcuni bit facendo or con un operando che abbia 1 nella posizione corrispondente (maschera) •  Esempio: §  Supponiamo di volere girare i qua7ro bit piu’ significa.ve di una word sui suoi bit meno significa.vi 1101 0000 0000 0000 0000 1100 0000 0000 !
Esempio
•  Primo passo s0 = 11010000000000000000110000000000 !
andi $t0, $s0, 0xF0000000!
t0 = 11010000000000000000000000000000 !
•  Second passo t0 = 11010000000000000000000000000000 !
srl $t0, $t0, 28!
t0 = 00000000000000000000000000001101 !
AND immediato Esempio
•  Terzo passo s0 = 11010000000000000000110000000000 !
sll $s0, $s0, 4!
s0 = 00000000000000001100000000000000 !
•  Quarto passo s0 = 00000000000000001100000000000000 !
or $s0, $s0, $to!
s0 = 00000000000000001100000000001101 !
Il nor
•  Supponiamo: t1 = 0000 0000 0000 0000 0000 1101 0000 0000 !
t2 = 0000 0000 0000 0000 0011 1100 0000 0000 !
nor$t0, $t1, $t2!
•  Risultato: t0 = 1111 1111 1111 1111 1100 0010 1111 1111 !
Lo strano caso del not
•  Il not normalmente e’ un operatore unario •  Per i progeXs. MIPS tu7e le operazioni ar.me.che hanno tre operandi di .po registro •  Per questo mo.vo si e’ deciso di non fornire il not ma il nor •  Il not si oXene dal nor molto facilmente nor $s0, $s0, $zero #equivale a not s0!
Or esclusivo
•  Oltre che AND, OR, NOR abbiamo anche un supporto per l’OR esclusivo (XOR) •  Ricordiamo che l’OR esclusivo produce 1 se e solo se I due bit operandi sono uno e zero (e zero negli altri casi). t1 = 0000 0000 0000 0000 0000 1101 0000 0000 !
t2 = 0000 0000 0000 0000 0011 1100 0000 0000 !
xor$t0, $t1, $t2!
•  Risultato: t0 = 0000 0000 0000 0000 0011 0001 0000 0000 !
Esempio
•  Cosa succede se facciamo? xor $t0, $t0, $t0!
•  Il risultato e’ quello di annullare il valore di t0 •  E’ una maniera molto veloce ed efficiente per annullare un registro •  Ricordare •  A XOR B = (A AND NOT(B)) OR (NOT(A) AND B) Istruzioni per prendere
decisioni
•  Una delle cara7eris.che fondamentali dei calcolatori (che li dis.nguono dalle calcolatrici) e’ la possibilita’ di alterare il flusso di programma al verificarsi di certe condizioni §  costru7o if nelle varie forme •  Il linguaggio macchina delle varie archite7ure supporta questa possibilita’ fornendo istruzioni di salto condizionali •  Tipicamente questo avviene sulla base del valore di un registro di flag di stato •  Nel caso le condizioni per il salto sono esplicite nell’istuzione di salto Salto su condizioni
•  Le due istruzioni di salto condizionale sono: beq reg1, reg2, L1!
bne reg1, reg2, L1!
Se il registro reg1 e’ uguale al registro reg2 effe7ua un salto all’istruzione con e.che7a L! Se il registro reg1 e’ diverso dal registro reg2 effe7ua un salto all’istruzione con e.che7a L! Costrutto if
•  Supponiamo di avere il seguente codice C. Come viene trado7o? if (i == j) f = g + h; else f = g – h;!
Costrutto if
•  Traduzione costru7o if precedente: bne
add
j
ELSE: sub
ESCI: ……
$s3, $s4, ELSE #Salta a ELSE se s3 div. da s4!
$s0, $s1, $s2 #f = g + h!
ESCI
# Salto incond. a ESCI!
$s0, $s1, $s2 # f = g - h !
!
•  Alcune osservazioni •  Le label vengono alla fine trado7e in indirizzi •  Per fortuna questo lavoro noioso e’ opera del compilatore Cicli
•  La stru7ura che abbiamo presentato puo’ essere usata anche per realizzare dei cicli •  Consideriamo l’esempio: while (salva[i] == k)!
i += 1;!
•  Traduzione: !
!
!
Ciclo: sll $t1, $s2, 2
! ! !add $t1, $t1, $s6
! ! !lw $t0, 0($t1)
! ! !bne $t0, $s5, Esci
addi$s2, $s2, 1
j
Ciclo!
Esci: …. !
#Registro temp. t1 = 4*I!
#Ind di salva[i] in t1!
#salva[i] in t0!
#Esci se raggiunto limite!
#i = i+1!
Commenti
•  Le sequenze di istruzioni di salto condizionato (condi.onal branch) sono cosi’ importan. che viene dato loro un nome: blocchi di base §  Blocco di base: seq. di istruzioni che non con.ene istuziomi di salto (con l’eccezione dell’ul.ma) ne e.che7e di des.nazione (con l’eccezione dela prima) •  Una delle prime fasi della compilazione e’ di individuare I blocchi base •  TuX I cicli in linguaggio ad alto livello vengono implementa. co blocchi di base. Altri confronti
•  Oltre al salto su operandi uguali o diversi, e’ utlie avere un salto anche su operandi minori/maggiori o minori uguali •  Il modo di fare del MIPS e’ tramite istruzioni che se7ano il valore di registri flag •  La prima di queste e’ se7a se minore o uguale slt $t0, $s3, $s4 #t0 = 1 se s3 < s4!
•  Di questa istruzione esiste anche una variante immediata: slti $t0, $s3, 10 #t0 = 1 se s3 < 10!
•  I compilatori MIPS o7engono I sal. su condizioni di .po minore o uguale combinando SLT con BEQ, o BNE e usando la costante 0 per fare I test Esempio
•  Consideriamo il codice if (i < j) f = g + h; else f = g – h;!
•  Traduzione !
!
slt $t0, $s3, $s4 #setta t0 se se i < j
!
!bne $t0, $zero, ELSE #Salta a ELSE se s3 div. da s4!
add $s0, $s1, $s2 #f = g + h!
j
ESCI
# Salto incond. a ESCI!
ELSE: sub $s0, $s1, $s2 # f = g - h !
ESCI: …… !
Signed e unsigned
•  L’esito del confronto e’ ovviamente diverso se si .ene conto del segno oppure no. •  Per questo mo.vo troviamo due versioni di SLT (SLTU, SLTUI) che operano su interi senza segno Esempio
•  Si supponga che s0 = 1111 1111 1111 1111 1111 1111 1111 1111 !
s1 = 0000 0000 0000 0000 0000 0000 0000 0001 !
•  Cosa produce? slt $t0, $s0, $s1!
t0 = 1!
•  E cosa sltu $t0, $s0, $s1!
t0 = 0!
Un piccolo trucco
•  Supponiamo di volere controllare se un indice (s1) e’ fuori dal limite di un array ([0, t2]) •  Ce la possiamo cavare con un solo confronto sltu $t0, $s1, $t2!
beq $t0, $zero, FuoriLimite!
•  Perche’? •  Se s1 e’ maggiore di t2, ovviamente avremo 0 in t2 •  Ma anche se s1 e’ nega.vo, interpretato come unsigned, sara’ maggiore di t2 (che ha il bit piu’ significa.vo a 0) Il costrutto case/switch
•  Una possibilita’ e’ quella di effe7uare una sequenza in cascata di if-­‐then-­‐else •  In realta’ esiste una tecnica diversa §  Memorizzare i vari indirizzi dove eseguire il codice in una tabella (una sequenza di word) §  Caricare in un registro l’indirizzo cui si deve saltare §  fare un salto all’indirizzo puntato dal registro (jr) Il costrutto case/switch
•  Esempio: switch(a) {!
case 1: <code 1>;!
! case 2: <code 2>;!
…..!
!
};!
!!
Tabella dove memorizzo gli indirizzi dei codici sll! $t0, $a0, 2 #moltiplica per
4!
lw $t0, TABLE($t0)!
jr $t0 !
!!
Salto all’indiriizzo nel registro Procedure
•  L’u.lita’ di un compute sarebbe molto limitata se non si potessero chiamare procedure (o funzioni) •  Possiamo pensare a una procedure come a una “spia” che fa del lavoro per noi senza che noi vogliamo sapere come lo fa •  La cosa importante e’ di me7ersi d’accordo su un protocollo Procedure
•  L’u.lita’ di un compute sarebbe molto limitata se non si potessero chiamare procedure (o funzioni) •  Possiamo pensare a una procedure come a una “spia” che fa del lavoro per noi senza che noi vogliamo sapere come lo fa •  La cosa importante e’ di me7ersi d’accordo su un protocollo Protocollo
1. me7er i parametri in un posto noto 2. trasferire il controllo alla procedura 1. Acquisire le risorse necessarie 2. Eseguire il compito 3. me7ere i valori di ritorno in pos. no. 4. Res.tuire il controllo al chiamante 3. Prendersi il valore di ritorno e “cancellare” le traccie Protocollo
•  Il modo in cui questo protocollo viene messo in pra.ca dipende dall’archite7ura e dalle convenzioni di chiamata del compilatore •  Lo vedremo in de7aglio per l’archite7ura INTEL •  Ci limi.amo a pochi cenni per il MIPS Protocollo di chiamata
MIPS
•  L’idea di base e’ di cercare di laddove possibile i registri, perche’ sono il meccanismo piu’ veloce per effe7uare il passaggio dei parametri •  Convenzione per il MIPS §  $a0, ..$a3: usa. per i parametri in ingresso §  $v0, $v1 : valori di ritorno §  $ra : indirizzo di ritorno per tornare al punto di partenza Protocollo di chiamata
MIPS
•  Oltre ai registri, l’hardware MIPS me7e a disposizione l’istruzione di jump and link (JAL) che effe7ua il salto e contemporaneamente memorizza in ra l’indirizzo di ritorno §  L’indirizzo che viene salvato in ra e’ il PC (program counter) incrementato di 4 (istruzione sucessiva alla jal) •  Alla fine della procedura sara’ sufficiente fare un salto jr $ra!
!!
…e se i registri non
bastano?
•  In cer. casi I registri non bastano perche’ ho piu’ parametri di quan. ne possano contenere I registri •  In tal caso si una lo stack, una stru7ura da. ges.ta con disciplina FIFO in cui e’ possibile me7ere a par.re da una posizione nota alla procedura (puntata dal registro fp) I parametri in piu’ •  Lo stack si puo’ usare anche me7ere variabili locali (tramite un’operazione di push) e salvare registri che occorrera’ ripris.nare in seguito •  Alla fine della procedura si puo’ ripulire lo stack (operazione pop) riportandolo alla situazione precedente Esempio
•  Consideriamo la procedura in C: int esempio_foglia(int g, int h, int i, int j) {!
int f;!
!
f = (g+h) – (i+j);!
return f;!
}!
•  Cerchiamo di capire come verrebbe trado7a Prologo
•  Per prima cosa il compilatore sceglie un’e.che7a associata all’indirizzo di entrata della procedura (esempio_foglia) §  In fase di collegamento (linking) l’e.che7a sara’ collegata a un’indirizzo •  La prima operazione e’ quella di salvare in memoria tuX I registri che la procedura usa in modo da poterli ripris.nare in seguito •  Tale fase e’ chiamata prologo e potrebbe richiedere di allocare nello stack anche spazio per le variabili locali (se i registri non bastano). Prologo
•  La procedura us I registri s0, t0, t1; •  Il registro SP punta alla testa dello stack (che si evolve verso il basso) •  Il codice del prologo e’ il seguente: Decremen.amo sp di 12, per far posto a 3 word esempio_foglia:
! ! ! !
! ! ! !
! ! ! !
addi
!sw
!sw
!sw
$sp, $sp, -12;!
$t1, 8($sp)!
$t0, 4($sp)!
$s0, 0($sp)!
Salvataggio di t1 in sp
+8 Salvataggio di s0 in sp
+0 Esecuzione della procedura
•  Dopo il prologo, l’esecuzione della procedura: In t0 meXamo g+h add $t0, $a0, $a1!
add $t1, $a2, $a3!
sub $s0, $t0, $t1!
In t1 meXamo i+j In s0 (g+h)-­‐(i+j) Epilogo
•  Dopo aver eseguito la procedura, si ripris.nano i registri usa. e si se7a il valore di ritorno Trasferiamo s0 in v0 (valore di ritorno) add
lw
lw
lw
addi
jr
!
$v0,
$s0,
$t0,
$t1,
$sp,
$ra!
Ripris.no I registri prelevando i valori esa7amente da dove li avevo messi $s0, $zer0 !
0($sp)!
4($sp)!
8($sp)!
$sp, 12!
Salto al punto da dove sono arrivato Ripris.no lo stack (tu7o cio’ che e’ so7o sp non e’ significa.vo) Evoluzione dello stack
Stack prima della chiamata Stack durante l’esecuzione della procedura Stack dopo la chiamata Ulteriori complicazioni
•  In realta’ le cose possono complicarsi per via di §  Variabili locali §  Procedure annidate •  Questo si risolve usando sempre lo stack e allocandovi dentro variabili locali e valori del registro ra •  Queste cose le vedremo in de7aglio per INTEL