/* project.h */

#ifndef SEEN_PROJECT_H
#define SEEN_PROJECT_H

#include <stdio.h>

/* Possible argument types */
typedef enum {
	A_IMM4,			/* Four-bit integer (0 - 15) */
	A_IMM16,		/* Sixteen-bit integer (0 - 65535) */
	A_NREG,			/* Normal register */
	A_BREG,			/* BCD register */
	A_PREG			/* Pseudoregister */
} arg_type_t;

/* An argument to an instruction */
typedef struct arg_t {
	unsigned pos;		/* Position within the instruction word */
	unsigned width;		/* Number of bits to represent argument */
	arg_type_t type;	/* Argument type */
} arg_t;

/* Function capable of emulating an instruction */
typedef void (*insn_func_t)(unsigned, unsigned, unsigned);

/* Instruction types */
typedef enum {
	I_NORMAL,		/* Normal instruction; takes one tick */
	I_MEMORY		/* Memory instruction; takes four ticks */
} insn_type_t;

/* Instruction definition */
typedef struct insn_t {
	char* name;		/* Mnemonic */
	unsigned opcode;	/* Low sixteen bits */
	insn_type_t type;	/* Type of instruction */
	insn_func_t func;	/* Function to simulate instruction */
	arg_t arg1;		/* Argument #1 */
	arg_t arg2;		/* Argument #2 */
	arg_t arg3;		/* Argument #3 */
} insn_t;

/* Possible register types */
typedef enum {
	R_NORMAL,		/* Normal register */
	R_BCD,			/* BCD register */
	R_PSEUDO		/* Pseudoregister */
} reg_type_t;

/* Register definition */
typedef struct reg_t {
	char* name;		/* Name of register (sans $) */
	unsigned code;		/* Four-bit register encoding */
	reg_type_t type;	/* Register type */
	unsigned val;		/* Value stored in register */
} reg_t;

/* Label */
typedef struct label_t {
	char* name;		/* Label name */
	unsigned addr;		/* Label address */
} label_t;

/* register.c */
extern reg_t* reg_by_name(char* name);
extern reg_t* reg_by_code(unsigned code, reg_type_t type);
extern unsigned reg_read(reg_t* reg);
extern void reg_write(reg_t* reg, unsigned val);

/* memory.c */
extern unsigned mem_read(unsigned addr);
extern void mem_write(unsigned addr, unsigned val);
extern void mem_load_image(char* filename);

/* instruction.c */
extern insn_t* insn_by_name(char* name);
extern insn_t* insn_by_code(unsigned code);
extern unsigned insn_encode(insn_t* insn,
		unsigned arg1, unsigned arg2, unsigned arg3);
extern void insn_decode(unsigned code, insn_t** insn,
		unsigned* arg1, unsigned* arg2, unsigned* arg3);

/* label.c */
extern char* label_add(char* name, unsigned addr);
extern label_t* label_by_name(char* name);
extern label_t* label_by_addr(unsigned addr);
extern label_t* label_before_addr(unsigned addr);
extern label_t* label_after_addr(unsigned addr);
extern void label_reset(void);
extern void label_load_map(char* filename);

/* main.c */
extern int main(int argc, char** argv);
extern void die(const char* format, ...);

/* asm.c */
extern void asm_assemble(char* source, char* image, char* map);
extern void asm_label_decl(char* name);
extern void asm_expr(unsigned val);
extern unsigned asm_reg(char* name);
extern unsigned asm_insn(char* name, unsigned arg1, unsigned arg2, unsigned arg3);
extern unsigned asm_label(char* name);

/* vm.c */
extern void vm_simulate(char* image, char* map);
extern void set_trace_mode(int flag);
extern void dump_memory(unsigned start, unsigned end);
extern void dump_regs(void);
extern void vm_read(unsigned nreg1, unsigned nreg2, unsigned imm16);
extern void vm_disp(unsigned nreg1, unsigned nreg2, unsigned imm16);

/* grammar.y */
extern int yynerrs;

/* scanner.l */
extern FILE* yyin;
extern void yyerror(char* s);
extern void scanner_reset(void);

#endif

/* EOF */

