
#ifndef WAL_BCE_JSY_H
#define WAL_BCE_JSY_H


/*
 * For the BCE_JSY_* worker family the following macros must be defined:
 * WAL_BCE_JSY_*_MAX_SIMD
 * WAL_BCE_JSY_*_DMEM_NUM_MEMORIES
 * WAL_BCE_JSY_*_CMEM_NUM_MEMORIES
 * WAL_BCE_JSY_*_SMEM_NUM_MEMORIES
 * wal_BCE_JSY_*_description_structure
 */

/* worker family ID */
/**
 * enum wal_bce_jsy_family_ids - family identifications in the BCE_JSY group of families
 */
enum wal_bce_jsy_family_ids {
    WAL_BCE_JSY_ID_UNKNOWN = 0,
    //WAL_BCE_JSY_ID_TRIVIAL = 1,
    WAL_BCE_JSY_ID_GENERIC_3D = 1,
    WAL_BCE_JSY_ID_GENERIC_4D = 2,
};


// Position of info register in PB CFG Memory, Output region (which starts at the word 0x80)
#define WAL_BCE_JSY_INFO_REG_ADDR    1
// Position of work register in PB output memory
// #define WAL_BCE_HK_WORK_REG_ADDR    254

#define WAL_BCE_JSY_ID_FAMILY_MASK   0x0000ff00
#define WAL_BCE_JSY_ID_FAMILY_SHIFT   8
#define WAL_BCE_JSY_ID_DFUKIND_MASK     0x000000ff
#define WAL_BCE_JSY_ID_DFUKIND_SHIFT    0
/*
 *
 */
#define wal_bce_jsy_family(id)          (((id) & WAL_BCE_JSY_ID_FAMILY_MASK) >> WAL_BCE_JSY_ID_FAMILY_SHIFT)
#define wal_bce_jsy_dfukind(id)         (((id) & WAL_BCE_JSY_ID_DFUKIND_MASK) >> WAL_BCE_JSY_ID_DFUKIND_SHIFT)
#define wal_bce_jsy_extid_num_ags(id)   ( ((id) >> 16) & 0x0f )
#define wal_bce_jsy_extid_num_idxags(id)        ( ((id) >> 20) & 0x0f )
#define wal_bce_jsy_extid_num_dtmems(id)        ( ((id) >> 8) & 0xff )

/* control memories */
// #define WAL_BCE_JSY_TRIVIAL_CMEM_NUM_MEMORIES    WAL_CMEM_NUM_MEMORIES
#define WAL_BCE_JSY_GENERIC_3D_CMEM_NUM_MEMORIES    WAL_CMEM_NUM_MEMORIES
#define WAL_BCE_JSY_GENERIC_4D_CMEM_NUM_MEMORIES     WAL_CMEM_NUM_MEMORIES

/* data memories */
#define WAL_BCE_JSY_MAX_SIMD     1
// #define WAL_BCE_JSY_TRIVIAL_MAX_SIMD     WAL_BCE_JSY_MAX_SIMD  /* must be defined for checking if registered worker doesn't want more than this */
#define WAL_BCE_JSY_GENERIC_3D_MAX_SIMD     WAL_BCE_JSY_MAX_SIMD  /* must be defined for checking if registered worker doesn't want more than this */
#define WAL_BCE_JSY_GENERIC_4D_MAX_SIMD     WAL_BCE_JSY_MAX_SIMD  /* must be defined for checking if registered worker doesn't want more than this */

/**D
 * enum wal_bce_jsy_data_memories - indices to BCE_JSY data memories
 * @WAL_BCE_JSY_DMEM_A: index of the A data memory
 * @WAL_BCE_JSY_DMEM_B: index of the B data memory
 * @WAL_BCE_JSY_DMEM_C: index of the C data memory
 * @WAL_BCE_JSY_DMEM_D: index of the D data memory
 * @WAL_BCE_JSY_DMEM_NUM_MEMORIES: number of data memories in the BCE_JSY families
 */
