SOTTOPROGETTO MIC-2
Lo scopo di questo progetto e' l'estensione del set d'istruzioni
IJVM
da utilizzare nella scrittura di programmi. Le nuove istruzioni da
realizzare
sono di tre tipi: istruzioni logico-aritmetiche, gestione di array
statici globali ed istruzioni di shift.
ISTRUZIONI LOGICO-ARITMETICHE
Estendere IJVM con le seguenti istruzioni:
INEG
(Integer Negate). Questa istruzione, il cui codice operativo e' 0x74,
effettua la negazione della parola in cima allo stack. Subito prima
della sua esecuzione, INEG
si aspetta di trovare in cima allo stack il valore da negare.
L'esecuzione di INEG prevede la rimozione dallo stack del valore da
negare e la
scrittura in cima allo stack del risultato.
IMUL
(Integer MULtiplication). Questa istruzione, il cui codice operativo
e' 0x68,
effettua una moltiplicazione tra due parole. Subito prima della sua
esecuzione, IMUL si aspetta
di trovare in cima allo stack due valori che specificano i fattori
da moltiplicare.
L'esecuzione di IMUL prevede la rimozione dallo stack dei due valori
prima menzionati,
e la scrittura in cima allo stack del risultato della moltiplicazione
senza il controllo di eventuali overflow.
IDIV
(Integer DIVision). Questa istruzione, il cui codice operativo e' 0x6c,
effettua la divisione tra due parole. Subito prima della sua esecuzione,
IDIV si aspetta
di trovare in cima allo stack due valori che specificano il dividendo
ed il
divisore (il divisore è in cima allo stack)
L'esecuzione di IDIV prevede la rimozione dallo stack dei due valori
prima menzionati,
e la scrittura in cima allo stack del risultato intero della divisione.
IREM
(Integer REMinder). Questa istruzione, il cui codice operativo e' 0x70,
effettua la divisione tra due parole. Subito prima della sua esecuzione,
IREM si aspetta
di trovare in cima allo stack due valori che specificano il dividendo
ed il
divisore (il divisore è in cima allo stack)
L'esecuzione di IREM prevede la rimozione dallo stack dei due valori
prima menzionati,
e la scrittura in cima allo stack del resto della divisione intera.
ISTRUZIONI PER GESTIONE ARRAY
Per l'implementazione delle istruzioni per la gestione degli array,
supporre
che il riferimento all'array sia memorizzato nel constant pool (ossia
supporre
che esso rappresenti uno scostamento da CPP) e che la relativa locazione
nel constant pool contenga l'indirizzo di memoria a partire dal quale
si trovano,
uno di seguito all'altro, gli elementi dell'array. Supporre inoltre
che l'indice di
un elemento dell'array rappresenti uno scostamento da tale indirizzo.
ESEMPIO: se abbiamo un array V di 4 elementi in memoria centrale a partire
dall'indirizzo 0x5000 la situazione della memoria centrale sara':
MEMORIA INDIRIZZO
|_____0x5000____| 0x4000 < CPP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
:::::::::::::::
|_____0x23B4____| 0x5000
|_____0x123A____| 0x5001 ARRAY V
|_____0xDA80____| 0x5002 DI 4 ELEMENTI
|_____0x12F2____| 0x5003
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
:::::::::::::::
|_______________| 0x8000 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
L'indice di un elemento dell'array si intende come scostamento da 0x5000
per cui,
V[0]=0x23B4 (ovvero la parola a scostamento 0 da 0x5000)
V[1]=0x123A (ovvero la parola a scostamento 1 da 0x5000)
V[2]=0xDA80 (ovvero la parola a scostamento 2 da 0x5000)
V[3]=0x12F2 (ovvero la parola a scostamento 3 da 0x5000)
ISTRUZIONE DI CARICAMENTO DA ARRAY
- IALOAD (Integer Array LOAD). Questa istruzione, il cui codice operativo
e' 0x2E, carica un elemento di un array in cima allo stack. Subito
prima della sua
esecuzione, IALOAD si aspetta di trovare in cima allo stack il riferimento
all'array (indirizzo del primo elemento) e l'indice dell'elemento da
caricare.
L'esecuzione di IALOAD ha come effetto la rimozione dallo stack dei
due dati
prima menzionati, il calcolo dell'indirizzo dell'elemento da caricare,
e la scrittura
in cima allo stack del valore di tale elemento.
ESEMPIO: se in un programma IJVM vogliamo caricare in cima allo stack
l'elemento
V[2] allora dobbiamo scrivere un frammento di codice del tipo
.constant
V 0x5000
.end-constant
.......
LDC_W V
BIPUSH 2
IALOAD
.......
ottenendo per lo stack (dopo le prime due istruzioni)
|____0x5000_____|
|____0x0002_____| 0x8002 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
e dopo IALOAD
|____0xDA80__-__| 0x8001 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
ISTRUZIONE DI SCRITTURA IN UN ARRAY
- IASTORE (Integer Array STORE). Questa istruzione, il cui codice operativo
e` 0x4F, carica il valore in cima allo stack in un elemento di un array.
Subito prima della sua esecuzione, IASTORE si aspetta di trovare in
cima allo
stack il riferimento all'array, l'indice dell'elemento in cui caricare
il valore, e il
valore. L'esecuzione di IASTORE prevede la rimozione dallo stack dei
tre dati
prima menzionati, il calcolo dell'indirizzo dell'elemento su cui caricare
il valore,
e la scrittura del valore nell'indirizzo precedentemente calcolato.
ESEMPIO: se vogliamo assegnare a V[3] il valore in cima allo stack (ad
esempio,
0x1D1A) allora lo stack prima dell'esecuzione di IASTORE deve essere
|____0x5000_____|
|____0x0003_____|
|____0x1D1A_____| 0x8003 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
dopo l'esecuzione di IASTORE si otterra'
:::::::::::::::
|_____0x23B4____| 0x5000
|_____0x123A____| 0x5001 ARRAY V
|_____0xDA80____| 0x5002 DI 4 ELEMENTI
|_____0x1D1A ___| 0x5003
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
:::::::::::::::
|_______________| 0x8000 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
ISTRUZIONI DI SHIFT
- ISHL (Integer SHift Left). Questa istruzione, il cui codice operativo
e' 0x78,
effettua uno shift a sinistra. Subito prima della sua esecuzione, ISHL
si aspetta
di trovare in cima allo stack due valori che specificano rispettivamente
l'oggetto
e la dimensione dello shift.
L'esecuzione di ISHL prevede la rimozione dallo stack dei due valori
prima menzionati,
lo shift a sinistra del primo valore di s bit dove s e' dato dai 5
bit meno
significativi del secondo valore, e la scrittura in cima allo stack
del risultato
dello shift.
ESEMPIO: se vogliamo effettuare uno shift a sinistra di 3 posizioni
della parola
0x0020 allora sullo stack deve esserci
|____0x0020_____|
|____0x0003_____| 0x8002 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
dopo l'esecuzione di ISHL lo stack sara'
|____0x0100_____| 0x8001 < SP --------
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
|_______________|
- ISHR (Integer Shift Right). Questa istruzione, il cui codice operativo
e' 0x7A,
effettua uno shift a destra preservando il segno. Subito prima della
sua esecuzione,
ISHR si aspetta di trovare in cima allo stack due valori che specificano
rispettivamente
l'oggetto e la dimensione dello shift. L'esecuzione di ISHR prevede
la rimozione dallo
stack dei due valori prima menzionati, lo shift a destra del primo
valore (con estensione
del segno) di s bit dove s e' dato dai 5 bit meno significativi del
secondo valore, e la
scrittura in cima allo stack del risultato dello shift.
- IUSHR (Integer Unsigned Shift Right). Questa istruzione, il cui codice
operativo
e' 0x7C, effettua uno shift a destra senza preservare il segno. Subito
prima della sua
esecuzione, IUSHR si aspetta di trovare in cima allo stack due valori
che specificano
rispettivamente l'oggetto e la dimensione dello shift.
L'esecuzione di IUSHR prevede la rimozione dallo stack dei due valori
prima menzionati,
lo shift a destra del primo valore (con estensione 0) di s bit dove
s e` dato dai 5 bit
meno significativi del secondo valore, e la scrittura in cima allo
stack del risultato
dello shift.
COME PROCEDERE
Per poter ottenere un set di istruzioni esteso e' necessario agire su due fronti:
1) Permettere che l'assemblatore di programmi IJVM riconosca come parte
del set di
istruzioni le nuove istruzioni. A tal fine bisogna modificare il file
ijvm.conf nella
cartella mic2001; questo file contiene una riga per ogni istruzione
IJVM dove viene
specificato il codice mnemonico, il codice operativo in esadecimale
ed eventuali
argomenti. Questo file e' usato dall'assemblatore ijvmasm per produrre
un file
che l'emulatore puo' caricare nella sua rappresentazione della memoria
centrale
dell'architettura.
P.S. se il file ijvm.conf non fosse modificabile con un editor di testi
allora
selezionare la sua icona con il tasto destro del mouse, scegliere la
voce proprieta'
e deselezionare la casella "solo lettura" dalla sezione attributi.
2) Modificare opportunamente il microinterprete (memorizzato nel file
mic1ijvm.mal da
scaricare dalla pagina del software) affinche' realizzi correttamente
il fetch e
l'esecuzione delle 5 nuove istruzioni.
COME VERIFICARE LA CORRETTEZZA DELL'IMPLEMENTAZIONE
Per le istruzioni di shift e per le istruzioni aritmetiche potete usare
il seguente schema di
programma IJVM variando a piacimento i valori e le istruzioni usate.
Si deve:
- salvarlo in un file con l'estensione .jas
- assemblarlo con ijvmasm (l'equivalente di mic1asm per i programmi
IJVM)
- tradurre il vostro microinterprete modificato
- con l'emulatore, caricare il micro interprete (File->Load Microprogram)
- con l'emulatore, caricare il vostro esempio (File->Load Macroprogram)
- eseguire il programma con run e verificare il risultato sullo stack
////////////////////////////////////////
// --- Start program ---
.constant
VALUE_TO_SHIFT 0x0A10 // Notazione per ii numeri esadecimali
NUMBER_OF_SHIFT 7 // Notazione per ii numeri decimali
.end-constant
.main
LDC_W VALUE_TO_SHIFT // push sullo stack del valore da shiftare
LDC_W NUMBER_OF_SHIFT // push sullo stack del numero di shift
ISHL // oppure ISHR o IUSHR
HALT
.end-main
// --- End program ---
COMPITI D'ESAME
Per questo esercizio dovete consegnare una relazione che contenga,
- microinterprete commentato
- commenti sul trattamento delle nuove istruzioni
- file di definizione del set di istruzioni commentato
- descrizione sintetica delle prove effettuate