/**
 * Data structure definitions for microcode algorithm
 * 
 * @file microcode.h
 * @author Lukas Vykydal
 */

#include <stdio.h>
#include "linkedList.h"
#include <stdbool.h>
#include <tcl.h>


#ifndef __MICROCODE_H__
#define __MICROCODE_H__

#define __H__
#include "tcl.h"
#undef __H__ 

typedef enum mcOperationType{
  OP_READ      = 1,
  OP_WRITE     = 2,
  OP_READ_CHK  = 3,
  OP_WRITE_CHK = 4,
  OP_SMARCH    = 5,
  OP_SMARCH_CHK= 8,
  OP_DELAY     = 6,
  OP_NOP       = 7
} t_OperationType;

typedef enum mcDirection{
  DIR_NONE   = 0,
  DIR_UP     = 1,
  DIR_DOWN   = 2,
  DIR_SINGLE = 3
} t_Direction;

typedef enum mcAccess{
  ACCESS_NORMAL = 0,
  ACCESS_ROW    = 1,
  ACCESS_COL    = 2
} t_Access;

LINKEDLIST(Operation,
  t_OperationType      Type;
  int                  TestVector;
);

LINKEDLIST(Element,
  enum mcDirection     Direction;
  enum mcAccess        AddressAccess;
  t_Operation          *Operations;
);

LINKEDLIST(Definition, 
  char* Key;
  char* Value;
);

typedef struct Microcode {
  t_Element *MarchElements;
  t_Definition *Definitions;
} t_Microcode;

/**
 * Microcode instruction data type - same as in VHDL code
 */
//typedef struct MC_INSTR {
//  enum up_down {
//    c_DIR_UP,
//    c_DIR_DOWN
//  } col_up_down;
//  bool col_clr;
//  bool col_cnte;
//  
//  enum up_down row_up_down;
//  bool row_clr;
//  bool row_cnte;
//  
//  bool ncnt_cnte;
//  bool ncnt_clr;
//  
//  bool chkbrd_col;
//  bool chkbrd_row;
//  
//  enum {
//    c_MEM_OP_NONE,
//    c_MEM_OP_RD,
//    c_MEM_OP_WR
//  } mem_op;
//  int mem_data;
//  
//  enum {
//    c_JUMP_NOCOND,
//    c_JUMP_ROW_END,
//    c_JUMP_COL_END,
//    c_JUMP_NCNT_END
//  } jump_cond;
//  int next_adr;
//  int jump_adr;
//} t_MC_INSTR;


#define MC_INSTR_UP_DOWN        \
TCL_ENUM(MC_INSTR_UP_DOWN, {    \
  TCL_ENUM_ITEM(c_UP)           \
  TCL_ENUM_ITEM(c_DOWN)})

#define MC_INSTR_MEM_OP         \
TCL_ENUM(MC_INSTR_MEM_OP, {     \
  TCL_ENUM_ITEM(c_NOP)          \
  TCL_ENUM_ITEM(c_RD)           \
  TCL_ENUM_ITEM(c_WR)           \
  TCL_ENUM_ITEM(c_SMARCH)})

#define MC_INSTR_JUMP_COND      \
TCL_ENUM(MC_INSTR_JUMP_COND, {  \
  TCL_ENUM_ITEM(c_NO_COND)      \
  TCL_ENUM_ITEM(c_ROW_END)      \
  TCL_ENUM_ITEM(c_COL_END)      \
  TCL_ENUM_ITEM(c_NCNT_END)})

MC_INSTR_UP_DOWN
MC_INSTR_MEM_OP
MC_INSTR_JUMP_COND

#define MC_INSTR_DEF                     \
TCL_OBJECT(MC_INSTR, {                   \
  TCL_ITEM(MC_INSTR, t_MC_INSTR_UP_DOWN, col_up_down)      \
  TCL_ITEM(MC_INSTR, bool, col_clr)      \
  TCL_ITEM(MC_INSTR, bool, col_cnte)     \
                                         \
  TCL_ITEM(MC_INSTR,  t_MC_INSTR_UP_DOWN, row_up_down)      \
  TCL_ITEM(MC_INSTR, bool, row_clr)      \
  TCL_ITEM(MC_INSTR, bool, row_cnte)     \
                                         \
  TCL_ITEM(MC_INSTR, bool, chkbrd_col)   \
  TCL_ITEM(MC_INSTR, bool, chkbrd_row)   \
                                         \
  TCL_ITEM(MC_INSTR, t_MC_INSTR_MEM_OP, mem_op)      \
  TCL_ITEM(MC_INSTR,  int, mem_data)     \
                                         \
  TCL_ITEM(MC_INSTR,  int, smarch)       \
                                         \
  TCL_ITEM(MC_INSTR, t_MC_INSTR_JUMP_COND, jump_cond)     \
  TCL_ITEM(MC_INSTR,  int, next_adr)     \
  TCL_ITEM(MC_INSTR,  int, jump_adr)     \
})

MC_INSTR_DEF

LINKEDLIST(Microprogram,
  t_MC_INSTR instruction;
);

//Prototypes

t_Microcode *Microcode_ReadFile(FILE *fp);
char *Microcode_Export(t_Microcode *mc);
void Microcode_Destroy(t_Microcode *mc);

void Microcode_TclRegister(Tcl_Interp*);
#endif 
