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

📄 usb1_pa.v

📁 usb1.1 ip核
💻 V
字号:
/////////////////////////////////////////////////////////////////////////                                                             ////////  Packet Assembler                                           ////////  Assembles Token and Data USB packets                       ////////                                                             ////////  Author: Rudolf Usselmann                                   ////////          rudi@asics.ws                                      ////////                                                             ////////                                                             ////////  Downloaded from: http://www.opencores.org/cores/usb1_funct/////////                                                             /////////////////////////////////////////////////////////////////////////////                                                             //////// Copyright (C) 2000-2002 Rudolf Usselmann                    ////////                         www.asics.ws                        ////////                         rudi@asics.ws                       ////////                                                             //////// This source file may be used and distributed without        //////// restriction provided that this copyright statement is not   //////// removed from the file and that any derivative work contains //////// the original copyright notice and the associated disclaimer.////////                                                             ////////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     //////// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   //////// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   //////// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      //////// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         //////// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    //////// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   //////// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        //////// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  //////// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  //////// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  //////// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         //////// POSSIBILITY OF SUCH DAMAGE.                                 ////////                                                             ///////////////////////////////////////////////////////////////////////////  CVS Log////  $Id: usb1_pa.v,v 1.1.1.1 2002/09/19 12:07:13 rudi Exp $////  $Date: 2002/09/19 12:07:13 $//  $Revision: 1.1.1.1 $//  $Author: rudi $//  $Locker:  $//  $State: Exp $//// Change History://               $Log: usb1_pa.v,v $//               Revision 1.1.1.1  2002/09/19 12:07:13  rudi//               Initial Checkin////还有些疑问:rd_next,last,tx_valid_d,tx_valid_last!!!//////////`include "usb1_defines.v"module usb1_pa(	clk, rst,		// UTMI TX I/F		tx_data, tx_valid, tx_valid_last, tx_ready,		tx_first,		// Protocol Engine Interface		send_token, token_pid_sel,		send_data, data_pid_sel,		// IDMA Interface		tx_data_st, rd_next,		ep_empty		);input		clk, rst;// UTMI TX Interfaceoutput	[7:0]	tx_data;output		tx_valid;output		tx_valid_last;input		tx_ready;output		tx_first;// Protocol Engine Interfaceinput		send_token;input	[1:0]	token_pid_sel;input		send_data;		//事实上这个由idma提供input	[1:0]	data_pid_sel;// IDMA Interfaceinput	[7:0]	tx_data_st;output		rd_next;input		ep_empty;/////////////////////////////////////////////////////////////////////// Local Wires and Registers//parameter	[3:0]	// synopsys enum state		IDLE   = 4'b0001,		DATA   = 4'b0010,		CRC1   = 4'b0100,		CRC2   = 4'b1000;reg	[3:0]	/* synopsys enum state */ state, next_state;// synopsys state_vector statereg		last;//这个是干什么的??reg		rd_next;//不明,可以去查idma模块reg	[7:0]	token_pid, data_pid;	// PIDs from selectorsreg	[7:0]	tx_data_d;//跟tx_data什么关系?reg	[7:0]	tx_data_data;//这是干什么的?reg		dsel;       //用来选tx_spec_data的reg		tx_valid_d;//跟tx_valid什么关系?输出的寄存器reg		send_token_r;reg	[7:0]	tx_spec_data;reg		crc_sel1, crc_sel2;reg		tx_first_r;reg		send_data_r;wire		crc16_clr;reg	[15:0]	crc16;wire	[15:0]	crc16_next;wire	[15:0]	crc16_rev;reg		crc16_add;//这个是一位信号reg		send_data_r2;//注意send_data有两级寄存器reg		tx_valid_r;//不是有了tx_valid_d作寄存器吗?reg		tx_valid_r1;//153行,搞这么多级为了什么??wire		zero_length;//wire型/////////////////////////////////////////////////////////////////////// Misc Logic//reg		zero_length_r;//零长度寄存器,干什么用的?assign		zero_length = ep_empty;//根本不知道它们在干什么!端点空always @(posedge clk or negedge rst)	if(!rst)	zero_length_r <= #1 1'b0;//复位时,零长寄存器清零	else	if(last)	zero_length_r <= #1 1'b0;//这个last从哪里来的?状态机产生的	else	if(crc16_clr)	zero_length_r <= #1 zero_length;//如果清除crc16,那么就把ep_empty的信号写入之always @(posedge clk)  //一级缓冲装载	tx_valid_r1 <= #1 tx_valid;//134行always @(posedge clk) //二级缓冲装载	tx_valid_r <= #1 tx_valid_r1;//在做什么!!!你看看上句always @(posedge clk or negedge rst)	if(!rst)	send_token_r <= #1 1'b0;//复位清零	else	if(send_token)	send_token_r <= #1 1'b1;//send_token_r缓冲保存send_token	else	if(tx_ready)	send_token_r <= #1 1'b0;//utmi可传输却清零,为什么?表达一种清零关系而已吧?// PID Select握手包装配always @(token_pid_sel)	case(token_pid_sel)		// synopsys full_case parallel_case	   2'd0: token_pid = {  ~`USBF_T_PID_ACK,   `USBF_T_PID_ACK};	   2'd1: token_pid = { ~`USBF_T_PID_NACK,  `USBF_T_PID_NACK};	   2'd2: token_pid = {~`USBF_T_PID_STALL, `USBF_T_PID_STALL};	   2'd3: token_pid = { ~`USBF_T_PID_NYET,  `USBF_T_PID_NYET};	endcasealways @(data_pid_sel)//数据包标识符装配	case(data_pid_sel)		// synopsys full_case parallel_case	   2'd0: data_pid = { ~`USBF_T_PID_DATA0, `USBF_T_PID_DATA0};	   2'd1: data_pid = { ~`USBF_T_PID_DATA1, `USBF_T_PID_DATA1};	   2'd2: data_pid = { ~`USBF_T_PID_DATA2, `USBF_T_PID_DATA2};	   2'd3: data_pid = { ~`USBF_T_PID_MDATA, `USBF_T_PID_MDATA};	endcase// Data path Muxesalways @(send_token or send_token_r or token_pid or tx_data_data)//发送握手包还是数据	if(send_token | send_token_r)	tx_data_d = token_pid;	else				tx_data_d = tx_data_data;//tx_data_data是要传输的数据的二级缓冲always @(dsel or tx_data_st or tx_spec_data)//tx_data_data在tx_data_st和	if(dsel)	tx_data_data = tx_spec_data;//tx_spec_data中作选择,由dsel决定,dsel好象是用来选择特殊数据的	else		tx_data_data = tx_data_st;//这个进程装载tx_spec_dataalways @(crc_sel1 or crc_sel2 or data_pid or crc16_rev)//如果crc_sel1和crc_sel2均为低,则组装数据包标识符	if(!crc_sel1 & !crc_sel2)	tx_spec_data = data_pid;//	else	if(crc_sel1)			tx_spec_data = crc16_rev[15:8];	// CRC 1	else				tx_spec_data = crc16_rev[7:0];	// CRC 2assign tx_data = tx_data_d;//这个缓冲关系要留下印象,这可不是什么缓冲关系,引脚直接相连了!!!// TX Valid assignment 看不懂assign tx_valid_last = send_token | last;//这个条件不完全懂,tx_valid_last可去utmi查assign tx_valid = tx_valid_d;//直接相连了,值永远保持一致always @(posedge clk)//只要是有东西要发送了,那么tx_first_r就变高	tx_first_r <= #1 send_token | send_data;		assign tx_first = (send_token | send_data) & ! tx_first_r;//有东西要发且tx_first_r为低才可使tx_first为高,可能出现毛刺// CRC Logicalways @(posedge clk)	send_data_r <= #1 send_data;always @(posedge clk)	send_data_r2 <= #1 send_data_r;assign crc16_clr = send_data & !send_data_r;//清零条件的巧妙                                            //send_data为高,send_data_r为低清零always @(posedge clk)//设定crc16_add信号,crc16_add究竟是干什么的?可能是表明什么时候需要装配上crc16的	crc16_add <= #1 !zero_length_r &			((send_data_r & !send_data_r2) | (rd_next & !crc_sel1));//搞清last在里面起的关键作用,直接控制了                                                                    //zero_length_r的清零与否。   always @(posedge clk)	if(crc16_clr)		crc16 <= #1 16'hffff;//置位同步,但我担心它的时序.不必担心:)	else	if(crc16_add)		crc16 <= #1 crc16_next;//需要加载crc16usb1_crc16 u1(                      //难道下一次的crc16码还与本次的有关?想通了,因为crc16可能是要校验多个字节的数据	.crc_in(	crc16		),	.din(	{tx_data_st[0], tx_data_st[1],		tx_data_st[2], tx_data_st[3],		tx_data_st[4], tx_data_st[5],		tx_data_st[6], tx_data_st[7]}	),	.crc_out(	crc16_next		) );assign crc16_rev[15] = ~crc16[8];assign crc16_rev[14] = ~crc16[9];assign crc16_rev[13] = ~crc16[10];assign crc16_rev[12] = ~crc16[11];assign crc16_rev[11] = ~crc16[12];assign crc16_rev[10] = ~crc16[13];assign crc16_rev[9]  = ~crc16[14];assign crc16_rev[8]  = ~crc16[15];assign crc16_rev[7]  = ~crc16[0];assign crc16_rev[6]  = ~crc16[1];assign crc16_rev[5]  = ~crc16[2];assign crc16_rev[4]  = ~crc16[3];assign crc16_rev[3]  = ~crc16[4];assign crc16_rev[2]  = ~crc16[5];assign crc16_rev[1]  = ~crc16[6];assign crc16_rev[0]  = ~crc16[7];/////////////////////////////////////////////////////////////////////// Transmit/Encode state machine//always @(posedge clk or negedge rst)	if(!rst)	state <= #1 IDLE;//复位为空闲状态	else		state <= #1 next_state;always @(state or send_data or tx_ready or tx_valid_r or zero_length)//由此可见判断总线上的数据是否有效都是用的tx_valid_r   begin	next_state = state;	// Default don't change current state	tx_valid_d = 1'b0;//每次开始执行时,给utmi的信号都通报总线上的数据无效	dsel = 1'b0;//用来选tx_spec_data的,每次开始时,都切换为tx_data_st	rd_next = 1'b0;//跟idma有关	last = 1'b0;//刚开始时都清零	crc_sel1 = 1'b0;	crc_sel2 = 1'b0;	case(state)		// synopsys full_case parallel_case	   IDLE:		   begin			if(zero_length & send_data)//要传数据并且零长度,注意:zero_length是直接连到ep_empty的			   begin				tx_valid_d = 1'b1;				dsel = 1'b1;//此时,数据包的data_pid已送出,这个时钟一到,这个data_pid就通过tx_data存到utmi中了				next_state = CRC1;//因为是零长度的数据包,下面自动去crc16模块			   end			else			if(send_data)		// Send DATA packet,不是零长度的数据包			   begin				tx_valid_d = 1'b1;				dsel = 1'b1;   //这个时候,已发出data_pid				next_state = DATA;			   end		   end	   DATA: //切换到该状态时,dsel已自己清零了,会把tx_data_st存到tx_data_d		   begin			if(tx_ready & tx_valid_r)//可以传输并且前一个时钟在总线上的数据有效,注意它用的是tx_valid_r				rd_next = 1'b1;//应该是准备读下个数据了			tx_valid_d = 1'b1;//告诉utmi数据有效。有效数据已送出,我总觉得这句和上句该调换位置			if(!send_data & tx_ready & tx_valid_r)//如果数据传输完并且可以传输,而且前一个在总线上的数据有效(何必加这个条件)			   begin                              //则开始装配crc				dsel = 1'b1;				crc_sel1 = 1'b1;				next_state = CRC1;			   end		   end	   CRC1:		   begin			dsel = 1'b1;			tx_valid_d = 1'b1;//表明数据有效,此时crc1已放到总线上			if(tx_ready)//如果此时可以传输,如果这个条件为真,那么上个时钟发送的data_pid已经送出到主机了,如果是零字节数据,是有点问题!!			   begin				last = 1'b1;//准备传crc2				crc_sel2 = 1'b1;//我认为现在不必将之置为1				next_state = CRC2;//crc1传完,准备切换到crc2			   end			else//如果此时忙,不能传输,则不跳到下个状态crc2,而继续传输crc1			   begin				tx_valid_d = 1'b1;				crc_sel1 = 1'b1;			   end		   end	   CRC2:		   begin			dsel = 1'b1;			crc_sel2 = 1'b1;//到这里时,已将crc2的数据放到tx_data_d中了。这里有疑问:需要的crc数据是放上去了,但是tx_valid_d为零啊!!!有可能被last搞定			if(tx_ready)			   begin				next_state = IDLE;//crc2装载完毕,回到idle状态			   end			else			   begin				last = 1'b1;//继续传crc2			   end		   end	endcase   endendmodule

⌨️ 快捷键说明

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