NOTA BENE: tutti i numeri esadecimali usati in questo testo sono
da considerarsi come numeri di 8 cifre (per ottenere 32 bit). Per
comodita', un numero del tipo 0x00003244 e'stato scritto omettendo
le cifre piu' significative uguali a 0, ovvero 0x3244.
 
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