⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi4_tx.c

📁 ixp2400的一个小程序
💻 C
字号:
 //  Copyright (C) 2002-2003 Intel Corporation, All Rights Reserved.
//  Permission is hereby granted to merge this program code with 
//  other program material to create a derivative work.  This 
//  derivative work may be distributed in compiled object form only.
//  Any other publication of this program, in any form, without the 
//  explicit permission of the copyright holder is prohibited.
//
//  Send questions and comments to erik.j.johnson@intel.com, 
//  aaron.kunze@intel.com

//-------------------------------------------------------------------
// spi4_tx.c - Chapter 5
// Dequeues packets from processing, then segments them and transmits
// them using a single thread onto a single port
//

#include "ixp.h"
#include "spi4_tx.h"
#include "dl_buf.c"
#include "dl_meta.h"
#include "dl_source.h"
 

extern dl_buf_handle_t			dlBufHandle;
extern __declspec(gp_reg) int 	dlNextBlock;
extern dl_meta_t				dlMeta;


#define TBUF_ELEM_SIZE			64
#define TBUF_ELEM_SIZE_SHIFT	6
#define NUM_TBUFS				(128 * 64 / TBUF_ELEM_SIZE)
/*#define TX_CONTROL_VAL			((1 << TX_EN_SPHY_BITPOS) | \
								 (1 << TX_ENABLE_BITPOS)	| \
								 (0 << TBUF_ELE_SIZE_0_BITPOS))
*/
// VALUE FOR THE SPI3 
#define TX_CONTROL_VAL			((0 << TX_EN_SPHY_BITPOS) | \
								  (0 << TBUF_ELE_SIZE_0_BITPOS) | \
								  (0 << TX_MPHY_LEVEL2) | \
							       (1 << TX_MPHY_EN) | \
								   (0 << TX_MPHY_MODE)| \
								   (0 << TX_MPHY_POLL_MODE) | \
								   (00 << TX_WIDTH) | \
								   (0 << TX_MODE)) 
								  
								 
#define TX_CONTROL_VAL_SECOND   ((TX_CONTROL_VAL) | \
                                 (1<< TX_EN_SPHY_BITPOS))

#define TX_UP_CONTROL_VAL       ((1 << TX_UP_CONTROL_CPMODE) | \
								(1 << TX_UP_CONTROL_PPMODE) | \
								(1 << TX_UP_CONTROL_DRTIME))

//-------------------------------------------------------------------
// This state is used to store the current packet's segmentation
// state
typedef struct s_tx_state
{
	// 1 if the current mpacket is SOP/EOP respectively
	unsigned int sop, eop; 
	// A pointer to the current mpacket
	__declspec(dram) unsigned char *cur_mpacket_addr;
	// Length remaining, in bytes, of the current mpacket
	unsigned int remaining_length;
	// The handle of the current buffer
	dl_buf_handle_t cur_buf_handle;
} tx_state_t;

static tx_state_t tx_state;


//-------------------------------------------------------------------
// spi4_tx_init
//
//    Description:
//       Initialize the appropriate CSRs to transmit packets on
//       the SPI4 interface.
//
//    Parameters:
//      Outputs: n/a
//      In/Outs: n/a
//      Inputs: n/a
//      Constants: n/a
//      Labels: n/a
//
//    Side effects: Writes to the MSF transmit control CSR
//
//    See also: n/a
//
void spi4_tx_init()
{
	void* addr; // Holds the address of the CSR being set
	__declspec(sram_write_reg) unsigned int tx_ctl;
	SIGNAL msf_tx_ctl_sig;

	//----------- Set the receive control CSR in the MSF.
//可能要写一次tx_en在这里为0
	tx_ctl = TX_CONTROL_VAL;
	addr   = (void *)MSF_TX_CONTROL_ADDR;
	msf_write(&tx_ctl, addr, 1, ctx_swap, &msf_tx_ctl_sig);
	//初始化以后要再写一次tx_en
	
	
	tx_ctl= TX_UP_CONTROL_VAL;
	addr = (void *)MSF_TX_UP_CONTROL_0_ADDR;
	msf_write(&tx_ctl,addr,1,ctx_swap,&msf_tx_ctl_sig);
	
	addr = (void *)MSF_TX_UP_CONTROL_1_ADDR;
	msf_write(&tx_ctl,addr,1,ctx_swap,&msf_tx_ctl_sig);
	
	addr = (void *)MSF_TX_UP_CONTROL_2_ADDR;
	msf_write(&tx_ctl,addr,1,ctx_swap,&msf_tx_ctl_sig);
	
	addr = (void *)MSF_TX_UP_CONTROL_3_ADDR;
	msf_write(&tx_ctl,addr,1,ctx_swap,&msf_tx_ctl_sig);
	
	addr   = (void *)MSF_TX_CONTROL_ADDR;
	tx_ctl=TX_CONTROL_VAL_SECOND;
	msf_write(&tx_ctl,addr,1,ctx_swap,&msf_tx_ctl_sig);
}


