/*******************************************************************
*																   *
*   Loughborough Sound Images Ltd								   *
*   The Technology Centre										   *
*   Epinal Way													   *
*   Loughborough												   *
*   Leics						  Tel : (0509)  231843			   *
*   LE11  0QE					  FAX : (0509)  262433			   *
*																   *
*   Copyright 1991 Loughborough Sound Images Ltd				   *
*																   *
*   Date	 : 20th November 1991								   *
*   Project  : TMS 320C40 Application Library					   *
*   Modules  :													   *
*																   *
*   History  :													   *
*	  Date		   Ver		  Change							   *
*   10/1992		  1.00		  Initial production version		   *
*   06/1993		  2.00		  Alter DPC App lib for QPC/C40		   *
*																   *
*																   *
*******************************************************************/
#include   <iol\lia\lia.hpp>

#define	   ENABLED			   1
#define	   DISABLED			   0
#define	   FAST_MODE		   ENABLED /* C or Assembler */

/*********************************************
 *											 *
 *											 *
 *   local function prototypes				 *
 *											 *
 *											 *
 *********************************************/
UINT	   Send_BOOT_Header(UINT, ULONG, ULONG, ULONG);
UINT	   Send_BOOT_Trailer(UINT);
UINT	   Send_Word(UINT, ULONG);
UINT	   Download_Section_Data(UINT, ULONG, ULONG, FILE *);
UINT	   C4x_To_IEEE_32(void *, UINT);
UINT	   IEEE_To_C4x_32(void *, UINT);
void	   read_new_line(FILE  *);
void	   Clear_DSP_Board_Entry(UINT);
void	   skip_initial_comments(FILE  *);

/*********************************************
 *											 *
 *											 *
 *   global variable definitions			 *
 *											 *
 *											 *
 *********************************************/


UINT	   Global_LIA_Address = 0;

/*
   The following array definition is used to store the data associated
   with each board currently in use with the software to which these
   libraries are linked. The number of boards allowed at any time is
   defined in TIC4XAPP.H as MAX_NO_DSP_BOARDS.
*/

#if MAX_NO_DSP_BOARDS> 4
#define MAX_NO_DSP_BOARDS   4
#endif

#define		ALL_PROC_RESET	  { PROC_RESET, PROC_RESET, PROC_RESET, PROC_RESET }

Board_Description_Type		 DSP_Board[MAX_NO_DSP_BOARDS] = {
	   /*
		  Now repeat the initialisation definitions for each entry in
		  DSP_Board. Note that all fields not explicitly mentioned are
		  set to 0 autoatically.
	   */

#if MAX_NO_DSP_BOARDS > 0
	   {   0x0,			   /*  Control_Reg;			   */
		   0x0,			   /*  Status_Reg			   */
		   0x0,			   /*  No_Modules			   */
		   0x0,			   /*  Port_Address			   */
		   0x0,			   /*  LIA_Address			   */
		   ALL_PROC_RESET, /*  All Processor modes	   */
	   },
#endif

#if MAX_NO_DSP_BOARDS > 1
	   {   0x0,			   /*  Control_Reg;			   */
		   0x0,			   /*  Status_Reg			   */
		   0x0,			   /*  No_Modules			   */
		   0x0,			   /*  Port_Address			   */
		   0x0,			   /*  LIA_Address			   */
		   ALL_PROC_RESET, /*  All Processor modes	   */
	   },
#endif

#if MAX_NO_DSP_BOARDS > 2
	   {   0x0,			   /*  Control_Reg;			   */
		   0x0,			   /*  Status_Reg			   */
		   0x0,			   /*  No_Modules			   */
		   0x0,			   /*  Port_Address			   */
		   0x0,			   /*  LIA_Address			   */
		   ALL_PROC_RESET, /*  All Processor modes	   */
	   },
#endif

#if MAX_NO_DSP_BOARDS > 3
	   {   0x0,			   /*  Control_Reg;			   */
		   0x0,			   /*  Status_Reg			   */
		   0x0,			   /*  No_Modules			   */
		   0x0,			   /*  Port_Address			   */
		   0x0,			   /*  LIA_Address			   */
		   ALL_PROC_RESET, /*  All Processor modes	   */
	   },
#endif

		  }; /* End of initialisation */


/********************************************************************
*																	*
*   The array u_module_sense_line is used to determine if we have   *
*   a module available in the requested site.						*
*																	*
********************************************************************/
unsigned int	   u_module_sense_line[] = { A_SENSE, B_SENSE, C_SENSE, D_SENSE };

