Esercizi C MIPS PDF

Title Esercizi C MIPS
Course Architettura dei calcolatori e sistemi operativi
Institution Politecnico di Milano
Pages 40
File Size 626.3 KB
File Type PDF
Total Downloads 101
Total Views 142

Summary

Esercizi in C MIPS...


Description

esercizio linguaggio m acchina – esame 9 luglio 2015 prima parte – traduzione in assembler Si

deve

tradurre

in

linguaggio

macchina

simbolico

(linguaggio

assemblatore)

MIPS

il

frammento

di

programma C riportato sotto, costituito dalla sezione dichiarativa delle variabili globali che contiene la sola variabile vett , e dalla funzione ricorsiva f_ric. Non si tenti di accorpare od ottimizzare insieme istruzioni C indipendenti. La memoria ha indirizzi da

32 bit ,

è indirizzabile per

byte

e gli interi sono da

32 bit .

Si

facciano le ipotesi seguenti:



il fame pointer non è in uso



le variabili locali sono allocate nei registri se possibile

Si chiede

di svolgere i quattro punti seguenti:

1.

Si descriva

l’area di attivazione della funzione f_ric, secondo il modello MIPS, nella tabella predisposta.

2.

Si traduca

in linguaggio macchina MIPS la sezione dichiarativa della variabile globale vett nella tabella

predisposta, in cui è già stata inserita la direttiva . data che definisce l’indirizzo di impianto delle variabili globali. 3.

Si traduca

in linguaggio macchina MIPS il codice della funzione f_ric, coerentemente con le specifiche e

le risposte ai punti precedenti, usando la tabella predisposta. Se lo si ritiene utile, prima della traduzione si derivino gli alberi associati alle espressioni presenti nel codice. 4.

Si risponda

alla domanda sulla

mappatura della memoria

così come richiesto al punto

/ sezione dichiarativa variabili globali / #define N 10 int vett [N];

/ funzione f_ric / int f_ric (int  p, int i)  int j;

/ variabili locali /

j = i; if (j == -1)  return 0;  else  p = vett [i]; return f_ric (p, i - 1);  / end if /  / f_ric /

/ chiamata ricorsiva /

4.

punto

1

– (numero di righe non significativo)

area di attivazione di f_ric

contenuto simbolico

spiazz. rispetto a stack pointer

ra

4

s0 (assegnato a varloc j)

0

a1 (assegnato a param i)

salvato prima di chiamata

indirizzi alti

 sp max estensione del prologo chiamante

indirizzi bassi

Si noti che la funzione è ricorsiva, pertanto essa funziona sia come chiamante (caller) sia come chiamato (callee). Il chiamante salva il secondo parametro “a1” (assegnato a “i”) in pila per poterlo poi riavere inalterato. Tuttavia, si può notare che in effetti il chiamante non usa il secondo parametro dopo la chiamata; dunque si può evitare di salvare tale parametro in pila. Va anche bene salvare sempre, prudenzialmente, tutti i parametri passati (qui entrambi), a prescindere da che poi il chiamante ne abbia ancora bisogno con i loro valori originali. IL MODELLO DI CHIAMATA A FUNZIONE USUALE PREVEDE CHE IL CHIAMANTE SALVI I PARAMETRI IN PILA SOLO SE DOPO LA CHIAMATA A FUNZIONE ESSO NECESSITA DI RITROVARLI INALTERATI. QUI IL MODELLO NON VIENE RISPETTATO RIGOROSAMENTE SOLO PER MOSTRARE COME SALVARE UN PARAMETRO IN PILA. punto

VETT:

2

– codice MIPS della sezione dichiarativa globale (num. righe non signif.)

.data

0x 1000 0000

// indirizzo di impianto dati

.space

40

// dichiarazione variabile globale

punto

F_RIC:

IF:

THEN:

ELSE:

3

– codice MIPS di

(num. righe non signif.)

addiu $sp, $sp, -8

// costruisci area

.eqv

RA, 4

// spiazzamento di ra salvato

.eqv

S0, 0

// spiazzamento di s0 salvato

sw

$ra, RA($sp)

// salva ind rientro

sw

$s0, S0($sp)

// salva reg s0 (varloc J)

move

$s0, $a1

// aggiorna varloc j

li

$t0, -1 (o addi $t0, $0, -1) // carica cost -1

bne

$s0, $t0, ELSE

// se j != -1 va’ a ELSE

move

$v0, $0 (o add $v0, $0, $0)