//-------------------------------------------------------------------
// _spi4_tx_move_dram_to_tbuf
//
//    Description:
//       Transfer the given DRAM memory into the given TBUF element
//
//    Parameters:
//      Outputs: n/a 
//      In/Outs: n/a
//      Inputs: in_tbuf_elem - The TBUF element number to use
//              in_dram_addr - The start address to the packet to
//							   transfer
//				in_size - The number of bytes to transfer
//				in_dram_sig	 - The signal to use for the transfer
//      Constants: n/a
//      Labels: n/a
//
//    Side effects: The given dual signal must be caught by the
//					calling routine.
//					The in_size must be between 1 and
//					128.  The number of bytes transfered will
//					be (in_size >> 3) << 3) since
//					the transfer must be an even number of quadwords
//    See also: n/a
//
__forceinline
static void _spi4_tx_move_dram_to_tbuf(
	unsigned int in_tbuf_elem, 
	void __declspec(dram) *in_dram_addr, 
	unsigned int in_size, 
	SIGNAL_PAIR *in_dram_sig)
{
	dram_rbuf_tbuf_ind_t indir;
	unsigned int tbuf_addr;

	// Compute the TBUF address.  This is the base TBUF
	// address in the MSF plus the element number times
	// 64.
	tbuf_addr = MSF_TBUF_BASE_ADDR + 
			   (in_tbuf_elem << 6);

	// Override the tbuf address
	indir.value = 0;
	indir.ov_buf_addr = 1;
	indir.buf_addr = tbuf_addr;

	// Override the transfer size
	indir.ov_ref_count = 1;
	indir.ref_count = ((in_size + 7) >> 3) - 1;

	dram_tbuf_write_ind(in_dram_addr,
					   	8,
					    indir,
					    sig_done,
					    in_dram_sig);
}


//-------------------------------------------------------------------
// _spi4_tx_validate_tbuf
//
//    Description:
//       Validate the given TBUF entry
//
//    Parameters:
//      Outputs: n/a 
//      In/Outs: n/a
//      Inputs: in_tbuf_elem - The TBUF element number to use
//              in_sop       - 1 if the TBUF is an SOP, 0 otherwise
//              in_eop       - 1 if the TBUF is an EOP, 0 otherwise
//				in_size - The number of bytes to transfer
//      Constants: n/a
//      Labels: n/a
//
//    Side effects: The given signal must be caught by the
//					calling routine.
//    See also: n/a
//
__forceinline
static void _spi4_tx_validate_tbuf(
		unsigned int in_tbuf_elem, 
		unsigned int in_sop, 
		unsigned int in_eop, 
		unsigned int in_size)
{
	spi4_tcw_t tbuf_control;
	__declspec(sram_write_reg) spi4_tcw_t tbuf_control_wr;			
	SIGNAL msf_sig;

	tbuf_control.control_word.whole = 0;
	tbuf_control.reserved = 0;

	// Set the mpacket length
	tbuf_control.control_word.parts.payload_length = 
										in_size;	

	// Set SOP and EOP
	tbuf_control.control_word.parts.sop = in_sop;
	tbuf_control.control_word.parts.eop = in_eop;
	tbuf_control_wr = tbuf_control;

	msf_write(
		&tbuf_control_wr, 
		(void *)(MSF_TBUF_CONTROL_BASE_ADDR + 
			(in_tbuf_elem<<3)),
		sizeof(tbuf_control_wr) / sizeof(unsigned int),
		ctx_swap,
		&msf_sig);
}