/********************************************************************
*																	*
*  When we check the status of the LIA XMIT directly then we		*
*  selectively mask out the appropriate bit.						*
*																	*
********************************************************************/
unsigned int	   u_module_xmit_masks[] = { A_XMIT_DATA_EMPTY, B_XMIT_DATA_EMPTY, \
						 C_XMIT_DATA_EMPTY, D_XMIT_DATA_EMPTY };

/********************************************************************
*																	*
*   When we check the status of the LIA REC directly then we		*
*   selectively mask out the appropriate bit.						*
*																	*
********************************************************************/
unsigned int	   u_module_rec_masks[]  = { A_REC_DATA_FULL, B_REC_DATA_FULL, \
						 C_REC_DATA_FULL, D_REC_DATA_FULL };

/********************************************************************
*																	*
*   When we write to the LIA we have to add a bias from the			*
*   base to the appropriate registers. The offsets are stored		*
*   in the array below.												*
*																	*
********************************************************************/
unsigned int	   u_module_LIA_reg_base[] = { 4, 12, 0, 8 };



/*********************************************
 *											 *
 *											 *
 *   Procedures and functions				 *
 *											 *
 *											 *
 *********************************************/

/*******************************************************************
*																   *
*   Function :  Put_Control_Register							   *
*																   *
*   Purpose  :  Write the current control reg value to the		   *
*				current DSP board.								   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*																   *
*******************************************************************/
UINT	   Put_Control_Register(void)
{
	Write_to_Port(CONTROL1, DSP_Board[CURRENT_BOARD].Control_Reg);
	return (RC_NO_ERROR);
}

/*******************************************************************
*																   *
*   Function :  Get_Status_Register								   *
*																   *
*   Purpose  :  Read the current contents of the Status			   *
*				register.										   *
*																   *
*   Paramtrs :  1												   *
*				address of temp status register -				   *
*							 the address of a location where the   *
*							 status register value will be put.	   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*																   *
*******************************************************************/
UINT	   Get_Status_Register(UINT  *u_status_reg)
{
	*u_status_reg = Read_from_Port(STATUS);
	DSP_Board[CURRENT_BOARD].Status_Reg = *u_status_reg;
	return (RC_NO_ERROR);
}

/*******************************************************************
*																   *
*   Function :  Change_Control_Register_Field					   *
*																   *
*   Purpose  :  Change a field/bit in the Control reg. Then poll   *
*				the register until the field is seen to be set	   *
*				correctly.										   *
*																   *
*   Paramtrs :  2												   *
*				u_bit_field -									   *
*							 the name of the bit field from the	   *
*							 list in TIC4XQA.H					   *
*				u_bit_action   -								   *
*							 the action to be performed with that  *
*							 field (chosn form list in TIC4XQA.H   *
*																   *
*   Returns  :  RC_NO_ERROR  if the change was successful		   *
*				RC_TIMEOUT   otherwise							   *
*																   *
*******************************************************************/
UINT	   Change_Control_Register_Field(UINT   u_bit_field, UINT u_bit_action)
{
	UINT	u_control;

	set_reg_field(DSP_Board[CURRENT_BOARD].Control_Reg, u_bit_field, u_bit_action);
	Put_Control_Register();
	return (RC_NO_ERROR);
}

/*******************************************************************
*																   *
*   Function :  Global_Network_Reboot							   *
*																   *
*   Purpose  :  Assert the GRESETC bits for all QPC boards in the  *
*				chain  and then release again. Make sure that JTAG *
*				master bit is set on all the boards in the network *
*				on leaving this function or else				   *
*				the other boards will respond to our JTAG commands *
*																   *
*   Paramtrs :  0												   *
*																   *
*   Returns  :  RC_NO_ERROR if the reset worked correctly		   *
*				RC_NET_FILE_NOT_FOUND if DPC_C40.NET not found	   *
*																   *
*******************************************************************/
UINT	   Global_Network_Reboot(void)
{
	UINT		u_port_addrs[MAX_NO_DSP_BOARDS];
	FILE		*fp;
	UINT		u_number;
	UINT		u_board_addr;
	UINT		u_ctl_reg;
	UINT		u_bacount, u_batotal;
	/*
	   Open the data file and read in the values for the QPC/C40 boards in the
	   network. For each board make an entry in the u_port_addrs array
	*/
	u_bacount = 0;
	if ((fp = fopen("QPC_C40.NET", "r")) != NULL) {
		skip_initial_comments(fp);
		u_number = fscanf(fp, "%x", &u_board_addr);
		read_new_line(fp);
		while ((u_number == 1) &&(u_bacount < MAX_NO_DSP_BOARDS)) {
			u_port_addrs[u_bacount] = u_board_addr;
			u_bacount++;
			u_number = fscanf(fp, "%x", &u_board_addr);
			read_new_line(fp);
		}
		fclose(fp);
	}
	else {
		return (RC_NET_FILE_NOT_FOUND);
	}
	u_batotal = u_bacount;
	/*
		For each board in the system lower the Global, Site A, B, C & D
		reset bits, to ensure the processor is not running. Also we need to
		reset the LIA on each board.
	*/
	for (u_bacount = 0; u_bacount < u_batotal; u_bacount++) {
		u_ctl_reg = GRESETC | A_RESET | B_RESET | C_RESET | D_RESET | LINK_ADPT_RESET;
		outpw(u_port_addrs[u_bacount] + CONTROL1_OFFSET, u_ctl_reg);
	}
	/*
		For each board in the system now raise the Global reset line but
		leave the individual Reset lines low. This will ensure
		that these procesors will only run when we first call Select_Board
		for this port address and raise the individual lines.
	*/
	for (u_bacount = 0; u_bacount < u_batotal; u_bacount++) {
		u_ctl_reg = 00;
		outpw(u_port_addrs[u_bacount] + CONTROL1_OFFSET, u_ctl_reg);
	}
	/*
		Also clear all the entries in DSP_Board array so that
		subsequent calls to Select_Board think we are accessing the boards
		for the first time.
	*/
	for (u_bacount = 0; u_bacount < MAX_NO_DSP_BOARDS; u_bacount++) {
		Clear_DSP_Board_Entry(u_bacount);
	}
	return (RC_NO_ERROR);
}