// prepara valusc

j

ENDIF

// va’ a ENDIF

la

$t0, VETT

// carica ind VETT

move

$t1, $a1

// copia arg i

sll

$t1, $t1, 2

// allinea indice

addu

$t0, $t0, $t1

// calcola ind elem (

lw

$t1, ($t0)

// carica elem v[i]

sw

$t1, ($a0)

// aggiorna

addiu $sp, $sp, -4

 )

p

// 1) decrementa reg sp (

 )

sw

$a1, ($sp)

// 2) salva param i (push)

addi

$a1, $a1, -1

// calcola i – 1 (

jal

F_RIC

// chiama f_ric

lw

$a1, ($sp)

// 3) ripristina param i (pop)

addiu $sp, $sp, 4 ENDIF:

f_ric

 )

// 4) incrementa reg sp

lw

$s0, S0($sp)

// ripristina reg s0

lw

$ra, RA($sp)

// ripristina ind rientro

addiu $sp, $sp, 8 jr

$ra

// elimina area // rientra

Le istruzioni (1-2) realizzano l’operazione “PUSH” di “a1” (param “i”) sulla cima della pila; le istruzioni (3-4) realizzano l’operazione “POP” di “a1” (param “i”) dalla cima della pila.



Qui si usa una somma “addu” (oppure “addiu”) di tipo “senza segno” (unsigned), poiché si tratta di

un’operazione per calcolare un indirizzo, ossia un numero naturale sempre positivo o nullo. Infatti, giacché il risultato di un’operazione su indirizzi sarà sempre un numero naturale, va usata l’aritmetica senza segno.



Invece per un’operazione su variabili di tipo intero relativo (positive, nulle o negative), come per varabili di

tipo “int” nel calcolo di un’espressione algebrica, va usata l’aritmetica “con segno”.

Note varie:



l’istruzione “li” è sostituibile con l’istruzione “addi” poiché la costante –1 da caricare è a solo 16 bit



la pseudo-istruzione “move” è facilmente espandibile tramite un’istruzione “addi”



formalmente il registro “s0” va salvato in pila a cura del chiamato, poiché è assegnato alla variabile locale “j”, ma giacché la funzione in realtà non lo modifica, ottimizzando molto si potrebbe evitare di salvarlo (così però deviando dal modello rigoroso di area di attivazione)



il parametro “i” allocato nel registro “a1” viene modificato dal chiamante per passarlo al chiamato ricorsivo, e se si prende il ramo ELSE è salvato in pila prima della modifica così causando un’estensione della pila, e poi è ripristinato subito dopo il rientro da “jal” (il ramo THEN non ha effetto); in realtà si potrebbe evitare di salvarlo perché dopo il rientro non viene più usato; si veda il modello di chiamata a funzione illustrato a lezione



invece il parametro “p” allocato nel registro “a0” non viene modificato dalla funzione, pertanto senz’altro non viene salvato (e dunque neppure ripristinato)



AVVERTENZA: si badi bene che lo statement C di assegnamento “*p = vett [i]” USA il parametro puntatore “p”, ma non ne modifica il valore, ossia non cambia l’indirizzo che costituisce il valore di “p” ! ciò che viene modificato, assegnandogli il valore dell’elemento con indice “i” del vettore, è l’oggetto puntato da “p” (si riveda il punto precedente)



i registri temporanei “t0-t7” non vengono salvati (non vengono date indicazioni che la funzione si aspetti di poterli riavere inalterati dopo la chiamata ricorsiva)

Potrebbero esserci altre piccole ottimizzazioni di codice.

punto

4

– mappatura della memoria

Si considerino le ipotesi seguenti relative all’allocazione del programma in codice eseguibile in memoria:



il programma è collocato in memoria secondo il modello standard di MIPS, e l’ordine delle funzioni nel codice è prima main, poi f_ric

 

la dimensione di main è di

1024 byte

il valore del registro sp immediatamente prima che main effettui il passaggio di parametri alla prima invocazione di f_ric è pari a



0x 7FFF 0000

si ricorda che la memoria è indirizzabile a

byte

si chiedono: l’indirizzo della prima istruzione di main:

0x 0040 0000 (standard MIPS)

l’indirizzo della prima istruzione di f_ric:

0x 0040 0000

 1024 (dec)  0x 0040 0000  0x 0000 0400  0x 0040 0400

il valore di sp subito prima della seconda invocazione di f_ric:

