#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>

// BEGIN CUT
// [Exercice sur emulator.h]
// 1. - PC : adresse de la prochaine intruction à exécuter
//    - regs ("registers") : registres généraux x0..x31
//    - memory : contenus de la mémoire
//    Sur un système réel, PC et regs sont cachés dans le CPU, memory est la
//    puce/barette de RAM (ROM/Flash acceptable aussi pour la partie contenant
//    le code sur certains systèmes embarqués).
// 2. MACHINE_MEMSIZE est en octets. memory est un tableau de int64_t, qui font
//    chacun 8 octets, donc pour avoir MACHINE_MEMSIZE octets en tout il faut
//    MACHINE_MEMSIZE / 8 éléments de type int64_t.
// 3. - lb: Load Byte (1 octet)
//    - lh: Load Halfword (2 octets)
//    - lw: Load Word (4 octets)
//    - ld: Load Doubleword (8 octets)
// 4. machine_luw(): Load Unsigned Word
//    machine_suw(): Store Unsigned Word
//    Le préfixe "machine_" groupe et identifie des fonctions qui manipulent
//    l'état de la machine émulée. C'est un peu comme des méthodes en POO.
//
// [Exercice sur *.c]
// 1. main.c s'occupe de l'interface CLI et la gestion des fichiers.
//    machine.c s'occupe de gérer l'état machine et d'émuler la mémoire.
//    emulate.c émuler le CPU, i.e. décode/exécute les instructions.
// 2. main.c appelle emulate.c
//    emulate.c appelle machine.c
//    La structure du projet est en fait assez rigide.
// 3. Les autres options sont un tableau statique ou une globale.
//    Tableau statique : trop grand (16 ko discutable à la limite mais sur un
//    vrai système en Mo, non—ou alors faut allouer la struct machine entière
//    sur le tas, ce qui revient un peu au même).
//    Globale : moche, et là y'a pas de raison particulière d'en mettre.
// 4. "file pointer, input" et "file pointer, output"
// 5. On ne peut pas exécuter à la volée parce qu'on passe plusieurs fois sur
//    les instructions à cause des sauts, du coup il faudrait (1) décoder les
//    instructions plusieurs fois, ce qui est inélégant, et (2) sauter en avant
//    et en arrière dans la lecture du fichier, ce qui est difficile si le
//    format n'est pas ultra rigide.
// END CUT

/* Émule le code hexadécimal de `fp_in` et produit le résultat final dans
  `fp_out` */
void emulate(FILE *fp_in, FILE *fp_out);

#define MACHINE_MEMSIZE 16384

/* Donnée pour la machine en cours d'exécution */
struct machine {
    uint32_t PC;
    int64_t regs[32];
    int64_t memory[MACHINE_MEMSIZE / 8];
};

/* Initialise l'état de la machine (mémoire vide, pointeur de pile...). */
void machine_init(struct machine *mach);

/* Lit une valeur non signée de 32 bits dans la mémoire à l'adresse `addr`. */
uint32_t machine_luw(struct machine *mach, uint32_t addr);

/* Écrit une valeur non signée de 32 bits à l'adresse `addr`. */
void machine_suw(struct machine *mach, uint32_t addr, uint32_t value);

/* Lit une valeur signée de 64 bits à l'adresse `addr`. */
int64_t machine_ld(struct machine *mach, uint32_t addr);

/* Écrit une valeur signée de 64 bits à l'adresse `addr`. */
void machine_sd(struct machine *mach, uint32_t addr, int64_t value);