void	   Clear_DSP_Board_Entry(UINT entry)
{
	Board_Description_Type		 DSP_Board_Default = {
			   0x0,			   /*  Control_Reg;			   */
			   0x0,			   /*  Status_Reg			   */
			   0x0,			   /*  No_Modules			   */
			   0x0,			   /*  Port_Address			   */
			   0x0,			   /*  LIA_Address			   */
			   ALL_PROC_RESET, /*  All Processor modes	   */
		   };

	DSP_Board[entry] = DSP_Board_Default;
}

void	   read_new_line(FILE  *fpdatfile)
{
	int		ch;
	int		done = 0;

	while (!done) {
		while ((!feof(fpdatfile)) &&(ch = getc(fpdatfile)) != 0xa)
			;
		ch = getc(fpdatfile);
		if (ch != ';') {
			done = 1;
			ungetc(ch, fpdatfile);
		}
	}
}

void	   skip_initial_comments(FILE  *fpdatfile)
{
	int		ch;
	int		done = 0;

	while (!done) {
		ch = getc(fpdatfile);
		if (ch != ';') {
			done = 1;
			ungetc(ch, fpdatfile);
		}
		else {
			while ((!feof(fpdatfile)) &&(ch = getc(fpdatfile)) != 0xa)
				;
		}
	}
}

/*******************************************************************
*  Function		: Load_And_Run_File								   *
*																   *
*  Purpose		: Loads a COFF file (.OUT) from disk to memory on  *
*				  TMS320C40 Board and starts it running			   *
*																   *
*  Parameters   : 4												   *
*				  module site (MODULE_SITE_A to MODULE_SITE_D)	   *
*				  file_name (Pointer to string)					   *
*				  global memory control register				   *
*				  local memory control register					   *
*																   *
*  Returns		: RC_NO_ERROR									   *
*				  RC_INVALID_MODULE_ID							   *
*				  RC_CANNOT_OPEN_FILE							   *
*				  RC_INVALID_FORMAT								   *
*				  RC_DSP_ERROR									   *
*				  RC_OUT_OF_MEMORY								   *
*				  RC_MODULE_ACCESS_ERROR						   *
*				  RC_PROC_STILL_RUNNING							   *
*																   *
*  Action		: Opens file if possible, reads each character	   *
*				  Read in the section headers of the file, use	   *
*				  information in these headers to get the program  *
*				  word by word and put it into the memory.		   *
*				  Errors can be returned at various points.		   *
*																   *
********************************************************************/