0x 7FFF 0000

 (8  4) dec  0x 7FFF

0000

 0x 0000 000C  0x 7FFE FFF4

nota bene: subito prima della seconda invocazione di f_ric la pila ha la max estensione

il valore di sp relativo all’area di attivazione della seconda chiamata di f_ric:

0x 7FFE FFF4

 8 dec  0x 7FFE

FFF4

 0x 0000 0008  0x 7FFE FFEC

nota bene: l’area di attivazione di f_ric (senza estensione per il prologo del chiamante) ha dimensione 8 byte

esercizio linguaggio m acchina – esame 9 luglio 2015 – VARI ANTE I prima parte – traduzione in assembler Si

deve

tradurre

in

linguaggio

macchina

simbolico

(linguaggio

assemblatore)

MIPS

il

frammento

di

programma C riportato sotto, costituito dalla sezione dichiarativa delle variabili globali che contiene la sola variabile vett , e dalla funzione ricorsiva f_ric. Non si tenti di accorpare od ottimizzare insieme istruzioni C indipendenti. La memoria ha indirizzi da

32 bit ,

è indirizzabile per

byte

e gli interi sono da

32 bit .

Si

facciano le ipotesi seguenti:



il fame pointer è in uso



le variabili locali sono allocate nei registri se possibile

Si chiede

di svolgere i quattro punti seguenti:

1.

Si descriva

l’area di attivazione della funzione f_ric, secondo il modello MIPS, nella tabella predisposta.

2.

Si traduca

in linguaggio macchina MIPS la sezione dichiarativa della variabile globale vett nella tabella

predisposta, in cui è già stata inserita la direttiva . data che definisce l’indirizzo di impianto delle variabili globali. 3.

Si traduca

in linguaggio macchina MIPS il codice della funzione f_ric, coerentemente con le specifiche e

le risposte ai punti precedenti, usando la tabella predisposta. Se lo si ritiene utile, prima della traduzione si derivino gli alberi associati alle espressioni presenti nel codice. 4.

Si risponda

alla domanda sulla

mappatura della memoria

così come richiesto al punto

/ sezione dichiarativa variabili globali / #define N 10 int vett [N];

/ funzione f_ric / int f_ric (int  p, int i)  int j;

/ variabili locali /

j = i; if (j == -1)  return 0;  else  p = vett [i]; return f_ric (p, i - 1);  / end if /  / f_ric /

/ chiamata ricorsiva /

4.

punto

1

– (numero di righe non significativo)

contenuto simbolico

spi. rispetto a spi. rispetto a stack pointer

frame pointer

fp

8

0

ra

4



4

s0 (assegnato a varloc j)

0



8

a1 (assegnato a param i)

indirizzi alti

 fp

salvato prima di chiamata

 sp max estensione del prologo chiamante

indirizzi bassi

punto

VETT:

2

– codice MIPS della sezione dichiarativa globale (num. righe non signif.)

.data

0x 1000 0000

// indirizzo di impianto

.space

40

// dichiarazione variabile globale

punto

F_RIC:

3

– codice MIPS di

f_ric

(num. righe non signif.)

addiu $sp, $sp, -12 sw

$fp, 8($sp)

addiu $fp, $sp, -8

// costruisci area // salva fp chiamante // sposta fp

// da qui si usa $fp come reg base per accedere all’area di att.

IF:

THEN:

ELSE:

.eqv

RA, -4

// spi ra salvato (risp. a fp)

.eqv

S0, -8

// spi s0 salvato (risp. a fp)

sw

$ra, RA($fp)

// salva ind rientro

sw

$s0, S0($fp)

// salva reg s0 (varloc J)

move

$s0, $a1

// aggiorna varloc j

li

$t0, -1 (o addi $t0, $0, -1) // carica cost -1

bne

$s0, $t0, ELSE

// se j != -1 va’ a ELSE

move

$v0, $0 (o add $v0, $0, $0)

// prepara valusc

j

ENDIF

// va’ a ENDIF

la

$t0, VETT

// carica ind VETT

move

$t1, $a1

// copia arg i

sll

$t1, $t1, 2

// allinea indice

addu

$t0, $t0, $t1

// calcola ind elem

lw

$t1, ($t0)

// carica elem v[i]

sw

$t1, ($a0)

// aggiorna

addiu $sp, $sp, -4

// 1) decrementa reg sp

sw

$a1, ($sp)

// 2) salva param i (push)

addi

$a1, $a1, -1

// calcola i – 1

