#ifndef PBBCELIB_H
#define PBBCELIB_H

/**
 * enum dfu_fp01_operations - codes of operations supported by accelerator DFU_FP01
 *
 * These codes are used with functions %pb2dfu_start_op and %pd2dfu_restart_op
 * to select operation performed in the accelerator.
 */
#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_VMSUBAC  24 /* multiple-subtract    mi(0)[i] <= mi[3][l] - (mi(1)[j] * mi(2)[k]) */


/**
 * DFU Arguments / Address Generators.
 */
#define DFUAG_0         0x30
#define DFUAG_1         0x40
#define DFUAG_2         0x50
#define DFUAG_3         0x60

#define DFUAG_IDX_0     0x70
#define DFUAG_IDX_1     0x80
#define DFUAG_IDX_2     0x90
#define DFUAG_IDX_3     0xA0

/**
 * Physical Local memory banks.
 */
#define MBANK_A         0x00
#define MBANK_B         0x01
#define MBANK_C         0x02
#define MBANK_D         0x03

/**
 * Address generator flags/modes.
 * This is used in pb2dfu_set_agflags().
 * NOTE: The AGFL_USE_IDX and AGFL_STEP_IDXBND flags can be used independently.
 *       That is, it is possible to step the main AG by the boundary condition of the slave AG,
 *       while not using the indices received from it. However, the slave AG will still read data from
 *       the BRAM even if they are not used in the main AG.
 */
#define AGFL_USE_IDX            0x01    ///< Offset each address produced in the main AG by an index delivered from the slave AG.
#define AGFL_STEP_IDXBND        0x02    ///< Increment address of the main AG only when the slave AG is reaching the boundary.

/**
 * External opcodes incomming from MB,
 * as given in WAL
 */
/* General ops. */
#define WAL_OP_GETID    0
#define WAL_OP_GETCAP   1
#define WAL_OP_GETLIC   2
/* JSY ops. */
#define WAL_BCE_JSY_OP_VCPY   0x03       /* copy vector    M0[i] <= M1[j]            */
#define WAL_BCE_JSY_OP_VADD   0x04       /* add vectors    M0[i] <= M1[j] + M2[k]    */
#define WAL_BCE_JSY_OP_RUNX   0x05
/* special */
#define WAL_OP_NONE     0xFF


/* BCE IDs for the WAL_OP_GETID operation */
#define WAL_BCE_JSY_ID_GENERIC_3D  1
#define WAL_BCE_JSY_ID_GENERIC_4D  2

/* capabilities constants */
#define WAL_BCE_JSY_CAP_NONE    0x00000000
#define WAL_BCE_JSY_CAP_VCPY    0x00000001
#define WAL_BCE_JSY_CAP_VADD    0x00000002
#define WAL_BCE_JSY_CAP_RUNX    0x00000004


/***********************************/
/* functions for interfacing MB-PB */

/**
 * Exchange byte with microblaze using the barrier synchronization.
 * This function blocks.
 */
unsigned char mbpb_exchange_data(unsigned char data);

/**
 * Sets the R and B bits in the CFG Status register
 * to report that the firmware has sucessfully started and is busy.
 * This function does NOT block.
 * It should be called immediately when picoblaze starts up.
 * NOTE: This could be integrated into picoblaze C library
 * to be called automatically upon startup.
 */
void pb2mb_report_running();

/**
 * Write the BCE ID into the cfg output memory.
 */
void write_bce_id_to_cmem(unsigned char fam1);

/**
 * Write the whole DFU capabilities bitmap (256bits = 32 B = 8 words) into the cfg output memory,
 * starting at address 0x81 of the ctrl/status memory.
 */
void write_dfu_caps_to_cmem();

/**
 * Read u8 value from the BCE input cfg region.
 * @cfgaddr = word address in the config mem.
 * @byteidx = [0; 3] Byte index, 0 = LL, 3 = HH
 */
unsigned char read_bce_cmem_u8(unsigned char cfgaddr, unsigned char byteidx);

/**
 * Read u16 value from the BCE input cfg region.
 * @cfgaddr = word address in the config mem.
 * @widx = {0; 2} Word index, 0 = Lo, 2 = Hi
 */
unsigned int read_bce_cmem_u16(unsigned char cfgaddr, unsigned char widx);

/**
 * Write u16 value into BCE cfg memory.
 * The @cfgaddr shall be in the output status region, ie. 0x80 - 0xff.
 * @widx = {0; 2} Word index, 0 = Lo, 2 = Hi
 */
void write_bce_cmem_u16(unsigned char cfgaddr, unsigned char widx, unsigned int dt);