UINT	   Load_And_Run_File(UINT	 u_module_site,
				char *filename,
				ULONG ul_gmcr,
				ULONG ul_lmcr)
{
	FILE				*file_ptr;
	FILHDR				obj_header;
	SCNHDR				sec_header;
	OPTHDR				opt_header;
	ULONG				first;
	ULONG				address;
	ULONG				ul_entry;
	UINT				u_ret;
	UINT				u_temp_sts;

	u_ret = RC_NO_ERROR;

	if (DSP_Board[0].u_Module_Mode[u_module_site] != PROC_RESET) {
		printf("Error: LIA Process Still Running\n");
		return RC_PROC_STILL_RUNNING;
	}

	Get_Status_Register(&u_temp_sts);
	if (u_temp_sts & u_module_sense_line[u_module_site]) {
		printf("Error: LIA Module Access Error (%x)\n",u_temp_sts);
		return RC_MODULE_ACCESS_ERROR;
	}

	if ((file_ptr = fopen(filename, "rb")) == NULL) {
		printf("Error: LIA Can't Open File\n");
		return RC_CANNOT_OPEN_FILE;
	}
	else {

		/* Read in the header */
		if (!fread((unsigned char *) &obj_header, FILHSZ, 1, file_ptr)) {
			printf("Error: LIA Couldn't Read .out File Header\n");
			fclose(file_ptr);
			return RC_INVALID_FORMAT;
		}

		/* Make sure it's a 320C40 COFF file */
		if (obj_header.f_magic != COFF_C40_MAGIC_NO) {
			printf("Error: LIA Bad .out File Header\n");
			fclose(file_ptr);
			return RC_INVALID_FORMAT;
		}

		/* Check whether there is an optional header. If there is then
			read it and set the PC to the start of executable memory.   */
		if (obj_header.f_opthdr != 0) {
			fread((unsigned char *) &opt_header, OPTHSZ, 1, file_ptr);
			ul_entry = opt_header.entry;
		}
		else {
			ul_entry = 0L;
		}

		/* Now send a header block to the downloader in the BOOT format. */
		u_ret = Send_BOOT_Header(u_module_site, ul_gmcr, ul_lmcr, ul_entry);

		/* Check the return code to make sure the board is responding */
		if (u_ret != RC_NO_ERROR) {
			printf("Error: LIA Couldn't Send Boot Header\n");
			fclose(file_ptr);
			return u_ret;
		}

		/* FOR (each section) */
		for (first = 0; first < obj_header.f_nscns; first++) {

			/* . Seek to the section header */
			if (fseek(file_ptr,(sizeof(FILHDR) + obj_header.f_opthdr) +(sizeof(SCNHDR) * first), SEEK_SET)) {
				printf("Error: LIA Couldn't Seek To Section Header\n");
				fclose(file_ptr);
				return RC_INVALID_FORMAT;
			}

			/* . Read the section header */
			if (!fread((unsigned char *) &sec_header, SCNHSZ, 1, file_ptr)) {
				printf("Error: LIA Couldn't Read Section Header\n");
				fclose(file_ptr);
				return RC_INVALID_FORMAT;
			}

			if (sec_header.s_scnptr != 0L) {
				/* . Seek to the data section */
				if (fseek(file_ptr, sec_header.s_scnptr, SEEK_SET)) {
					printf("Error: LIA Couldn't Seek To Data Section\n");
					fclose(file_ptr);
					return RC_INVALID_FORMAT;
				}

				/* . Get the starting address of the section */
				address =(ULONG)sec_header.s_paddr;

				if (sec_header.s_size != 0L) {

					/* . CASEOF (section page number) */
					switch (sec_header.s_page) {

						/* . CASE (Program or Data) - Page 0/1 */
						case SECTION_CODE:
						case SECTION_DATA:
							u_ret = Download_Section_Data(u_module_site, sec_header.s_size, address, file_ptr);

							if (u_ret != RC_NO_ERROR) {
								printf("Error: LIA Couldn't Download Section Data\n");
								fclose(file_ptr);
								return u_ret;
							}
							break;

						/* . CASE some other page!  */
						default:
							fclose(file_ptr);
							return RC_INVALID_FORMAT;
					}
				}
			}
		}

		fclose(file_ptr);

		u_ret = Send_BOOT_Trailer(u_module_site);

		/* Check the return code to make sure the board is responding */
		if (u_ret != RC_NO_ERROR) {
			printf("Error: LIA Couldn't Send Boot Trailer\n");
			return (u_ret);
		}
	}

	if (u_ret == RC_NO_ERROR) {
		DSP_Board[0].u_Module_Mode[u_module_site] = PROC_RUNNING;
	}
	return (u_ret);
}

/*******************************************************************
*																   *
*   Function :  Send_BOOT_Header								   *
*																   *
*   Purpose  :  Send the first 3 words of the BOOT format data to  *
*				the module specified. Then send a dummy first	   *
*				block which sets the entry point of the code.	   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*				RC_DSP_ERROR									   *
*																   *
*******************************************************************/
UINT	   Send_BOOT_Header(UINT u_module, ULONG Global_MBCR,
				 ULONG Local_MBCR, ULONG ul_entry)
{
	UINT	u_retval;

	u_retval = RC_NO_ERROR;
	if ((u_retval = Send_Word(u_module, Global_MBCR)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, Local_MBCR)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, 1L)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, ul_entry)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, 0L)) != RC_NO_ERROR) {
		return (u_retval);
	}
	return (u_retval);
}

