/*  SPINCORE TECHNOLOGIES, INC

    GAINESVILLE, FL

    www.spincore.com



    Release 02.01.0101 - PulseBlasterDDS



    This file is being distributed as community software free of charge.  SpinCore

    Technologies, Inc retains ownership of the software but does not make any

    claims as to its functionaliy or warranty it in any way.  Any modifications

    to this code must be provide to SpinCore along with a description of what

    was changed as well as the motivation behind the changes.  The modifications

    will be reviewed by SpinCore and made availible to others if the changes are

    deemed positive by SpinCore.

*/



enum ENDIAN{

  BIG,

  LITTLE,

};





/* Constant Definitions - HW Dependent Variables */

#define PRODUCT                     "PulseBlasterDDS"

#define MIN_INSTRUCTION_TICKS_INT   5

#define MIN_INSTRUCTION_TICKS_EXT   9

#define FLAG_BIT_LENGTH				24

#define DDS_UNITS                   1

#define DDS_REGS_AVAILABLE          4

#define DDS_CLOCK_FREQ              50

#define BYTE_CODE_FILE	            "bytecode.dat"

#define DEFAULT_OUTPUT_FILE			"pulse_info.txt"

#define ENDIAN_TYPE                 LITTLE



#define OUTPUT_ON     ((UINT32)0<<19) /* flag value and bit position */

#define OUTPUT_OFF    ((UINT32)1<<19) 

#define FREQ0     ((UINT32)0<<22)

#define FREQ1     ((UINT32)1<<22)

#define FREQ2     ((UINT32)2<<22)

#define FREQ3     ((UINT32)3<<22)

//Labels added for TVR (Dual Output) design

#define INTERNAL_MEMORY                 512

#define EXTERNAL_MEMORY             32*1024

#define OVERHEAD_TICKS                    3

#define MIN_DELAY_LOOPS                   3

#define LOOP_COUNT_CORRECTION             1       // corrects for HW design specification

#define LONG_DELAY_LOOP_COUNT_CORRECTION  2       // corrects for HW design specification

#define	COUNTER_BIT_LENGTH				  32

#define OP_CODE_BIT_LENGTH				  4

#define DATA_FIELD_BIT_LENGTH			  20

#define DDS_BIT_LENGTH                    32



#define CONTINUE     0

#define STOP         1

#define LOOP         2

#define END_LOOP     3

#define JUMP         4

#define RETURN       5

#define BRANCH       6

#define LONG_DELAY   7

#define WAIT         8

#define INITIAL_FLAG 127



#define ns           1.0

#define us           1e3

#define ms           1e6

#define s            1e9



/* Define Data Types */

typedef long ADDRESS;

typedef long INT32;

typedef unsigned long UINT32;

typedef char INT8;

typedef unsigned char UINT8;

typedef short int INT16;

typedef unsigned short int UINT16;



/* Structure Definitions */

typedef struct{

  UINT32 dds[DDS_UNITS][DDS_REGS_AVAILABLE];

  UINT8  programmed[DDS_UNITS][DDS_REGS_AVAILABLE];

  UINT8  dds_info_specified;

}  DDS_Unit;



typedef struct{

  UINT32 flags;

  UINT8  programmed;

} Init_Flags_Unit;





typedef struct{

  UINT8  op_code;

  UINT32 delay;

  UINT32 data_field;

  UINT32 flags;

} Instruction_Unit;



typedef struct{

    UINT8  op_code;

    double delay;

    UINT32 data_field;

    UINT32 flags;

    INT32  index;

} Command;



typedef struct{

    char   hw_type[80];

    INT16  port_address;

    INT16  op_code_bit_length;

    INT16  data_field_bit_length;

    INT16  delay_bit_length;

    INT16  flag_bit_length;

} HW_Parameters;



struct parameters

{

    UINT8    opcode;

    UINT32   branch_addr;

    UINT32   delay;

    UINT32   flags;

    UINT8    opcode_width;

    UINT8    branch_width;

    UINT8    delay_width;

    UINT8    flag_width;

};

typedef struct parameters PARAM;



enum designs {

  PB24,

  PBDDS,

};



enum programming_errors{

  no_errors,

  incorrect_product_type,

  no_product_type,

  bad_opcode_size_spec,

  bad_branch_size_spec,

  bad_delay_size_spec,

  bad_flag_size_spec,

  bad_initial_flag,

  bad_instruct_line_spec,

  bad_port_addr,

  bad_dds_word_size,

  no_dds_registers_spec,

  dds_regs_out_of_order,

  could_not_open_file,

};



enum add_to_program_errors{

  Delay_Shorter_Than_Min = -10,

  Bad_Loop,

  Negative_Address,

};

  

/* 	F U N C T I O N    D E F I N I T I O N S */



/*  Function : GRAP_IMAGE_MEMORY

    This function is used to allocate memory from the host computer to be used

    as an image of the program memory.  The image allows the "program memory"

    to be modified as needed without dealing with the programming hardware.  The

    image can be programmed to the PulseBlaster memory when the creation of the 

    PulseBlaster execution code is completed.

    

    The only values accepted for the length parameter are INTERNAL_MEMORY and

    EXTERNAL_MEMORY, which are both defined in this header file           */

void *grab_image_memory(UINT32 length);



/*  Function : SET_TIME_BASE

    This function is used to specify the frequency of the clock being used with

    the PulseBlaster board.  While the boards are shipped with a specified clock,

    the board comes with an input for an external clock.  The external clock can

    be any frequency up to the max frequency supported by the particular board.

    The frequency specified must be in MHz.

*/