enum wal_bce_jsy_data_memories {
        WAL_BCE_JSY_DMEM_A = 0,
        WAL_BCE_JSY_DMEM_B,
        WAL_BCE_JSY_DMEM_C,
        WAL_BCE_JSY_DMEM_D,
        WAL_BCE_JSY_DMEM_NUM_MEMORIES
};
// #define WAL_BCE_JSY_TRIVIAL_DMEM_NUM_MEMORIES    WAL_BCE_JSY_DMEM_NUM_MEMORIES
#define WAL_BCE_JSY_GENERIC_3D_DMEM_NUM_MEMORIES    WAL_BCE_JSY_DMEM_NUM_MEMORIES
#define WAL_BCE_JSY_GENERIC_4D_DMEM_NUM_MEMORIES    WAL_BCE_JSY_DMEM_NUM_MEMORIES

/* data memories length */
// #define WAL_BCE_JSY_TRIVIAL_DMEM_LENGTH          1024
#define WAL_BCE_JSY_GENERIC_3D_DMEM_LENGTH          1024
#define WAL_BCE_JSY_GENERIC_4D_DMEM_LENGTH          1024

/* support memories */
#define WAL_BCE_JSY_SMEM_NUM_MEMORIES    0
// #define WAL_BCE_JSY_TRIVIAL_SMEM_NUM_MEMORIES    WAL_BCE_JSY_SMEM_NUM_MEMORIES
#define WAL_BCE_JSY_GENERIC_3D_SMEM_NUM_MEMORIES    WAL_BCE_JSY_SMEM_NUM_MEMORIES
#define WAL_BCE_JSY_GENERIC_4D_SMEM_NUM_MEMORIES    WAL_BCE_JSY_SMEM_NUM_MEMORIES

/******************************************************************************/
/* BCE_JSY worker specific operations and capabilities */
/**
 * enum wal_bce_jsy_operation_codes - worker operations known to BCE_JSY group of families
 * @WAL_BCE_JSY_OP_VCPY: copy vector    M0[i] <= M1[j]
 * @WAL_BCE_JSY_OP_VADD: add vectors    M0[i] <= M1[j] + M2[k]
 */
enum wal_bce_jsy_operation_codes {
    /* the first op-code should start at WAL_OP_FIRST_USER_CODE */
    WAL_BCE_JSY_OP_VCPY   = 0x03,       /* copy vector    M0[i] <= M1[j]            */
    WAL_BCE_JSY_OP_VADD   = 0x04,       /* add vectors    M0[i] <= M1[j] + M2[k]    */
    WAL_BCE_JSY_OP_RUNX   = 0x05,       /* directly run an operation */
};

/* BCE_JSY worker capabilities */
/**
 * enum wal_bce_jsy_capabilities - BCE_JSY possible worker capabilities
 * @WAL_BCE_JSY_CAP_NONE: supported NONE :-)
 * @WAL_BCE_JSY_CAP_VCPY: supported VCPY
 * @WAL_BCE_JSY_CAP_VADD: supported VADD
 */
enum wal_bce_jsy_capabilities {
    WAL_BCE_JSY_CAP_NONE   = 0x00000000,
    WAL_BCE_JSY_CAP_VCPY   = 0x00000001,
    WAL_BCE_JSY_CAP_VADD   = 0x00000002,
};

/******************************************************************************/
/* BCE_JSY specific structures and functions */

/* aliases */
#define WAL_CMEM_INP            WAL_CMEM_MB2PB
#define WAL_CMEM_OUTP           WAL_CMEM_PB2MB