/*******************************************************************
*																   *
*   Function :  Send_BOOT_Trailer								   *
*																   *
*   Purpose  :  Send the last few words of the BOOT format data to *
*				the module specified.							   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*				RC_DSP_ERROR									   *
*																   *
*******************************************************************/
UINT	   Send_BOOT_Trailer(UINT u_module)
{
	UINT	u_retval;

	u_retval = RC_NO_ERROR;

	if ((u_retval = Send_Word(u_module, 0L)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, IVTP_ADDR)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, TVTP_ADDR)) != RC_NO_ERROR) {
		return (u_retval);
	}
	if ((u_retval = Send_Word(u_module, IACK_ADDR)) != RC_NO_ERROR) {
		return (u_retval);
	}
	DSP_Board[0].u_Module_Mode[u_module] = PROC_RUNNING;
	return (u_retval);
}

/*******************************************************************
*																   *
*   Function :  Download_Section_Data							   *
*																   *
*   Purpose  :  Read a section of data from the COFF file and send *
*				it to the C40 board.							   *
*				At present assume it is always loaded to the	   *
*				Primary module site.							   *
*				Assume the mem loader is currently installed and   *
*				running on the C40 board.						   *
*				If the block is in DP RAM then redirect it to the  *
*				copy pointed to by the field in DSP_Board array	   *
*																   *
*   Parametrs:  4												   *
*				u_module_site - MODULE_SITE_A to MODULE_SITE_D	   *
*				block_size -   number of words to download		   *
*				C40_address -  start address of block on C40	   *
*				file_ptr   -   file pointer at start of data in	   *
*							   open COFF file					   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*				RC_INVALID_FORMAT								   *
*				RC_OUT_OF_MEMORY								   *
*				RC_ZERO_BLOCK_SIZE								   *
*																   *
*******************************************************************/
UINT	   Download_Section_Data(UINT	 u_module_site,
				 ULONG   ul_block_size,
				 ULONG   ul_address,
				 FILE	 *fp_file_ptr)
{
	const   ULONG   ul_MAX_BLOCK_SIZE = 100L;
	ULONG   *ulp_temp_area, *ulp_temp_ptr;
	ULONG   ul_curr_address;
	ULONG   ul_remaining;
	char	far		*cp_DP_ptr;
	UINT	u_number_to_transfer;
	UINT	u_ct;
	UINT	u_ret = 0;

	ulp_temp_area = ulp_temp_ptr =(unsigned long*)malloc(102 * 4);
	if (ulp_temp_area != NULL) {
		if (ul_block_size > 0L) {
			ul_curr_address = ul_address;
			ul_remaining = ul_block_size;
			while (ul_remaining > 0L) {
				ulp_temp_area = ulp_temp_ptr;
				if (ul_remaining > ul_MAX_BLOCK_SIZE) {
					u_number_to_transfer =(UINT)ul_MAX_BLOCK_SIZE;
				}
				else {
					u_number_to_transfer =(UINT)ul_remaining;
				}
				if (fread(ulp_temp_area, 4, u_number_to_transfer, fp_file_ptr) == u_number_to_transfer) {
					u_ret = Send_Word(u_module_site,(ULONG)u_number_to_transfer);
					u_ret = Send_Word(u_module_site, ul_curr_address);
					for (u_ct = 0;((u_ct < u_number_to_transfer) &&(u_ret == RC_NO_ERROR)); u_ct++) {
						u_ret = Send_Word(u_module_site, *ulp_temp_area++);
					}
					if (u_ret != RC_NO_ERROR) {
						u_ret = RC_DSP_ERROR;
						ul_remaining = 0L;
					}
					else {
						ul_remaining -= u_number_to_transfer;
						ul_curr_address += u_number_to_transfer;
					}
				}
				else {
					u_ret = RC_INVALID_FORMAT;
					ul_remaining = 0L;
				}
			}
		}
		else {
			u_ret = RC_ZERO_BLOCK_SIZE;
		}
		free(ulp_temp_ptr);
	}
	else {
		u_ret = RC_OUT_OF_MEMORY;
	}
	return (u_ret);
}