void set_time_base(float clock_frequency, UINT32 type);





/* PULSEBLASTER INSTRUCTION FUNCTIONS */

/*  TIME -  This parameter is used to specify the delay time for this instruction.

            The time is specified in NANOSECONDS.  The FLAGS value associated

            with this instruction will be expressed for the time given in this

            parameter.

    FLAGS - This parameter is used to pass the values for the flag bits to be

    	    expressed as outputs on the PulseBlaster board.

    *IMAGE- Image is a block of memory that is used to simulate the control

    	    memory on the PulseBlaster board so that an image of the memory  

            can be constucted first and programmed to the board when the final

            compilation of the execution code is complete.

    All the instructions below return an ADDRESS type value.  This value 

    specifies the next memory/image location following the instruction 

    implemented by the instruction function.  



    These functions will return a negative number when an error occurs.  Checking

    for error can be done at the users discretion.  */



ADDRESS delay(double time, UINT32 flags, Instruction_Unit *image);

ADDRESS stop(double time, UINT32 flags, Instruction_Unit *image);

ADDRESS rts(double time, UINT32 flags, Instruction_Unit *image);



/*  The loop_count parameter is used to specify the number of times the loop

    initiated by this instruction is supposed to occur.				  */

ADDRESS loop(double time, UINT32 loop_count, UINT32 flags, Instruction_Unit *image);



/*  The top_of_loop parameter specifies the address of the top of the loop.  It

    is the users responsibility to track the address of the top of a loop.	  */

ADDRESS end_loop(double time, UINT32 top_of_loop, UINT32 flags, Instruction_Unit *image);



/*  The next address parameter is used to specify the address of the subroutine

    that is being jumped to.						          */

ADDRESS jump(double time, UINT32 next_addr, UINT32 flags, Instruction_Unit *image);



/*  The next address parameter is used to specify the address of the location

    that is being jumped to (no rts allowed from a branch).	          */

ADDRESS branch(double time, UINT32 next_addr, UINT32 flags, Instruction_Unit *image);



/*  Function : ADD_TO_PROGRAM   

    This function should not be called by the average user.  This is a low level function

    used by the higher level instruction type functions to generate a program.  This

    function will return a negative number on error. */

ADDRESS add_to_program(Command info, Instruction_Unit *data_array);



void program_initial_flag_values(UINT32 flags);



/*  Function : PROGRAM_DDS

    This function is used to program the frequency registers of DDS's used by the

    PulseBlasterDDS.  The first field specifies the DDS unit to program, the second

    specifies the register for the given DDS unit, and the third specifies the 

    frequency of DDS output. The output frequency must be specified in MHz.  The fourth

    field is a pointer to a structure of type DDS_Unit that will be used to hold all

    information regarding DDS frequency programming.  */

INT8 program_dds(UINT8 dds, UINT8 reg, double frequency, DDS_Unit *dds_array);





/*  Function : CREATE_BYTECODE_FILE

    This function will create a file, specified by *name, that will be used to 

    hold the programming information that will be used to program the PB/PBDDS board.

    This intermediate file is created to allow users to see what is being programmed

    to the PB/PBDDS board and allow easier debugging of problems.  It also allows 

    programs to be "compiled" once and run there after by simply calling the

    function program_pulseblaster    */

INT16 create_bytecode_file_dds(Instruction_Unit *image, UINT32 image_size, DDS_Unit *dds, char *name, HW_Parameters hw);

INT16 create_bytecode_file(Instruction_Unit *image, UINT32 image_size, char *name, HW_Parameters hw);





/*  Function : CREATE_MASK    */

UINT32 create_mask(UINT16  size);



/*  Function : PROGRAM_PULSE_BLASTER

    This function is used to send the data contained in the bytecode.dat 

    file over the ISA Bus and program the PulseBlaster board.  It returns

    a value that specifies whether programming was successful or not.  A 

    return value of zero means success, a return value > 0 means failure.

    Failure codes are specified in spincore.h header file.    */

INT16 program_pulseblaster(char *name);



/*  Function :	READ_LINE

    This function is used to read in instruction fields from the bytecode.evt

    file.  The instruction fields are in a pre-determined order and should

    not be changed, so that code will be forward and backward compatible.

*/

PARAM read_line(FILE *);



/*  Function :	ORDERED_BYTE_OUTPUT

    This function takes the instruction fields and orders them correctly

    for programming the PulseBlaster over the ISA Bus.  The instruction field

    order in bytecode.evt is fixed, and the variation in hardware byte ordering

    of the fields is taken care of in this function.  This function provides a

    Hardware Abstraction Layer (HAL) for this code architecture.

*/

void ordered_byte_output(PARAM data, UINT8 *array);



/* Function : INITHW

   This function initializes HW dependent information into a variable

   for use in programming PB/PBDDS board */

HW_Parameters InitHW(UINT16 myPort, float clock_frequency, UINT32 memory_type);



/*  Function : OUTPUT_DATA

    This fucntion orders data to be programmed to the PB/PBDDS board in the 

    correct order.  The order is endian dependent and this function tries to

    account for different OS types. */  

int output_data(void *data, int length, UINT16 port_address);





/*  Function : GRAB_DDS_MEMORY 

    This function allocates memory for programming DDS data */

DDS_Unit* grab_dds_memory(void);



void start_pb(UINT16 port);

void reset_pb(UINT16 port);

void arm_pb(UINT16 port);






