
Compilatore
Il compilatore è stato realizzato al fine di agevolare la riscrittura e la codifica di programmi sorgenti. Al pari del resto del sistema anche tale programma è stato suddiviso in sottoprogrammi in modo da rendere la funzione main quanto più snella possibile; questo ha permesso di ritoccare il programma focalizzando senza problemi i punti di intervento. Oltre al file Compiler.c si sono realizzati i file header seguenti :
#include "myConstant.h" // dichiara le costanti degli operandi e di programma
#include "myVariable.h" // variabili globali
#include "myFunction.h" // dichiara funzioni matematiche IntToBin BinToInt EsaToInt...
#include "Compute.h" // funzioni di codifica delle istruzioni
Tale programma può essere eseguito anche in ambiente DOS e se ricompilato può essere eseguito anche con sistemi operativi differenti.
Per eseguire il programma è necessario passargli come parametro il file da compilare.
C:\Compiler prova.asm
Se la compilazione viene eseguita tramite il programma Editor.exe come parametro viene automaticamente passato il file sorgente del progetto caricato.
Dal nome del file passato vengono creati due nuovi file; il primo è il file di log (estensione *.clg) che viene creato ogni volta che viene avviata una compilazione indipendentemente dal fatto che questa abbia esito positivo o meno. In questo file vengono scritte tutte le operazioni che vengono svolte dal compilatore con relative segnalazioni di errore nel caso di interruzione[1]. Il secondo file generato (estensione *.hex) viene invece generato solo se la compilazione termina senza errori.
La prima operazione che viene svolta dal compilatore è la ricerca delle etichette e relativi indirizzi puntati, la logica seguita è “tutto ciò che non è un’istruzione è un’etichetta”. I valori trovati vengono memorizzati all’interno di una tabella così strutturata :
typedef struct
{
char label [LABEL_LEN]; // nome etichetta
short int target; // indirizzo puntato
} Record;
Record etichette[NUM_LABEL]; // record di etichette con relativi indirizzi puntati
Tale tabella permette, una volta creata, di fare salti sia all’indietro che in avanti in maniera più snella. L’operazione loggata come “Label Finder” non comporta ancora la compilazione di alcuna istruzione.
Durante questa scansione vengono trovati, eventualmente, una prima tipologia di errori di sintassi; questo viene fatto con l’ausilio della variabile flag che permette di evitare che siano presenti due label consecutive.
Creata la tabella dei riferimenti avviene la compilazione delle istruzioni precedentemente scansionate. Tale operazione viene svolta rileggendo il file dall’inizio saltando tutto ciò che non è un’istruzione, ovvero le label[2]. Una volta rilevata una istruzione viene richiamata la relativa funzione che la codificherà in linguaggio macchina; nel caso di una istruzione SUB si avrebbe :
SubAdd (prg,log,PrgMemory);
alla funzione viene passato il puntatore del file *.asm in modo da poter andare a leggere gli operandi, il puntatore del file di log *.clg in modo da poter aggiornare il file con le nuove operazioni svolte e il puntatore alla memoria RAM, precedentemente allocata tramite la funzione malloc, dove risiedono le istruzioni compilate (in formato long int).
La lettura delle istruzioni da compilare termina con la fine del file. Giunti a questo punto, la compilazione deve essere avvenuta correttamente altrimenti il processo verrebbe interrotto prematuramente con la relativa segnalazione d’errore, viene generato il file *.hex in formato compatibile con la funzione di accesso ai dati in file ASCII presente nelle librerie di ModelSim. All’interno di ogni funzione relativa alla codifica di un’istruzione avviene la rilevazione di ulteriori errori:
Miss parameter after the instruction add.
Viene segnalato per ogni istruzione se mancano dei parametri per fine file.
[label] is not recognize like any instruction.
Viene segnalato se dopo un’etichetta non viene trovata un’istruzione valida (ci sarebbero due label a puntare lo stesso indirizzo).
The label [ %s ] is not previously defined.
Viene segnalato durante la codifica del BRGT se l’etichetta di salto non è nella tabella dei riferimenti.
Shift position overflow.
Viene segnalato quando lo shift è maggiore di 31 (i registri sono comunque di 16 bit ma per lo shift si hanno comunque 5 bit a disposizione)
Immediate operator overflow.
Viene segnalato se si tenta di caricare, nelle istruzione MOVE e STORB un operando maggiore di 512.
One or more Registers file are not available.
Viene segnalato quando si fa involontariamente uso di un registro superiore a R15.
R14 is not a user Register file.
Viene segnalato quando si fa uso del registro R14
Quest’ultimo errore merita una nota in più. Si ricorda che l’istruzione BRGT non contiene tra gli operandi l’indirizzo a cui saltare, a causa del numero esiguo di bit a disposizione; l’indirizzo puntato dall’etichetta, contenuta tra gli operandi della BRGT, è contenuto in R14; tale indirizzo deve essere preventivamente caricato prima dell’istruzione BRGT. Questa operazione risulterebbe onerosa per il programmatore, per questo è stata mascherata dal compilatore che introduce una MOVE R14,[indirizzo] in maniera automatica. In questo modo il programmatore può effettuare salti in avanti o indietro facendo solo riferimento alle etichette da lui definite, ignorando il modo con cui verrà poi eseguita l’istruzione di BRGT.
Viene ora riportato un esempio di un semplice programma con relativo file di log.
loop move R0,#1
move R2,#30
move R3,#8
shiftl R3,R3,#2
loop1 sub R3,R3,R0
brgt loop1,R3,R2
return
Il file *.clg generato è il seguente:
Set Source file : Prova.asm
Open Source File : Prova.asm
************** LABEL FINDER **************
loop is set like a label.
Pointed Memory : 0
loop1 is set like a label.
Pointed Memory : 8
************ FINDER TERMINATED ************
*********** COMPILER OPERATIONS ***********
[ move R0,#1 ] instruction is compiling.
Destination Register : 0
Immediate operator : 1
Word compiled like : 1100000000000001
[ move R2,#30 ] instruction is compiling.
Destination Register : 2
Immediate operator : 30
Word compiled like : 1100010000011110
[ move R3,#8 ] instruction is compiling.
Destination Register : 3
Immediate operator : 8
Word compiled like : 1100011000001000
[ shiftl R3,R3,#2 ] instruction is compiling.
Destination Register : 3
Source 1 Register : 3
Shift position : 2
Word compiled like : 1110011001100010
[ sub R3,R3,R0 ] instruction is compiling.
Destination Register : 3
Source 1 Register : 3
Source 2 Register : 0
Word compiled like : 0010011001100000
[ brgt loop1,R3,R2 ] instruction is compiling.
Source 1 Register : 3
Source 2 Register : 2
The label is : loop1
Pointed Memory : 8
Word [ move ] compiled like : 1101110000001000ßistruzione move inserita dal compilatore
Word [ brgt ] compiled like : 0100011001011100
[ return ] instruction is compiling.
Word compiled like : 0110000000000000
*************** END COMPILE ***************
Hex File created.
Total lines compiled : 8
---------------------------------
Compiled program :
C001
C41E
C608
E662
2660
DC08
465C
6000
---------------------------------
Il file *.hex generato tiene conto del fatto che la memoria è a 8 bit.
width: 8
default: FF
0000: 01
0001: C0
0002: 1E
0003: C4
0004: 08
0005: C6
[…]
000D: 46
000E: 00
000F: 60
Per ulteriori dettagli sul programma si rimanda ai commenti presenti sul file sorgente.
[1] Oltre agli errori vengono loggate le varie fasi della compilazione permettendo di verificare, e questo è stato importane durante la stesura del programma, la correttezza degli operandi prelevati e della codifica svolta.
[2] Se si è giunti a questo punto della compilazione, senza interruzioni, dopo una label è sicuramente presente un’istruzione.