/*******************************************************************
*																   *
*   Function :  Send_Word										   *
*																   *
*   Purpose  :  Transfer a word of data to the boot loader code	   *
*				running on any module. All data is passed using	   *
*				the LIA transfer functions.						   *
*																   *
*   Paramtrs :  2												   *
*				u_module_site  -   module site to write to		   *
*				data_word	   -   data value to be sent		   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*				RC_DSP_ERROR									   *
*																   *
*******************************************************************/
UINT	   Send_Word(UINT u_module_site, ULONG   ul_data_word)
{
	int		i_timeout;
	UINT	u_ret;
	UINT	u_flag;
	ULONG   ul_data;

#if FAST_MODE

	u_ret = LIA_FWrite_Block(u_module_site, 1, &ul_data_word, 200);
	if (!u_ret) {
		return (RC_DSP_ERROR);
	}
	else {
		return (RC_NO_ERROR);
	}

#else

	u_ret = RC_NO_ERROR;
	i_timeout = DSP_TIMEOUT;
	do {
		u_flag = inpw(INT_STATUS_FLAG) & u_module_xmit_masks[u_module_site];
	} while ((i_timeout > 0) && !u_flag);
	if (i_timeout == 0) {
		u_ret = RC_DSP_ERROR;
	}
	else {
		outpw((Global_LIA_Address + u_module_LIA_reg_base[u_module_site] + 0),
		  (UINT)ul_data_word);
		outpw((Global_LIA_Address + u_module_LIA_reg_base[u_module_site] + 2),
		  (UINT)(ul_data_word >> 16));
	}
	return (u_ret);

#endif
}


/*******************************************************************
*																   *
*   Function :  Select_Board									   *
*																   *
*   Purpose  :  Set the I/O port address and dual port RAM address *
*				of the board to be accessed for subsequent library *
*																   *
*   Paramtrs :  2												   *
*				base address -									   *
*							 address of the base I/O location in   *
*							 the PC's I/O map					   *
*				LIA address  -									   *
*							 address of the LIA I/O location in	   *
*							 the PC's i/O map					   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*				RC_NO_MODULES									   *
*				RC_CANNOT_SELECT								   *
*																   *
*******************************************************************/
UINT		   Select_Board(UINT u_portaddress, UINT u_portaddress2)
{
	UINT		u_retval;
	int			i_array_count;
	BOOLEAN		b_found, b_inserted;
	Board_Description_Type  sp_temp_board_info;
	UINT		u_modules;
	UINT		u_mask_val;
	UINT		u_status;


	b_found = False;
	u_retval = RC_NO_ERROR;

	if (DSP_Board[0].Port_Address != u_portaddress) {
		for (i_array_count = 1; i_array_count < MAX_NO_DSP_BOARDS; i_array_count++) {
			if (DSP_Board[i_array_count].Port_Address == u_portaddress) {
				sp_temp_board_info = DSP_Board[i_array_count];
				DSP_Board[i_array_count] = DSP_Board[CURRENT_BOARD];
				DSP_Board[CURRENT_BOARD] = sp_temp_board_info;
				DSP_Board[CURRENT_BOARD].LIA_Address = u_portaddress2;
				Global_LIA_Address = u_portaddress2;
				Write_and_Enable_BARs;
				b_found = True;
				break;
			}
		}
	}
	else {
		/* Board in use is already at 0 in array */
		b_found = True;
		Global_LIA_Address = u_portaddress2;
		DSP_Board[CURRENT_BOARD].LIA_Address = u_portaddress2;
		Write_and_Enable_BARs;
	}
	if (!b_found) {
		b_inserted = False;
		for (i_array_count = 0; i_array_count < MAX_NO_DSP_BOARDS; i_array_count++) {
			if (DSP_Board[i_array_count].Port_Address == 0) {
				if (i_array_count != 0) {
					DSP_Board[i_array_count] = DSP_Board[0];
				}
				DSP_Board[0].Port_Address = u_portaddress;
				/*
				Get the PCs copy of the Control Reg in step with the
				board Control Register set with the Global_Network_Reboot
				function.
				*/
				DSP_Board[CURRENT_BOARD].Control_Reg = 0; /* Raise RESET lines */
				Put_Control_Register();
				DSP_Board[CURRENT_BOARD].LIA_Address = u_portaddress2;
				Global_LIA_Address = DSP_Board[CURRENT_BOARD].LIA_Address;
				Write_and_Enable_BARs;
				Get_Status_Register(&u_status);
				u_modules = 0;
				if (~u_status & A_SENSE) {
					u_modules++;
				}
				if (~u_status & B_SENSE) {
					u_modules++;
				}
				if (~u_status & C_SENSE) {
					u_modules++;
				}
				if (~u_status & D_SENSE) {
					u_modules++;
				}
				if (u_modules != 0) {
					DSP_Board[CURRENT_BOARD].No_Modules = u_modules;
				}
				else {
					u_retval = RC_NO_MODULES;
				}
				b_inserted = True;
				break;
			}
		}
		if (b_inserted == False) {
			u_retval = RC_CANNOT_SELECT;
		}
	}
	return (u_retval);
}

