#include #include #include #include #include "config.h" #include "alu.h" #include "simulator.h" #include "interne.h" #include "registre.h" #include "memoire.h" #include "fpu.h" #include "exceptions.h" #include "linker.h" #include "terminal.h" int HasToRun = 1, HasToReset = 0, debug = 0; Uint32 base_addr = 0; Uint32 LireInstruction(void) { return (LD(LireRegistrePC())); } void IncrementeCompteurOrdinal(void) { EcrireRegistrePC(AdditionNonSigne(LireRegistrePC(), 1)); } static FILE *openfilereading(char *name) { FILE *f; if (!(f = fopen(name, "rb"))) { pushcontext(strerror(errno)); exception(1, _("Error reading file")); } return f; } static Uint32 readword(FILE * f) { Uint32 a; if (fread(&a, sizeof(a), 1, f) != 1) { exception(1, _("premature end of file")); } return a; } Uint32 Adresse(Uint32 u, Uint32 instruction) { Uint32 tmp; switch (champ(u, 4)) { case 0: exception(1, _("Adresse: Call With Invalid r/m Field State ( r/m=00 )")); return (0); case 1: tmp = LireInstruction(); IncrementeCompteurOrdinal(); return (tmp); case 2: return (LireRegistre(Champ3(instruction))); /* Adresse dans registre */ case 3: tmp = LireRegistre(Champ3(instruction)) + LireInstruction(); /* Adresse dans registre + decalage de nouvelle instruction */ IncrementeCompteurOrdinal(); return (tmp); default: exception(1, _("Adresse: Unmatched Addr Field")); return (0); } } void Initialisation(void) { int i; InitMemoire(); for (i = 0; i < TAILLE_MEMOIRE; i++) Reset(&memoire_principale[i]); EcrireRegistre(0, 0); EcrireRegistreSP(ADD_SP); /* initialisation du stack pointer */ } void Flush(void) { FlushMemoire(); } void DecodeExec(Uint32 instruction) { Uint32 champ_registre_resultat, val1, val2, resultat; int test1, test2; Uint32 val; /* valeur qui va etre stockée */ if (Opcode(instruction) & 0x80) { fpu(Opcode(instruction)); } else { switch (Opcode(instruction)) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* ALU */ champ_registre_resultat = Champ1(instruction); /* Champ du registre dans lequel va etre stocké le résultat */ val1 = LireRegistre(Champ2(instruction)); /* Premier entier qui va etre utilisé dans l'opération */ if (Opcode(instruction) < 6) { if (ValeurBit(Extension(instruction), 0) == 0) val2 = LireRegistre(Champ3(instruction)); /* Deuxième entier, stocké dans un registre, qui va etre utilisé dans l'opération */ else { val2 = LireInstruction(); /* Deuxième entier, stocké après l'instruction, qui va etre utilisé dans l'opération */ IncrementeCompteurOrdinal(); } } if (ValeurBit(Extension(instruction), 1) == 0) { /* Teste si l'opération est signée ou pas */ switch (Opcode(instruction)) { case 0: resultat = AdditionNonSigne(val1, val2); break; case 1: resultat = SoustractionNonSigne(val1, val2); break; case 2: resultat = MultiplicationNonSigne(val1, val2); break; case 3: resultat = DivisionNonSigne(val1, val2); break; case 4: resultat = AND(val1, val2); break; case 5: resultat = OR(val1, val2); break; case 6: resultat = SHL(val1); break; case 7: resultat = SHR(val1); break; } } else { switch (Opcode(instruction)) { case 0: resultat = AdditionSigne(val1, val2); break; case 1: resultat = SoustractionSigne(val1, val2); break; case 2: resultat = MultiplicationSigne(val1, val2); break; case 3: resultat = DivisionSigne(val1, val2); break; case 4: resultat = AND(val1, val2); break; case 5: resultat = OR(val1, val2); break; case 6: resultat = SHL(val1); break; case 7: resultat = SHR(val1); break; } } if ((Opcode(instruction) & 2) && !(Opcode(instruction & 3))) { EcrireRegistreRG(resultat); EcrireRegistreRD(SecondResult); } else { EcrireRegistre(champ_registre_resultat, resultat); /* On écrit le résultat dans le registre de sortie */ } break; case 8: /* MOV */ if (ValeurBit(Extension(instruction), 4) == 1) { /* MOV conditionnel */ if (ValeurBit(Extension(instruction), 5) == 0) { /* Test normal */ switch (champ(Extension(instruction) >> 2, 4)) { /* teste les bits 2 et 3 */ case 0: if (Overflow() == 1) goto fin; case 1: if (Zero() == 1) goto fin; case 2: if (Sign() == 1) goto fin; case 3: if (Parity() == 1) goto fin; } } else { /* Negation du test */ switch (champ(Extension(instruction) >> 2, 4)) { /* teste les bits 2 et 3 */ case 0: if (Overflow() == 0) goto fin; case 1: if (Zero() == 0) goto fin; case 2: if (Sign() == 0) goto fin; case 3: if (Parity() == 0) goto fin; } } } /* Pas de MOV conditionnel */ if (ValeurBit(Extension(instruction), 1) == 0) { /* Mov arg1 arg2 */ if (ValeurBit(Extension(instruction), 0) == 0) { /* arg2 = reg */ if (champ(Champ1(instruction), 2) == 0) { /* r/m de arg1 = 0 */ EcrireRegistre(Champ3(instruction), LireRegistre(Champ2(instruction))); } else { ST(Adresse(Champ1(instruction), instruction), LireRegistre(Champ2(instruction))); } } else { /* arg2 = imm32 */ if (champ(Champ1(instruction), 2) == 0) { /* r/m de arg1 = 0 */ EcrireRegistre(Champ3(instruction), LireInstruction()); IncrementeCompteurOrdinal(); } else { val = Adresse(Champ1(instruction), instruction); ST(val, LireInstruction()); IncrementeCompteurOrdinal(); } } } else { /* mov arg2, arg1 */ if (ValeurBit(Extension(instruction), 0) == 0) { /* arg2 = reg */ if (champ(Champ1(instruction), 2) == 0) { /* r/m de arg1 = 0 */ EcrireRegistre(Champ2(instruction), LireRegistre(Champ3(instruction))); } else { EcrireRegistre(Champ2(instruction), LD(Adresse(Champ1(instruction), instruction))); } } else { /* arg2 = imm32 */ exception(1, _("MOV: Memory to Memory Forbidden On This Type Of Processor")); } } fin: break; case 9: /* NOP */ /* Instruction nulle */ break; case 10: /* J[cond] */ case 11: switch (champ(Extension(instruction), 4)) { case 0: if (Champ1(instruction) == Champ2(instruction)) { test1 = 1; } else { test1 = LireRegistre(Champ1(instruction)) == LireRegistre(Champ2(instruction)); } break; case 1: test1 = LireRegistre(Champ1(instruction)) != LireRegistre(Champ2(instruction)); break; case 2: test1 = LireRegistre(Champ1(instruction)) < LireRegistre(Champ2(instruction)); break; case 3: test1 = LireRegistre(Champ1(instruction)) <= LireRegistre(Champ2(instruction)); break; } switch (champ(Extension(instruction) >> 2, 4)) { case 0: test2 = Overflow(); break; case 1: test2 = Zero(); break; case 2: test2 = Sign(); break; case 3: test2 = Parity(); break; } switch (champ(Extension(instruction) >> 4, 4)) { case 0: test1 = test1; break; case 1: test1 = test1 || test2; break; case 2: test1 = test1 && !test2; break; case 3: test1 = test1 || !test2; break; } if (test1) { Uint32 tmp; tmp = LireInstruction(); if (Opcode(instruction) & 1) { tmp += LireRegistrePC(); } EcrireRegistrePC(tmp); } else { IncrementeCompteurOrdinal(); } break; case 12: /* JMP */ case 13: if (ValeurBit(Extension(instruction), 0) == 0) { /* RET */ EcrireRegistreSP(AdditionNonSigne(LireRegistreSP(), Champ1(instruction))); EcrireRegistreSP(AdditionNonSigne(LireRegistreSP(), 1)); EcrireRegistrePC(LD(LireRegistreSP())); } else if (ValeurBit(Extension(instruction), 1) == 0) { /* JMP */ if (ValeurBit(Extension(instruction), 2) == 0) { EcrireRegistrePC(LireRegistre(Champ1(instruction))); } else { EcrireRegistrePC(LireInstruction()); } } else { /* CALL */ ST(LireRegistreSP(), LireRegistrePC()); EcrireRegistreSP(SoustractionNonSigne(LireRegistreSP(), 1)); if (ValeurBit(Extension(instruction), 2) == 0) { EcrireRegistrePC(LireRegistre(Champ1(instruction))); } else { EcrireRegistrePC(LireInstruction()); } } break; case 14: /* PUSH */ if (ValeurBit(Extension(instruction), 0) == 0) val = LireRegistre(Champ1(instruction)); else { val = LireInstruction(); IncrementeCompteurOrdinal(); } ST(LireRegistreSP(), val); EcrireRegistreSP(SoustractionNonSigne(LireRegistreSP(), 1)); break; case 15: /* POP */ EcrireRegistreSP(AdditionNonSigne(LireRegistreSP(), 1)); EcrireRegistre(Champ1(instruction), LD(LireRegistreSP())); break; case 127: /* HALT-RESET */ if (ValeurBit(Extension(instruction), 0) == 0) { HasToRun = 0; /* Halt */ } else { HasToReset = 1; /* Reset */ ResetRegistres(); } break; default: exception(1, _("DecodeExec: Invalid Opcode")); } } } void AfficheReg(void) // affiche reg { int i, j; for (i = 0; i <= 3; i++) { for (j = 0; j < 8; j++) { fprintf(stderr, " R%02d ", (i * 8 + j)); } fprintf(stderr, "\n"); for (j = 0; j < 8; j++) { fprintf(stderr, "%08lX ", (registre[i * 8 + j])); } fprintf(stderr, "\n"); } fprintf(stderr, "Rg: %08lX | Rd: %08lX | Flag: %08lX | PC: %08lX\n", LireRegistreRG(), LireRegistreRD(), LireRegistreFLAG(), LireRegistrePC()); } void Debogueur(void) { int out = 0; Uint32 instruction = LireInstruction(); while (!out) { AfficheReg(); fprintf(stderr, "Opcode: %02X, extension: %02X, champ1: %02X, champ2: %02X, champ3: %02X\n", Opcode(instruction), Extension(instruction), Champ1(instruction), Champ2(instruction), Champ3(instruction)); fprintf(stderr, "%08lX:%08lX > ", LireRegistrePC(), instruction); switch (fgetc(input)) { case 'G': case 'g': fprintf(stderr, "Go\n\n"); debug = 0; out = 1; break; case 'p': case 'P': fprintf(stderr, "Proceed\n\n"); out = 1; break; case 'R': case 'r': break; case 'Q': case 'q': clearterm(); exception(1, _("Shutdown requested")); default: fprintf(stderr, _("Help:\nG: go\nP: Proceed\nR: display registers\nQ: quit\n")); } } } void Traitement(Uint32 entrypoint) { Uint32 instruction; while (HasToRun) { EcrireRegistrePC(entrypoint); HasToRun = 1; HasToReset = 0; while ((HasToRun) && (!HasToReset)) { if (debug) { initterm(); Debogueur(); clearterm(); } instruction = LireInstruction(); IncrementeCompteurOrdinal(); DecodeExec(instruction); } } } void ChargeBinaire(char *filename) { FILE *file; char message[BUFSIZ]; Uint32 entrypoint, nb, ns, nbss, nr, *relocation_table; int i; file = openfilereading(filename); if (readword(file) != 0x58454e4e) { /* verification de la signature */ exception(1, _("Invalid Signature")); } sprintf(message, _("Loading file %s"), filename); pushcontext(message); readword(file); entrypoint = readword(file); /* point d'entrée */ nb = readword(file); /* taille du segment text */ ns = readword(file); /* taille des donnes statiques */ nbss = readword(file); /* taille des donnees non init */ nr = readword(file); /* taille de la table de relogement */ relocation_table = (Uint32 *) Emalloc(nr * sizeof(Uint32)); for (i = 0; i < nr; i++) { relocation_table[i] = readword(file); } for (i = base_addr; i < (base_addr + nb + ns); i++) { /*chargement en ram de .text et .data */ ST(i, readword(file)); } for (i = 0; i < nr; i++) { /* relogement */ ST(base_addr + relocation_table[i], LD(base_addr + relocation_table[i]) + base_addr); } free(relocation_table); entrypoint += base_addr; EcrireRegistre(28, base_addr + nb); EcrireRegistre(30, base_addr + nb + ns + nbss); base_addr += nb + ns + nbss; fclose(file); popcontext(); sprintf(message, _("Executing file %s"), filename); pushcontext(message); Traitement(entrypoint); popcontext(); base_addr -= nb + ns + nbss; }