#ifndef CPU_H_INCLUDED
#define CPU_H_INCLUDED

#include"mem.h"


#define NUM_INST 14



enum instruction{INVALID = 0x0,   //INVALID     00 00 00 00 Instrucao invalida
                 READ = 0x1,      //READ     	00 01 00 00 Le uma palavra do dispositivo de entrada (o console) para o acumulador
                 WRITE = 0x2,     //WRITE    	00 02 00 00 Escreve um valor armazenado no acumulador no dispositivo de saida (o console)
                 LOAD = 0x3,      //LOAD POS	    00 03 XX XX Carrega para o acumulador uma palavra da memoria no endereco XX especificado pelos ultimos dois digitos
                 STORE = 0x4,     //STORE POS	00 04 XX XX Armazena na memoria, no endereco XX, a palavra contida no acumulador
                 ADD = 0x5,       //ADD	POS     00 05 XX XX Adiciona o valor no endereco de memoria XX ao valor no acumulador
                 SUB = 0x6,       //SUB	POS     00 06 XX XX Subtrai o valor no endereco de memoria XX do valor no acumulador
                 MUL = 0x7,       //MUL	POS     00 07 XX XX Multiplica o valor no acumulador pelo valor no endereco de memoria XX
                 DIV = 0x8,       //DIV	POS     00 08 XX XX Divide o  valor no acumulador pelo valor no endereco de memoria XX
                 MOD = 0x9,       //MOD	POS     00 09 XX XX Determina o resto da divisao do valor no acumulador pelo valor no endereco de memoria XX
                 BRANCH = 0xa,    //BRANCH	    00 0A XX XX Transfere o fluxo de execucao para o endereco  de memoria XX
                 BRANCHNEG = 0Xb, //BRANCHNEG	00 0B XX XX Transfere o fluxo para o endereco XX caso o valor no acumulador seja negativo
                 BRANCHZERO = 0xc,//BRANCHZERO	00 0C XX XX Transfere o fluxo para o endereco XX caso o valor no acumulador seja igual a zero
                 HALT = 0xd};     //HALT	    00 0D 00 00 Aborta o programa

typedef enum instruction instruction_t;

struct decode {char * inst_name;
               word_t opcode;} decode;


struct _cpu
{
    memory_t mem;
    word_t acc;
    int pc;

};

typedef struct _cpu cpu_t;

/*
Nunca defina vari‡veis globais em um header (arquivo .h). Declare como extern
e defina em um arquivo .c
*/

/* Array contendo pares <nome_instrucao, codigo_instrucao> */
extern struct decode decode_list[NUM_INST];

/* retorna um opcode, isto e, uma palavra de memoria com a instrucao e o operando */
word_t getOpcodeCPU(const cpu_t cpu);

/* Inicia o funcionamento da CPU, zera o contador de programa e limpa a memoria */
void init(cpu_t *cpu);

/* Roda um programa previamente carregado na memoria da CPU*/
void run(cpu_t *cpu);

void exec(cpu_t *cpu);

/* Sai da cpu */
void exitCPU(const cpu_t cpu);

/* Mostra o conteudo da CPU */
void dumpCPU(const cpu_t  cpu);

/* Le um arquivo com um programa em linguagem de montagem e compila gerando um codigo objeto*/
void assembleProgram(char *src_file_name, char *obj_file_name);

/* Carrega em memoria os bytes de um programa executável*/
void loadProgram(cpu_t *cpu, char *file_name);



#endif // CPU_H_INCLUDED