/********************************************************************
*																	*
*   Function   :  LIA_Write_Float									*
*																	*
*   Purpose	   :  This routine transfers 1 floating point value		*
*				  to the C40 via the LIA							*
*																	*
*   Parameters :  2													*
*				  u_module_site -									*
*								module site to write to				*
*				  f_value		-									*
*								value to write						*
*																	*
*   Returns	   :  none												*
*																	*
********************************************************************/
void far LIA_Write_Float(UINT u_module_site, float *f_value)
{
	IEEE_To_C4x_32((void *)f_value, 1);
	LIA_Write(u_module_site, *(ULONG *)f_value);
}

/********************************************************************
*																	*
*   Function   :  LIA_Read_Float									*
*																	*
*   Purpose	   :  This routine transfers 1 floating point value		*
*				  from the C40 via the LIA							*
*																	*
*   Parameters :  2													*
*				  u_module_site -									*
*								module site to read from			*
*				  f_value		-									*
*								address to write value to			*
*																	*
*   Returns	   :  none												*
*																	*
********************************************************************/
void far LIA_Read_Float(UINT u_module_site, float *f_value)
{
	LIA_Read(u_module_site,(ULONG *)f_value);
	C4x_To_IEEE_32((void *)f_value, 1);
}

/********************************************************************
*																	*
*   Function   :  LIA_Write_Float_Block								*
*																	*
*   Purpose	   :  This routine writes a number of floating point	*
*				  values to the C40 via the LIA						*
*																	*
*   Parameters :  3													*
*				  u_module_site -									*
*								module site to write to				*
*				  u_number_to_xfer -								*
*								number of words to write			*
*				  f_data_block  -									*
*								PC address to read data values from *
*																	*
*   Returns	   :  none												*
*																	*
********************************************************************/
void far LIA_Write_Block_Float(UINT u_module_site,
					 UINT u_number_to_xfer,
					 float *f_data_block)
{
	IEEE_To_C4x_32((void *)f_data_block, u_number_to_xfer);
	LIA_Write_Block(u_module_site, u_number_to_xfer,(ULONG *)f_data_block);
}

/********************************************************************
*																	*
*   Function   :  LIA_Read_Float_Block								*
*																	*
*   Purpose	   :  This routine reads a number of floating point		*
*				  values from the C40 via the LIA					*
*																	*
*   Parameters :  3													*
*				  u_module_site -									*
*								module site to read from			*
*				  u_number_to_xfer -								*
*								number of words to read				*
*				  f_data_block  -									*
*								PC address to write data values to  *
*																	*
*   Returns	   :  none												*
*																	*
********************************************************************/
void far LIA_Read_Block_Float(UINT u_module_site,
					UINT u_number_to_xfer,
					float *f_data_block)
{
	UINT	u_ret;

	LIA_Read_Block(u_module_site, u_number_to_xfer,(ULONG *)f_data_block);
	C4x_To_IEEE_32((void *)f_data_block, u_number_to_xfer);
}

/********************************************************************
*																	*
*   Function   :  LIA_FWrite_Block_Float							*
*																	*
*   Purpose	   :  This routine writes a number of floating point	*
*				  values to the C40 via the LIA						*
*																	*
*   Parameters :  4													*
*				  u_module_site -									*
*								module site to write to				*
*				  u_number_to_xfer -								*
*								number of words to write			*
*				  f_data_block  -									*
*								PC address to read data from		*
*				  u_timeout		-									*
*								timeout in milliseconds to transfer *
*								the ENTIRE block					*
*																	*
*   Returns	   :  The actual number of words transfered				*
*																	*
********************************************************************/
UINT far LIA_FWrite_Block_Float(UINT u_module_site,
					  UINT u_number_to_xfer,
					  float *f_data_block)
{
	IEEE_To_C4x_32((void *)f_data_block, u_number_to_xfer);
	return (LIA_FWrite_Block(u_module_site, u_number_to_xfer,
					  (ULONG *)f_data_block, 1000));
}

/********************************************************************
*																	*
*   Function   :  LIA_FRead_Block_Float								*
*																	*
*   Purpose	   :  This routine reads a number of floating point		*
*				  values from the C40 via the LIA					*
*																	*
*   Parameters :  4													*
*				  u_module_site -									*
*								module site to read from			*
*				  u_number_to_xfer -								*
*								number of words to read				*
*				  f_data_block  -									*
*								PC address to write value to		*
*				  u_timeout		-									*
*								timeout in milliseconds to transfer *
*								the ENTIRE block					*
*																	*
*   Returns	   :  The actual number of words transfered				*
*																	*
********************************************************************/
UINT far LIA_FRead_Block_Float(UINT u_module_site,
					 UINT u_number_to_xfer,
					 float *f_data_block)
{
	UINT	u_ret;

	u_ret = LIA_FRead_Block(u_module_site, u_number_to_xfer,(ULONG *)f_data_block, 1000);
	if (u_ret == u_number_to_xfer) {
		C4x_To_IEEE_32((void *)f_data_block, u_number_to_xfer);
	}
	return (u_ret);
}