//-------------------------------------------------------------------
// _spi4_tx_update_tbufs_in_flight
//
//    Description:
//       Read the current TX sequence number and with the last
//		 sequence number value, update the number of tbuf
//		 elements in flight.
//
//    Parameters:
//      Outputs: n/a 
//      In/Outs: io_tbuf_in_flight - On input, the last number of
//                                   TBUFs in flight based on
//                                   the last read value of
//                                   io_last_tx_seq.  On output,
//                                   the number of tbufs in flight
//                                   according to the updated
//                                   io_last_tx_seq
//               io_last_tx_seq    - On input, the last value
//                                   read for the TX sequence number.
//                                   On output, the current value
//                                   of the TX sequence number
//      Inputs: n/a
//      Constants: n/a
//      Labels: n/a
//
//    Side effects: n/a
//    See also: n/a
//
__forceinline
static void _spi4_tx_update_tbufs_in_flight(
	unsigned int *io_tbufs_in_flight, 
	unsigned int *io_last_tx_seq)
{	
	unsigned int cur_tx_seq;
	__declspec(sram_read_reg) unsigned int cur_tx_seq_rd;
	unsigned int tbufs_used;
	SIGNAL msf_sig;

	// First read the current sequence number
	msf_read(&cur_tx_seq_rd, 
		     (void *)MSF_TX_SEQUENCE_0_ADDR,
			 sizeof(cur_tx_seq_rd) / sizeof(unsigned int),
			 ctx_swap,
			 &msf_sig);
	cur_tx_seq = cur_tx_seq_rd & 0xff;

	// Compute how many TBUFs have been consumed since 
	// the last read.  Account for wrap around
	if (*io_last_tx_seq <= cur_tx_seq)
	{
		tbufs_used = cur_tx_seq - *io_last_tx_seq;
	}
	else
	{
		tbufs_used = *io_last_tx_seq - cur_tx_seq;
	}

	// Subtract the tbufs_used from the current number of
	// tbufs in flight
	*io_tbufs_in_flight -= tbufs_used;

	// Save the sequence number
	*io_last_tx_seq = cur_tx_seq;
}


//-------------------------------------------------------------------
// _spi4_tx_get_and_update_state
//
//    Description:
//       Get and update the segmentation state associated with a
//		 particular TBUF element.  This version of the routine first
//       attempts to extract the state from global registers, if that
//       state has the EOP state set, then a new packet is dequeued
//       and the first mpacket for the new packet is returned. 
//
//    Parameters:
//      Outputs: The handle of the current buffer,
//				 a pointer to the current mpacket
//               to transmit, 
//				 the length (in bytes) of the mpacket,
//				 sop and eop indicators.
//      In/Outs: n/a
//      Inputs: in_next_tbuf_elem - The TBUF element for which 
//                                  to retrieve the state
//      Constants: n/a
//      Labels: n/a
//
//    Side effects:  
//
//      This routine does not return until valid state can be obtained
//      This routine currently ignored the given TBUF element
//
//    See also: n/a
//
//    Example Usage: 
//		cur_state = tx_get_and_update_state(tbuf_elem)
//
__forceinline
static tx_state_t _spi4_tx_get_and_update_state(
	unsigned int in_next_tbuf_elem)
{
	tx_state_t ret_state;

	// If EOP is true, get a new packet
	if (tx_state.eop)
	{
		while (1)
		{
			// Dequeue a packet from the processing task
			dl_source();

			// Check for an empty queue
			if (dlBufHandle.value != 0)
			{
				// The queue was not empty
				tx_state.sop = 1;
				tx_state.cur_buf_handle   
					= dlBufHandle;
				tx_state.cur_mpacket_addr = 
					(__declspec(dram) unsigned char *)
					Dl_BufGetData(dlBufHandle);
				tx_state.remaining_length 
					= dlMeta.bufferSize;
				break;
			}
		}
	}

	ret_state.cur_mpacket_addr = tx_state.cur_mpacket_addr;
	ret_state.cur_buf_handle   = tx_state.cur_buf_handle;
	ret_state.sop			   = tx_state.sop;

	// Update the global state for the next call to 
	// this macro.  Check for EOP
	if (tx_state.remaining_length <= TBUF_ELEM_SIZE)
	{
		tx_state.eop = 1;
		ret_state.remaining_length = 
				tx_state.remaining_length;
	}
	else
	{
		tx_state.eop = 0;
		ret_state.remaining_length = TBUF_ELEM_SIZE;
	}

	tx_state.cur_mpacket_addr += TBUF_ELEM_SIZE;
	tx_state.remaining_length -= TBUF_ELEM_SIZE;
	tx_state.sop = 0;
	ret_state.eop = tx_state.eop;	
	return ret_state;	
}