jal

F_RIC

// chiama f_ric

lw

$a1, ($sp)

// 3) ripristina param i (pop)

addiu $sp, $sp, 4 ENDIF:

p

// 4) incrementa reg sp

lw

$s0, S0(fp)

// ripristina reg s0

lw

$ra, RA($fp)

// ripristina ind rientro

// fine dell’uso di $fp per accedere all’area di attivazione lw

$fp, 8($sp)

addiu $sp, $sp, 12 jr

$ra

// ripristina fp chiamante // elimina area // rientra

Nota

bene:

l’istruzione

“lw

$fp,

8($sp)”

di

ripristino

del

registro

fp

potrebbe

essere

anche

scritta

semplicemente come “lw $fp, ($fp)”, con base ancora fp; nella prima forma però essa è chiaramente l’inverso dell’istruzione “sw $fp, 8($sp)” di salvataggio iniziale. Insomma:

come nell’esercizio

(registro base sp)

in alternativa

sw $fp, 8($sp) // salva fp

sw $fp, 8($sp) // salva fp (base sp)

lw $fp, 8($sp) // ripristina fp

lw $fp, ($fp) // ripristina fp (base fp)

Note varie:



il registro fp viene salvato e aggiornato nel prologo del chiamato (e dunque ripristinato nell’epilogo del chiamato), come prima operazione (ultima operazione), pertanto nel corpo della funzione i riferimenti al contenuto dell’area sono fatti con spiazzamento rispetto a fp (non rispetto a sp)



l’istruzione “li” è sostituibile con l’istruzione “addi” poiché la costante –1 da caricare è a solo 16 bit



la pseudo-istruzione “move” è facilmente espandibile tramite un’istruzione “addi”



formalmente il registro “s0” va salvato in pila a cura del chiamato, poiché è assegnato alla variabile locale “j”, ma giacché la funzione in realtà non lo modifica, ottimizzando molto si potrebbe evitare di salvarlo (così però deviando dal modello rigoroso di area di attivazione)



per il parametro “i” si vedano le considerazioni fatte nella prima soluzione



idem per il parametro “p”



AVVERTENZA: si badi bene che lo statement C di assegnamento “*p = vett [i]” USA il parametro puntatore “p”, ma non ne modifica il valore, ossia non cambia l’indirizzo che costituisce il valore di “p” ! ciò che viene modificato, assegnandogli il valore dell’elemento con indice “i” del vettore, è l’oggetto puntato da “p” (si riveda il punto precedente)



i registri temporanei “t0-t7” non vengono salvati (non vengono date indicazioni che la funzione si aspetti di poterli riavere inalterati dopo la chiamata ricorsiva)

Potrebbero esserci altre piccole ottimizzazioni di codice.

punto

4

– mappatura della memoria

Si considerino le ipotesi seguenti relative all’allocazione del programma in codice eseguibile in memoria:



il programma è collocato in memoria secondo il modello standard di MIPS, e l’ordine delle funzioni nel codice è prima main, poi f_ric

 

la dimensione di main è di

1024 byte

il valore del registro sp immediatamente prima che main effettui il passaggio di parametri alla prima invocazione di f_ric è pari a



0x 7FFF 0000

si ricorda che la memoria è indirizzabile a

byte

si chiedono: l’indirizzo della prima istruzione di main:

0x 0040 0000 (standard MIPS)

l’indirizzo della prima istruzione di f_ric:

0x 0040 0000

 1024 (dec)  0x 0040 0000  0x 0000 0400  0x 0040 0400

il valore di sp subito prima della seconda invocazione di f_ric:

0x 7FFF 0000

 (12  4) dec  0x 7FFF 0000  0x 0000 0010  0x 7FFE FFF0

nota bene: subito prima della seconda invocazione di f_ric la pila ha la max estensione

il valore di sp relativo all’area di attivazione della seconda chiamata di f_ric:

0x 7FFE FFF0

 12 dec  0x 7FFE FFF0  0x 0000 000C  0x 7FFE FFE4

nota bene: l’area di attivazione di f_ric (senza estensione per il prologo del chiamante) ha dimensione 12 byte

esercizio linguaggio m acchina – esame 9 luglio 2015 – VARI ANTE I I prima parte – traduzione in assembler Si

deve

tradurre

in

linguaggio

macchina

simbolico

(linguaggio

assemblatore)

MIPS

il

frammento

di

programma C riportato sotto, costituito ...


Similar Free PDFs