/*****************************************************************************/
/*																			 */
/*	  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   */
/*	  @																	 @   */
/*	  @   THE REMAINDER OF THE ROUTINES IN THIS LIBRARY ARE NOT DESIGNED @   */
/*	  @   TO BE CALLED FROM OUTSIDE THIS FILE							 @   */
/*	  @																	 @   */
/*	  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   */
/*																			 */
/*****************************************************************************/

/*******************************************************************
*																   *
*   Function :  C4x_To_IEEE_32									   *
*																   *
*   Purpose  :  Convert a block of words from C4x float format	   *
*				to IEEE floating point format (in place).		   *
*																   *
*   Paramtrs :  2												   *
*				vp_memval   -									   *
*							address of start of memory containing  *
*							C4x float values					   *
*				u_length	-									   *
*							number of words to convert			   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*																   *
*******************************************************************/
UINT	   C4x_To_IEEE_32(void *vp_memval, UINT u_length)
{
	union utag {
	float ieeerep;
	long  transrep;
	} pat;
	ULONG  c4xexp, c4xval, ieeeval;
	UINT   u_count;

	for (u_count = 0; u_count < u_length; u_count++) {
		c4xval = *((ULONG *)vp_memval);
		if (c4xval == 0x80000000l) {
			ieeeval = 0;
		}
		else {
			c4xexp =((c4xval & 0xFF000000l) >> 24);
			if (c4xexp & 0x80) {
				c4xexp |= 0xFFFFFF00l;
			}
			c4xexp += 127;
			c4xexp &= 0xFFl;
			if (c4xval & 0x800000) {
				c4xval =(c4xval & 0x7FFFFF) | 0x1000000;
				c4xval = -c4xval;
				if ((c4xval & 0x800000) == 0) {
					c4xexp += 1;
				}
				ieeeval =(c4xexp << 23) +(c4xval & 0x7FFFFF) | 0x80000000;
			}
			else {
				c4xval = c4xval & 0x7FFFFF;
				c4xexp = c4xexp << 23;
				c4xval &= 0x7FFFFF;
				ieeeval = c4xexp + c4xval;
			}
		}
		pat.transrep = ieeeval;
		*((float *)vp_memval) = pat.ieeerep;
		((ULONG *)vp_memval)++;
	}
	return (RC_NO_ERROR);
}



/*******************************************************************
*																   *
*   Function :  IEEE_To_C4x_32									   *
*																   *
*   Purpose  :  Convert a block of words from IEEE float format	   *
*				to C4x floating point format (in place).		   *
*																   *
*   Paramtrs :  2												   *
*				vp_memval   -									   *
*							address of start of memory containing  *
*							IEEE float values					   *
*				u_length	-									   *
*							number of words to convert			   *
*																   *
*   Returns  :  RC_NO_ERROR										   *
*																   *
*******************************************************************/
UINT	   IEEE_To_C4x_32(void *vp_memdata, UINT u_length)
{
	union utag {
		float ieeerep;
		long  transrep;
	} pat;
	UINT   u_count;
	ULONG  c4xexp, c4xval, mantissa;

	for (u_count = 0; u_count < u_length; u_count++) {
		pat.ieeerep = *((float *)vp_memdata);
		if (pat.transrep == 0) {
			c4xval = 0x80000000;
		}
		else {
			c4xexp = pat.transrep & 0x7F800000;
			c4xexp = c4xexp >> 23;
			c4xexp -= 127;
			if (pat.transrep & 0x80000000) {
				mantissa = pat.transrep & 0x7fffff;
				mantissa |= 0x800000;
				mantissa = -mantissa;
				if (mantissa & 0x800000)
					c4xexp += -1;
				mantissa |= 0x800000;
				c4xval = mantissa & 0xFFFFFF;
			}
			else {
				c4xval = pat.transrep & 0x7fffff;
			}
			c4xexp &= 0xFF;
			c4xexp = c4xexp << 24;
			c4xval = c4xval | c4xexp;
		}
		*((ULONG *)vp_memdata) = c4xval;
		((ULONG *)vp_memdata)++;
	}
	return (RC_NO_ERROR);
}