/**
 * Get the running time in clock-cycles of the last DFU operation executed.
 */
unsigned int pcnt_get_dfutime();

/**
 * Get the program running time in clock-cycles.
 * The counter is 32b in total, thus we provide two functions to access its lo/hi part.
 */
unsigned int pcnt_get_prgtime_lo();
unsigned int pcnt_get_prgtime_hi();

/**
 * Reset the program running-time counter.
 */
void pcnt_reset_prgtime();

/**
 *  read licence flag - The functions returns licence counter or a flag which indicates that the DFU licence is run out.
 */
unsigned int get_dfulic();

/************************************/
/* functions for interfacing PB-DFU */

/**
 * pb2dfu_wait4hw - PB will wait for end of computation
 *
 * The function waits for finishing computation in the accelerator.
 * The function should be called before subsequent run of the next
 * operation. The next operation can be prepared before the waiting
 * to speed up the entire computation.
 * Return Value: Zero if ok, Non-zero on DFU error
 */
unsigned char pb2dfu_wait4hw();

/**
 * pb2dfu_start_op - start operation in DFU with specified length of data vectors
 * @op: DFU operation (constants %DFU_OP_xxx)
 * @cnt: length of input data vectors
 *
 * The function covers two functions (pb2dfu_set_cnt and pb2dfu_restart_op).
 * Return Value: The function doesn't return any value.
 */
void pb2dfu_start_op(unsigned char op, unsigned int cnt);

/**
 * pb2dfu_restart_op - start operation in DFU
 * @op: DFU operation (constants DFU_OP_xxx)
 *
 * All parameters of the operation must be set before this function.
 * All parameters are registered and so only changed parameters from
 * previous operations must be set. On the other hand, the operation
 * must be always set because the function starts a required operation
 * in the DFU. 
 * Return Value: The function doesn't return any value.
 */
void pb2dfu_restart_op(unsigned char op);

/**
 * pb2dfu_set_cnt - set length of input data vectors for the next operation
 * @cnt: length of input data vectors
 *
 * The function sets length of the input data vectors.
 * The simple operations (as VADD, VMULT) will be performed @cnt-times
 * as one pipelined operation.
 * Return Value: The function doesn't return any value.
 */
void pb2dfu_set_cnt(unsigned int cnt);

/**
 * pb2dfu_set_addr - set the base address of vector for the given DFU argument
 * @dfuag: select the DFU argument number (constant %DFUAG_x)
 * @addr: the initial address of the vector
 */
void pb2dfu_set_addr(unsigned char dfuag, unsigned int addr);

/**
 * pb2dfu_set_bank - select bank for specified memory
 * @dfuag: select the DFU argument number (constant %DFUAG_x)
 * @bank: the memory bank which will be used for the next operation (constant %MBANK_x)
 */
void pb2dfu_set_bank(unsigned char dfuag, unsigned char mbank);

/**
 * pb2dfu_set_fulladdr - set full address (bank and offset) of the first element in the vector
 * @dfuag: select the DFU argument number (constant %DFUAG_x)
 * @mbank: the memory bank which will be used for the next operation (constant %MBANK_x)
 * @addr: the initial address of the vector
 */
void pb2dfu_set_fulladdr(unsigned char dfuag, unsigned char mbank, unsigned int addr);

/**
 * pb2dfu_set_inc - set the stride of the vector for the DFU argument
 * @dfuag: select the DFU argument number (constant %DFUAG_x)
 * @inc: increment between two elements of vector
 */
void pb2dfu_set_inc(unsigned char dfuag, int inc);

/**
 * pb2dfu_set_bound_addr - set boundary addresses for vector accesses
 * @dfuag: select the DFU argument number (constant %DFUAG_x)
 * @lo_bound: lower addres boundary
 * @hi_bound: higher addres boundary
 */
void pb2dfu_set_bound_addr(unsigned char dfuag, unsigned int lo_bound, unsigned int hi_bound);

/**
 * pb2dfu_set_agflags - set operation flags/mode of the specified address generator (DFU argument)
 * @dfuag: select the DFU argument number (constant %DFUAG_x)
 * @agflags: bitmap of flags to set (constants %AGFL_x)
 */
void pb2dfu_set_agflags(unsigned char dfuag, unsigned char agflags);

/**
 * pb2dfu_set_repetitions - set the number of repetitions of a DFU operation.
 * @nrep: the number of times the following DFU operation will be restarted.
 */
void pb2dfu_set_repetitions(unsigned char nrep);


/** ******************************************************************************************** **/
    
#endif /* _DFU_FP01_1X1_HEADER_ */