//-------------------------------------------------------------------
// spi4_tx
//
//    Description:
//		 Segment and transmit buffers.  This microblock operates
//		 as a context-pipeline and thus never returns
//
//    Parameters:
//      Outputs: n/a
//      In/Outs: n/a
//      Inputs: n/a
//      Constants: n/a
//      Labels: n/a
//
//    Side effects:  
//
//    See also: n/a
//
//
void spi4_tx()
{
	// This state is used during the transmission process to ensure
	// that the TBUFs are used in order and without overrunning the
	// hardware
	
	// The index of the next tbuf element to be
	// used
	unsigned int next_tbuf_elem; 
	// The value of the last read to the
	// tx_sequence number
	unsigned int last_tx_seq;  
	// The number of TBUFs currently being
	// transmitted.  Based on the the last
	// time the tx sequence number was read 
	unsigned int tbufs_in_flight;  

	SIGNAL_PAIR dram_to_tbuf_sig;
	// State associated with the current mpacket
	tx_state_t cur_state; 

	// Initialize the transmit state
	next_tbuf_elem  = 0;
	tbufs_in_flight = 0;
	last_tx_seq     = 0;

	// Setting the global EOP = 1 will force a dequeue
	tx_state.eop    = 1;

	while(1)
	{
		// Check that the TBUF is available for use
		while (tbufs_in_flight == NUM_TBUFS)
		{
			// We are out of TBUFs, wait for the
			// sequence number to increase
			_spi4_tx_update_tbufs_in_flight(
					&tbufs_in_flight,
					&last_tx_seq);
		}

		// Get the state (next mpacket) for the current
		// TBUF element.
		cur_state = _spi4_tx_get_and_update_state(
							next_tbuf_elem);

		// Move the next portion of the packet into 
		// the next tbuf
		_spi4_tx_move_dram_to_tbuf(
		 				     next_tbuf_elem, 
							 cur_state.cur_mpacket_addr,
							 cur_state.remaining_length, 
							 &dram_to_tbuf_sig);

		// As an optimization, if we have only one 
		// more TBUF available, then 
		// read and update the tbufs in fight during 
		// the transfer from DRAM to TBUF
		if (tbufs_in_flight == (NUM_TBUFS - 1))
		{
			_spi4_tx_update_tbufs_in_flight(
						&tbufs_in_flight,
			 			&last_tx_seq);
		}

		// Wait for the TBUF to be filled
		wait_for_all(&dram_to_tbuf_sig);

		// Write the TBUF control word to validate 
		// the entry
		_spi4_tx_validate_tbuf(
					     next_tbuf_elem, 
						 cur_state.sop, 
						 cur_state.eop, 
						 cur_state.remaining_length);

		// Update the global transmit state
		next_tbuf_elem += TBUF_ELEM_SIZE / 64;
		next_tbuf_elem &= 0x7f;
		tbufs_in_flight++;

		if (cur_state.eop)
		{
			// Free the buffer
			Dl_BufDrop(cur_state.cur_buf_handle);
		}
	}
}

void exit(unsigned int code)
{
	/* EMPTY */
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -