Animazione del simulatore MIC-2
Basandoci sulla teoria sopra esposta è possibile adesso passare ad una descrizione sommaria dell'applet che implementa l'animazione del simulatore MIC-2.
Si vuole realizzare un'applet Java che mostri il funzionamento del MIC-2 basandosi su 2 esempi di programma IJVM. L'applet deve mostrare il datapath con tutti i suoi registri, l'ALU, lo Shifter e i 3 bus. Inoltre bisogna mostrare anche L'IFU in 2 modalità che l'utente può selezionare: in modo aperto (dettagliato) e in modo nascosto. Bisogna anche mostrare tutti i collegamenti che l'unità principale di esecuzione ha con l'IFU. L'utente in ogni momento deve essere informato (tramite qualche area di testo) delle operazioni appena svolte dall'unità principale di esecuzione. Ma non è tutto! Si deve far veder l'andamento grafico del clock e il Control Store. Sarà necessario mostrare anche il registro MIR e l'istruzione nel Control Store puntata dal registro MPC. L'utente deve anche vedere la method area su richiesta e sempre l'utente deve decidere quale dei due esempi caricare tramite un pannello di controllo. L'utente può pilotare l'unità principale di esecuzione grazie ad un pannello di bottoni in modo che ogni singola microistruzione può essere eseguita interamente (1 ciclo di clock) oppure dettagliatamente (4 sottocicli di clock) con la visualizzazione grafica del flusso di dati tra le varie parti. Deve essere possibile cambiare esempio in qualunque momento, resettare i registri, tornare indietro di una microistruzione (operazione utile ai fini dell'analisi dei risultati). Infine sarebbe meglio disporre di alcune form espletative che chiariscano all'utente i punti più importanti sull'architettura e sul funzionamento dell'applet.
Le misure dell'applet sono 1024x700. I files utilizzati dall'applet sono diversi e ciascuno implementa gli oggetti necessari per il raggiungimento degli obiettivi. Diamo di seguito una carrellata alle varie classi.
ClockPanel
Implementa il pannello che realizza e gestisce graficamente il clock. Il metodo più importante è Colck_sub_cycle(int subCycle) che seleziona in base al sottociclo che stiamo animando (subCycle) quale tratto di di curva illuminare di verde nella figura.
ControlStore
Implementa un pannello contenente una textarea che a sua volta contiene la lista delle microistruzioni del mic2. L'utente non può interagire con quest'oggetto, quindi è stata disattivata la gestione del muose sull'oggetto stesso. Il metodo più significativo di questa classe è SelectMpc(int mpc_val) che sposta a seconda del valore di mpc_val la barra selezionatrice sulla lista delle microistruzioni.
MemoryFrame
Implementa una finestra che visualizza la Method Area, il costruttore, infatti, contiene un campo pubblico <example> che verrà settato in Mic2Sim01. Se <example=0> allora la memoria conterrà delle informazioni irrilevanti "??" ad indicare che non è stato caricato alcun esempio. Se <example=1> allora verranno caricate le istruzioni relativi all'esempio 1, diversamente, se <example=2> verranno caricati le istruzioni relative all'esempio 2.
Ecco come appare nell'applet il pannello che rappresenta la memoria:
Fig. 3 - Method Area
Mic2Instruction
Questa classe implementa tutte le istruzioni del MIC-2. Innanzitutto si dichiara un vettore di tipo string: ex1[], successivamente ex1[] viene riempito dalle 81 microistruzioni. La prima microistruzione che interpreta una istruzione ISA è commentata dal nome dell'istruzione ISA stessa tra parentesi quadra.
Registri
Questa classe implementa ogni registro del MIC-2, compresi ovviamente i registri contenuti nell'IFU; queste variabili sono tutte di tipo String. Abbiamo aggiunto altre informazioni relative allo stato dei registri e sono:
boolean
read; //true se l'IFU deve effettuare una lettura dalla memoria
boolean rd; //true se si deve leggere dallo Stack
boolean wr; //true se si deve scrivere sullo Stack
boolean x2Mbr1; //è true se MBR1 viene letto 2 volte nel corso di una
singola istruzione, false altrimenti
Queste variabili serviranno al momento di decidere se illuminare MDR al ciclo successivo (ad indicare l'arrivo dei dati dallo stack) oppure segnare la marcatura su read nell'IFU ad indicare un'immediata lettura dalla method area e l'arrivo dei nuovi dati al ciclo successivo.
Mic2Sim01
Questa classe implementa l'applet vera e propria. Innanzitutto si dichiarano tutti i bottoni, le aree di testo, successivamente si stabiliscono le misure, il tipo di layout, la dimensione dei vari pannelli. Sul lato sinistro dell'applet abbiamo il pannello che riporta il clock, andando verso il basso troviamo un pannello con i primi 2 bottoni che servono ad aprire la finestra della method area e a nascondere (o svelare) l'IFU, i restanti 4 bottoni servono per aprire le finestre di info su memoria, IFU, Control-Store, e Prev.Step. Più in basso ancora abbiamo una textarea che rappresenta il control-Store. Il Clock e il Control Store sono delle classi discusse in precedenza che non facciamo altro che istanziare e inserire in un pannello proprio. MIR e NEXT MicroInstruction, sono 2 textfield e ad ogni ciclo o sottociclo vengono aggiornate rispettivamente con la microistruzione appena eseguita e la successiva da eseguire al prossimo step. La barra nel control store evidenzia sempre la microistruzione posta nel registro Next Microinstruction e cioè la prossima microistruzione che verrà processata. Infine abbiamo il pannello di controllo principale dell'applet che stabilisce quali dei 2 esempi caricare nella method area e da la possibilità di vedere le info relative e anche di uscire dall'applet se lo si desidera.
La seguente figura mostra la parte sinistra dell'applet con i relativi dettagli.
Fig. 4 - Inquadratura dell'applet: lato sinistro
Sul lato destro dell'applet abbiamo il data path del Mic-2 col relativo pannello di controllo. Per ragioni di semplicità grafica è stato necessario fondere alcune parti dell'IFU con il datapath, tuttavia i collegamenti fisici tra le varie parti dell'IFU sono riportati nei dettagli e saranno animati allo stesso modo in cui verrà animata l'unità principale di esecuzione.
Il metodo più significativo di quest'applet è:
public Registri Controlla(int step, boolean change_Istr, boolean sw);
dove step indica il passo di computazione, change_Istr e sw servono per stabilire ogni volta che viene chiamato il metodo se e quali parti tra MIR, NEXT MicroIstr. e Control Store devono essere aggiornate. Ad esempio la chiamata Controlla (23, true, false), aggiorna i registri del datapath allo stato successivo all'esecuzione del passo 23 di computazione del programma (cui corrisponde una ben precisa microistruzione), aggiorna il control Store alla successiva microistruzione da eseguire, nonchè i registri MIR e NEXT MicroInstruction. Poi l'applet viene gestita dal metodo:
public boolean action(Event ev, Object obj) //controllore di eventi dell'applet e interazioni con l'utente
che gestisce in modo completo tutti i bottoni e gli eventi che si possono verificare in seguito a ripetute operazione da parte dell'utente.
Mic2Anim
Quando viene premuto il tasto <clock sub cycle> la nostra applet deve animare il datapath e l'IFU per 4 cicli consecutivi di clock; durante questa fase verrà disattivato sia il bottone <step> che <prev.Step>. E' possibile animare consecutivamente premendo ripetute volte il bottone <Clock sub cycle> oppure direttamente eseguire in un ciclo intero di clock la microistruzione corrente senza animare.
Innanzitutto Mic2Anim definisce tutte le linee e le frecce che verranno evidenziate durante l'animazione, successivamente verranno aggiunte al datapath i textfields contenenti i valori dei registri (di tipo string). Per fare questa operazione ci serviamo di un metodo di nome ShowRegisters(Registri reg). I metodi IFUAnimation1, IFUAnimation2, IFUAnimation3, IFUAnimation4, controllano l'animazione nell'IFU a seconda del sottociclo in cui ci troviamo, mentre RdImar_IncrAnimation4 anima l'IFU al quarto sottociclo quando l'istruzione in questione è un "goto". Il metodo più importante di questa classe è sicuramente
StartAnimation(int select, Registri OldR, Registri NewR, int Microstep)
dove select individua il tipo di microistruzione, OldR è la configurazione attuale dei registri, NewR quella che dovrà avere dopo l'esecuzione della microistruzione e infine Microstep è il numero di sottociclo di clock (1, 2, 3, o 4). Molte Microistruzioni vengono animate allo stesso modo ed è per questo che i casi da gestire riportati nello Swich (select) sono molto inferiori rispetto al n. di tutte le possibili microistruzioni diverse. StartAnimation, in prima battuta, si prende cura di associare lo stesso valore a select quando 2 microistruzioni diverse vengono animate allo stesso modo (ciò fa risparmiare codice e fatica...). La variabile pubblica LOADMEM riferisce quali dei 2 esempi è stato caricato nella method area e indica dunque il set di microistruzioni che interpretano ciascuna istruzione ISA del programma in questione.
Quando select=1 ci troviamo al 1° sottociclo di clock e quindi illuminiamo le apposite frecce e coloriamo di verde lo sfondo dei registri interessati alla lettura; se per caso la microistruzione legge uno dei registri MBRx allora coloriamo anche lo shift. Quando select=2 è tempo di far viaggiare i dati dai registri attraverso i bus fino all'ALU; quando select=3 si colorano di rosso le unità di elaborazione, ovvero l'ALU e i sommatori (per incrementare PC e/o IMAR se necessario); infine quando select=4 i dati escono dallo shifter e viaggiano attraverso il bus C finchè non verranno scritti nei registri appropriati che contemporaneamente si coloreranno magenta. I registri MBRx possono essere scritti solo dall'IFU ed è per questo che la scrittura viene evidenziata con un colore diverso: il giallo. Il percorso animato dei dati avviene per mezzo di un rettangolino 3x3 pieno colorato di blu che in un loop infinito viene incrementato con un passo di 1pt alla volta. Al Thread di programma viene impostato un ritardo di 4 unità per rallentare la velocità del flusso.
Fig. 5 - Frammento del datapath animato e dell' I.F.U.
In coda a questa classe abbiamo i metodi che gestiscono la visualizzazione delle varie parti dell'applet, sia durante l'animazione che durante la fase di reset, cioè quando, una volta terminata l'animazione, tutti i colori devono ritornare a quelli iniziali. Da notare che l'applet ridisegna l'animazione ricordandosi il punto esatto da dove partire tutte le volte che la finestra principale viene spostata o ridotta ad icona oppure viene influenzata da eventi esterni che sovrappongono altre finestre alla finestra principale dell'applet.