View Full Version : L'Intel 8086
MAURIZIO81
21-11-2002, 18:59
Ciao ragazzi!!
Mi sto accingendo a preparare l'esame di Sistemi di Elaborazione dove dovro' simulare il suddetto processore,ma il prof non avendo spiegato una ma..a,dovrò vedermela da solo.Ho studiato il manuele dell'8086 ma a quanto pare non serve a granchè :mad:
Potreste darmi del materiale o della dritte a proposito perche,sinceramente, non so da dove
cominciare!!!Almeno qualcosa che mi aiuti nella stesura dell'assemblatore,o dovrei cominciare dall'interprete???:confused: :confused:
Aiutatemi o dovrò laurearmi a 60 anni:D
MAURIZIO81
21-11-2002, 22:11
Dai ragazzi, fate i buoni....
Se non mi aiutate sono nella ....melma:D
In che linguaggio devi simulare l'8086 ?
Che cosa deve ricevere in pasto il tuo simulatore ? Codice assemblato o sorgente ?
Anche a me servirebbero spiegazioni a riguardo!
Io devo simulare il processore in linguaggio C.
La simulazione in se per se è una cavolata...
Basta dichiararsi i segmenti e i registri...
unsigned char code[65536];
unsigned char data[65536];
unsigned char stack[65536];
struct reg_s {
unsigned char ax[2];
unsigned char bx[2];
unsigned char cx[2];
unsigned char dx[2];
unsigned char si[2];
unsigned char di[2];
unsigned char sp[2];
unsigned char bp[2];
/*secondo me in una implementazione didattica
i registri segmento vanno messi solo per bellezza */
unsigned short cs;
unsigned short ds;
unsigned short ss;
unsigned short es;
unsigned short ip;
unsigned short flag;
} regs;
Ad esempio...l'esecuzione di MOV AL, DS:[BX] sarà una semplice operazione di questo genere :
regs.ax[0] = *(data + (((unsigned short)regs.bx[1]) << 8) + (unsigned short)regs.bx[0]);
Il problema più grosso è l'intepretazione del sorgente...più facile se il sorgente non è assemblato...più difficile se è assemblato...
Vi faccio vedere anche come automatizzare la costruzione del risultato avendo come parametri registri diversi...
Vi fate una funzione di questo tipo :
inline unsigned short toWord(unsigned char *addr]
{
return ((unsigned short)*(addr+1)) << 8) + (unsigned short)*addr;
}
Questa funzione è utile sia per avere il valore a 16 bit contenuto in un registro che per ottenere il valore a 16 bit contenuto a partire da una locazione di memoria...
unsigned char *source;
unsigned char *dest;
int size; /*grandezza in byte degli operandi*/
Riconoscete che si tratta di una MOV...
Riconoscete che l'operando destinazione è un registro a 8 bit (size = 1)... Una volta riconosciuto il registro assegnate a dest l'indirizzo del registro :
se è al o ax (in questo caso size sarebbe 2) : opcode = regs.ax;
se è ah : opcode = regs.ax +1;
Riconoscete che il sorgente è un indirizzo del segmento dati...
Riconoscete che viene usato un registro per indirizzare il dato :
source = toWord(regs.bx);
Ora serve la vera e propria esecuzione :
for(i = 0; i < size; ++i)
*(dest+i) = *(source+i);
Ho usato questo metodo per permettere l'esecuzione delle MOV a 8 o 16 bit con lo stesso codice...
Ad esempio MOV DS:[456], BP :
size = 2;
dest = data + 456;
source = regs.bp;
L'esecuzione resta la stessa scritta sopra...
Per gli operandi immediati basta crearsi un'altra specie di registro virtuale che contiene il valore dell'operando immediato...
inline void toByte(unsigned short imm, unsigned char *data)
{
data[0] = imm & 0x00FF;
data[1] = (imm & 0xFF00) >> 8;
}
unsigned char imm[2];
Ad esempio per MOV AX, 2 :
size = 2;
dest = regs.ax;
toByte(2, imm);
source = imm;
L'esecuzione resta uguale a prima...
Per le altre istruzioni la decodifica degli oeprandi resta la stessa...cambia solo l'esecuzione...
Ad esempio per ADD AX, 2 :
size = 2;
dest = regs.ax;
toByte(2, imm);
source = imm;
La fase di esecuzione della ADD funziona in questo modo :
toByte(toWord(source) + toWord(dest), dest);
Grande!! Sei stato molto gentile a rispondere.
L'interpretazione del sorgente dovra essere fatta dall'assemblatore che dovremmo costruire anche noi.
Quindi in pratica dovremmo:
- Fare un qualunque programmino in Assembler dell'8086
- Farlo tradurre in binario dall'assemblatore
- Infine interpretarlo con il simulatore.
Questo è lo schema generale che dovrei svolgere almeno per quanto mi riguarda.
Per l'assemblatore... Deve rispecchiare il linguaggio macchina della Intel o puoi farti un linguaggio intermedio ?
MAURIZIO81
23-11-2002, 10:54
Grazie cionci!!!Sei stato molto esplicativo
Tutto è molto,molto utile anche se per me la tua spiegazione è ad un livello già più avanzato!!!!
Studierò al più presto ciò che mi hai postato.;) ;)
Comunque per l'assemblatore devo rispecchiare il linguaggio dell'Intel.
Ma come fai a sapere tutte queste notiziuole???
Hai forse un manuale da propormi???
Grazie mille ;)
Ho solo immaginato come fare un simulatore di una CPU niente di più...
Ma per la forma del file assemblato ? Non deve essere un file eseguibile...vero ?
Mi fai un esempio di sorgente che deve essere possibile assemblare ? Come definisci i segmenti codice e dati ?
Per l'assemblatore io lo farei in 2 passaggi...
Prendiamo per esempio questo codice sorgente (mi sono inventato la sintassi dei segmenti) :
.DATA
Vett BYTE 10 DUP(0) ;Un vettore pieno di 0
Indice BYTE 0H ;Indice inizializzato a 0
END .DATA
.CODE
Ciclo:
INC Indice
CMP Indice, 10
JB Ciclo
END CODE
Primo passaggio : si individua la lunghezza delle istruzioni (basta individuare l'istruzione e la posizione delle etichette nel segmento dati nel segmento codice...
Nel frattempo secondo me conviene riscrivere il sorgente in una versione intermedia...
.DATA
0000 BYTE 10 DUP(FAH) ;Un vettore di 10 elementi pieno di FA
000A BYTE 0H ;Indice inizializzato a 0
END .DATA
.CODE
0000 MOV BX, Indice
0004 INC Vett[BX]
0008 INC Indice
000C CMP Indice, 10
00F0 JB Ciclo
END CODE
Ho supposto le lunghezze delle istruzioni (solo della MOV sono sicuro che sia 4 byte)...
In memoria ti dovrai costruire due tabelle...una per le etichette del segmento dati...una per le etichette del segmento codice...
Etichette Dati
Vett 0000
Indice 000A
Etichette codice
Ciclo 0000
Volendo puoi scrivere queste tabelle nel file intermedio... Ti potrebbe tornare utile (molti assemblatori lo fanno)...
Ora il secondo passaggio : costruire il file assemblato...
Qui se non si devono rispettare le specifiche per i file OBJ si fa molto presto... Fissiamo la dimensione del nostro segmento dati a 65536...
Scriviamo il segmento dati...
FAFAFAFAFAFAFAFAFAFA00 e dopo tutti 0 fino a 65535...
Ora bisogna scrivere il segmento codice e quindi fare la traduzione vera e propria...
Qui vi serviranno le due tabelle che vi siete creati in memoria per tradurre le etichette in numeri...
Ad esempio INC Vett[BX]... L'istruzione che dovete tradurre è questa INC CS:[BX + 0000]...
Le tabelle di traduzione in linguaggio macchina la potete trovare sul sito Intel...
Dopo per caricare ils egmento dati e il segmento codice in memoria basterà caricare i primi 65536 in data[65536] e il segmento codice in code [65535]...
Inizializzare regs.ip a 0, bp a 0 e sp a 65535 e cominciare l'esecuzione (facendo la traduzione inversa)...
MAURIZIO81
23-11-2002, 19:39
Allora tanto per cominciare il mio Simulatore dovrà ricevere in pasto un codice in assembler che per esempio dovrà eseguire una somma tra numeri o una moltiplicazione.E non sarà un file eseguibile!
Il suddetto simulatore dovra, come primi step:
1)Costruire una tabella dei simboli in cui inserire etichette,codici in binario e prossima etichetta da leggere
2)Costruire il file oggetto.
Il problema è che questo secondo step mi risulta abbastanza difficile!!!!La dimensione di 65535 per il nostro segmento dati è arbitraria o è di tale lunghezza per qualche motivo???
Grazie mille per i tuoi preziosissimi suggerimenti cionci! ;)
Allora il sorgente dovrà essere semplice ? Bene...
La larghezza di 65536 non è arbitraria, ma è la grandezza reale di un segmento indirizzabile a 16 bit...
La tabella dei simboli è quella che ho scritto prima (quella con le etichette)...
Confermo comunque i passaggi di prima...
1) Leggi riga per riga il codice e scrivi il file intermedio che contiene la posizione all'interno del segmento di ogni riga (per fare questo devi riconoscere il tipo istruzione per il segmento codice e la dimensione dei dati per il segmento dati)...
2) Mano a mano che leggi le etichette ti fai la tabella dei simboli che associa una etichetta alla sua posizione all'interno del segmento...
3) Scrivi il segmento dati nel file oggetto...scrivendo il valore specificato, altrimenti ci metti 0... Realmente non ci viene messo zero...e il segmento dati non viene scritto nel file oggetto...ma nel file oggetto viene scritta la dimensione del segmento dati (puoi appunto scegliere di farla sempre 65536) e le istruzioni per inizializzare la memoria ai valori specificati...
Volendo puoi seguire anche questa strada...basta scrivere nel file oggetto l'equivalente di 10 MOV per inizializzare il vettore Vett di prima...
Magari questa strada potrebbe anche risultare più bella (il file oggetto risulterebbe molto più piccolo)...
Le varie etichette e la loro posizione non viene scritta nel file oggetto perchè vengono tradotte con la rispettiva posizione nel codice...
4) Scrivi il segmento codice... Traduci ogni istruzione con il rispettivo codice operativo e i vari operandi...
Se trovi un'etichetta nel linguaggio macchina dovrai scrivere il rispettivo valore... Le Jump e i Loop sono near (cioè lavorano all'interno del segmento corrente)...non mi ricordo se nel linguaggio macchina devi scrivere la posizione assoluta dell'etichetta o la posizione relativa rispetto alla posizione corrente (posizione istruzione - posizione etichetta)...
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.