/** bit masks */
/* TAG = two bits (5 downto 4) in both the CFG Control and Status registers */
#define MASK_TAG                0x30            /* in ctrl and status cfg */
#define MASK_PM                 0x0C            /* program-select bits in ctrl reg */
#define SHIFT_PM                2               /* PM bits in ctrl reg are 3:2 */
#define TAG_01                  0x10
#define N_MASK_TAG              0xCF            /* inverted MASK_TAG */
/* Bit 'Go' (bit#0) in CFG Control register; Hardware-controlled. */
#define MASK_G                  0x01
/* Bit 'Running' (bit#0) in CFG Status register */
#define MASK_R                  0x01
/* Bit 'Busy' (bit#1) in CFG Status register */
#define MASK_B                  0x02
#define N_MASK_B                0xFD
#define MASK_BR                 0x03            /* (MASK_B|MASK_R) */
/* Bit 'Done' (bit#0) in DFU Status reg. */
#define MASK_Done               0x01
#define MASK_License            0x08

#define MASK_DATA               0xFF00

/* name of the CE description structure must be wal_<name of CE>_description_structure */
// extern const struct wal_family_desc wal_BCE_JSY_TRIVIAL_description_structure;
extern const struct wal_family_desc wal_BCE_JSY_GENERIC_3D_description_structure;
extern const struct wal_family_desc wal_BCE_JSY_GENERIC_4D_description_structure;


/******************************************************************************/
/* Common DFU specification */

/**
 * The following DFU operations are implemented in the DFU for SMECY
 */

#define NUM_DFUOPS              28

#define DFU_VCOPY  1    /* copy vector          mi(0)[i] <= mi(1)[j] */
#define DFU_VADD   2    /* add vectors          mi(0)[i] <= mi(1)[j] + mi(2)[k] */
#define DFU_VMUL   3    /* mul vectors          mi(0)[i] <= mi(1)[j] * mi(2)[k] */
#define DFU_VMAC   4    /* multiple-accumulate   mi(0)[i] <= (mi(1)[j] * mi(2)[k]) + mi(3)[l]  */
#define DFU_DPROD  5    /* Dot Product          mi(0)[0] <= Sum(mi(1)[j] * mi(2)[k]) */
#define DFU_VSUB     6  /* Vector subtraction                     mi(0)[i] <= mi(1)[j] - mi(2)[k] */
#define DFU_VSUM     7  /* Summation                              mi(0)[0] <= Sum(mi(1)[i] - mi(2)[i]) */
#define DFU_VCMPLT   8  /* Vector less-than comparison            mi(0)[i] <= (mi(1)[i] < mi(2)[i]) ? 0xffff_ffff : 0x0000_0000 */
#define DFU_VSAD     9  /* Vector square-add                      mi(0)[i] <= mi(2)[j] + ( mi(1)[k] * mi(1)[k] ) */
#define DFU_VMAX     10 /* Maximum value in a vector              mi(0)[0] <= MAX(mi(1)[i]) */
#define DFU_VMIN     11 /* Minimum value in a vector              mi(0)[0] <= MIN(mi(1)[i]) */
#define DFU_INDEXMAX 12 /* Index of the maximal value in a vector mi(0)[0] <= INDEXMAX(mi(1)[i]) */
#define DFU_INDEXMIN 13 /* Index of the minimal value in a vector mi(0)[0] <= INDEXMIN(mi(1)[i]) */
#define DFU_VSQR     14 /* Vector square                          mi(0)[i] <= mi(1)[j] * mi(1)[j] */
#define DFU_VSELECT  15 /* Selection                              mi(0)[i] <= (mi(1)[j] != 0x0000_0000) ? mi(2)[k] : mi(3)[l] */
#define DFU_VGTE     16 /* Vector element-wise greater or equal   mi(0)[i] <= (mi(1)[j] < mi(2)[k]) ? mi(2)[k] : mi(1)[j] */
#define DFU_VLTE     17 /* Vector element-wise lesser or equal    mi(0)[i] <= (mi(1)[j] < mi(2)[k]) ? mi(1)[j] : mi(2)[k] */
#define DFU_VBAND    18 /* Vector element-wise binary AND         mi(0)[i] <= BITWISE_AND(mi(1)[j], mi(2)[k]) */
#define DFU_VBOR     19 /* Vector element-wise binary OR          mi(0)[i] <= BITWISE_OR(mi(1)[j], mi(2)[k]) */
#define DFU_VBNOT    20 /* Vector element-wise binary NOT         mi(0)[i] <= BITWISE_NOT(mi(1)[j]) */
#define DFU_VCONVR   21 /* Convert RED color to float             mi(0)[i] <= color2float(mi(1)[j], 3) */
#define DFU_VCONVG   22 /* Convert GREEN color to float           mi(0)[i] <= color2float(mi(1)[j], 2) */
#define DFU_VCONVB   23 /* Convert BLUE color to float            mi(0)[i] <= color2float(mi(1)[j], 1) */
#define DFU_VMSUBAC  24 /* multiple-accumulate   mi(0)[i] <= mi(3)[l] - (mi(1)[j] * mi(2)[k])  */
#define DFU_VAND3E   25 /* Logical AND between three consecutive elements */
#define DFU_VAND3V   26 /* Logical AND between three elements with the same index */
#define DFU_VOR3E    27 /* Logical OR between three consecutive elements */
#define DFU_VOR3V    28 /* Logical OR between three elements with the same index */

