#pragma once

#include <common.h>
#include <instructions.h>

typedef struct {
    u8 a;
    u8 f;
    u8 b;
    u8 c;
    u8 d;
    u8 e;
    u8 h;
    u8 l;
    u16 pc;
    u16 sp;
} cpu_registers;

typedef struct {
    cpu_registers regs;

    //current fetch...
    u16 fetched_data;
    u16 mem_dest;
    bool dest_is_mem;
    u8 cur_opcode;
    instruction *cur_inst;

    bool halted;
    bool stepping;

    bool int_master_enabled;
    bool enabling_ime;
    u8 ie_register;
    u8 int_flags;
    u16 inst_pc;
} cpu_context;

typedef struct {
    cpu_context ctx;
} cpu_state;

void cpu_save_state(cpu_state*);
void cpu_load_state(const cpu_state*);

void fetch_instruction(cpu_context *ctx);

void cpu_init();
bool cpu_step();

typedef void (*IN_PROC)(cpu_context *);

IN_PROC inst_get_processor(in_type type);

#define CPU_FLAG_Z BIT(ctx->regs.f, 7)
#define CPU_FLAG_N BIT(ctx->regs.f, 6)
#define CPU_FLAG_H BIT(ctx->regs.f, 5)
#define CPU_FLAG_C BIT(ctx->regs.f, 4)

cpu_context *cpu_get_context();

u16 cpu_read_reg(reg_type rt);

void cpu_set_reg(reg_type rt, u16 val);

u8 cpu_read_reg8(reg_type rt);

void cpu_set_reg8(reg_type rt, u8 val);

void fetch_data(cpu_context*);

u8 cpu_get_ie_register();
void cpu_set_ie_register(u8 ie);

cpu_registers *cpu_get_regs();

u8 cpu_get_int_flags();
void cpu_set_int_flags(u8 value);

void inst_to_str(cpu_context *ctx, char *str);

void cpu_set_flags(cpu_context *ctx, int8_t z, int8_t n, int8_t h, int8_t c);
