Les emulateurs - principes part 2

Emulation du processeur

Representation des registres en C,principes

En C il est aise de definir des structures.On utilisera donc un type de donnee proche du type REGS (ceux qui connaissent un peu le C sur PC doivent connaitre cette structure) pour definir la globalite des registres.Par exemple:
typedef register_68000
{
int D0,D1,D2,D3,D4,D5,D6,D7; // registres de donnes
int A0,A1,A2,A3,A4,A5,A6,A7; // registres d'adresse
int flag; // registre flag
int PC; // programm counter
int USP,SSP; // registres de piles (! idem A7)
} register_68000;

Ensuite pour emuler le processeur il faut faire dans l'ordre:

  • Recuperer l'opcode de l'instruction via PC
  • Identifier l'opcode de l'instruction
  • Recuperer le ou les operandes correspondant a l'opcode
  • Modifier les registres si lieu est
  • Modifier les flags
  • Modifier les adresses memoires
  • Incrementer Programm Counter a l'instruction suivante
  • Reiterer le procede pour l'instruction suivante

    Reperage de l'opcode

    Generalement l'instruction se presente sous la forme
    Opcode (8 bits 16 bits,32 bits....)Operande1Operande2....Opcode suivant

    On extrait donc l'opcode dans une variable,mettons OPCODE
    On extrait le pointeur sur l'operande suivante mettons POPERANDE=PC+sizeof(OPCODE)
    Tout le travail consiste a identifier l'opcode: Pour cela on peut utiliser une methode brutale:
    if (OPCODE=code1) {... traiteemnt de l'opcode code1}
    else if (OPCODE=code2) {.. traitement de l'opcode code2}
    ...
    else {... traitement du dernier opcode ...}
    Cette methode est peu optimise puisque quand on arrive a l'opcode k, on a effectue k comparaisons !! On a interet a placer les instruction les plus utilisee en debut de test !!!
    Il est possible d'optimiser de facon a n'avoir que n comparaisons pour 2^n opcodes !!!
    En effet on peut masquer chacun des bits de l'opcode et effectuer une sorte d'arbre binaire dictionnaire.Par exemple pour un opcode sur 4 bits (desole a vous de le faire pour 32 :))) )
    if (opcode&0x8)
    {if (opcode&0x4)
    { if (opcode&0x2)
    {if (opcode&0x1){...traite opcode 0xF}
    else {traite opcode 0xE}}
    else
    {if (opcode&0x1){...traite opcode 0xD}
    else {traite opcode 0xC}}}
    else
    { if (opcode&0x2)
    {if (opcode&0x1){...traite opcode 0xB}
    else {traite opcode 0xA}}
    else
    {if (opcode&0x1){...traite opcode 0x9}
    else {traite opcode 0x8}}}}
    else
    {if (opcode&0x4)
    { if (opcode&0x2)
    {if (opcode&0x1){...traite opcode 0x7}
    else {traite opcode 0x6}}
    else
    {if (opcode&0x1){...traite opcode 0x5}
    else {traite opcode 0x4}}}
    else
    { if (opcode&0x2)
    {if (opcode&0x1){...traite opcode 0x3}
    else {traite opcode 0x2}}
    else
    {if (opcode&0x1){...traite opcode 0x1}
    else {traite opcode 0x0}}}}

    C'est chiant a ecrire !! Mais le jeu en vaut la chandelle !!! Plus que 4 comparaisons pour identifier chaque instruction !!!!

    Extraire les operandes et traiter le code

    Le nombre d'operandes depend de l'opcode. Neanmoins il faut extraire les opcodes et placer le PC apres la derniere opcode extraite !!!
    On utilise POPERANDE, pour cela !!!

    On ecrit en memoire les resultats et on modifie les flags !!!

    Gestion de la memoire

    tous les pointeur PC,Adresse etc... sont relatifs au CPU emul , mais pas a la machine qui effectue l'emulation. On peut utiliser plusieurs methodes pour reprensenter la memoire de la machine.
    On distinguera le cas ou la machine a peu de RAM (64k) comme le CPC 464 et l'utilise de maniere lineaire.
    A ce moment la,ont peut utiliser un tableau lineaire de memoire, comme
    char* memoireCPC464=(char*)malloc(65536);

    Sinon on utilise une structure complexe: Ondivise la memoire en section ou pages, par exemple sur amiga on pourra diviser la memoire en plusieurs tableaux: ChipMem,SlowMem,Customchips,CIAs FastMem,... que l'on stockera separement.
    Puis au sein de l'emulateur on retournera pour une adresse memoire de la machine emulee un pointeur sur une case memoire reelle de la memoire de la machine qui emule.Par exemple:
    void* memory_mapping(int mem_emule);
    ...
    *((short*)memory_mapping(0xdff180))=0xFFF;

    En fait (short*)memory_mapping(0xdff180) sera un pointeur sur un case memoire reelle representant le customchip 0xdff180 (registre couleur 0 su AMIGA !!)


    Retour a la page principale