/* returns textual name of the DFU operation */
// FIXME: the DFU operations should depend on DFU kinds!
const char *dfuop2str(int dfuop);

//-- DFU Kinds
#define DFK_NONE                0
//-- constant DFK_TRIVIAL_INTEGER  : dfu_kind_t := 1;             not supported
#define DFK_INTEGER_SMECY_VIDEO 1
#define DFK_INTEGER             2
#define DFK_FLOAT_ALL           3
#define DFK_FLOAT_SMECY_VIDEO   4
#define DFK_FLOAT_SMECY_H       5

// #define DFK_FLOAT_VIRTEX5    3
// #define DFK_FLOAT_SPARTAN6   4
// #define DFK_FLOAT_VIRTEX5_A7 7
// #define DFK_FLOAT_VIRTEX5_A6 8
// #define DFK_FLOAT_VIRTEX5_A5 9
// #define DFK_FLOAT_VIRTEX5_A4 10
// #define DFK_FLOAT_VIRTEX5_A3 11
// #define DFK_FLOAT_VIRTEX5_A2 12
//
// #define DFK_FLOAT_VIRTEX5_A3_M2         13
// #define DFK_FLOAT_VIRTEX5_A4_M3         14
// #define DFK_FLOAT_VIRTEX5_A5_M3         15
//
// #define DFK_FLOAT_VIRTEX6_A6_M3         16
// #define DFK_FLOAT_VIRTEX6_A5_M6         17
// #define DFK_FLOAT_VIRTEX6_A4_M3         18
// #define DFK_FLOAT_VIRTEX6_A3_M2         19
// #define DFK_FLOAT_VIRTEX6_A6_M6         20
//
// #define DFK_FLOAT_SPARTAN6_A3_M4        21
// #define DFK_FLOAT_SPARTAN6_A4_M6        22
// #define DFK_FLOAT_SPARTAN6_A5_M7        23
// #define DFK_FLOAT_SPARTAN6_A6_M11       24
// #define DFK_FLOAT_SPARTAN6_A2_M4        25
// #define MAX_DFUKIND             25

#define MAX_DFUKIND             5

/* return textual name of the DFU kind */
const char *dfukind2str(int dfk);

/* returns true if the DFU is floating */
int dfukind_is_float(int dfk);

/* utility macro: terminates program when a WAL call fails */
#define CALLWAL(res)            do { int __res = (res); if (__res != WAL_RES_OK) { printf("CALLWAL FAILED '" # res "' at " __FILE__ ":%d; result=%d\n", __LINE__, __res); exit(1); } } while (0)


#endif
