📄 tests_lib.v
字号:
///////////////////////////////////////////////////////////////////////// //////// Test Bench Library //////// //////// //////// 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: tests_lib.v,v 1.1 2002/09/25 06:10:10 rudi Exp $//// $Date: 2002/09/25 06:10:10 $// $Revision: 1.1 $// $Author: rudi $// $Locker: $// $State: Exp $//// Change History:// $Log: tests_lib.v,v $// Revision 1.1 2002/09/25 06:10:10 rudi// Added Test Bench//////////////task show_errors;//这是任务begin$display("\n");$display(" +--------------------+");$display(" | Total ERRORS: %0d |", error_cnt);$display(" +--------------------+");endendtasktask recv_packet;//主机收到数据包output [3:0] pid;//应该仅是数据包的标识符output size;//有效数据载荷,即除去pid和crc16后的东西integer del, size,n;//del没有用????reg [15:0] crc16r;reg [7:0] x,y;begincrc16r = 16'hffff;//全一,算是初始化吧utmi_recv_pack(size);//两个作用:将主机接收到的数据存在txmen中,二,将接收到的总字节数存在size中for(n=1;n<size-2;n=n+1)//n从1到size-3,不包含0,和size-2,size-1,因为0是pid,最后两个是crc16 begin y = txmem[n];//注意x的存放顺序,是为了计算crc16而设定的顺序 x[7] = y[0]; x[6] = y[1]; x[5] = y[2]; x[4] = y[3]; x[3] = y[4]; x[2] = y[5]; x[1] = y[6]; x[0] = y[7]; crc16r = crc16(crc16r, x);//crc16(crc_in,din),这里的crc16是一个函数 end//到这里时,针对payload部分的crc16校验已经计算完毕,存在crc16r中y = crc16r[15:8];x[7] = y[0];x[6] = y[1];x[5] = y[2];x[4] = y[3];x[3] = y[4];x[2] = y[5];x[1] = y[6];x[0] = y[7];crc16r[15:8] = ~x;//实际上是将crc16的高8位重新排了个序y = crc16r[7:0];x[7] = y[0];x[6] = y[1];x[5] = y[2];x[4] = y[3];x[3] = y[4];x[2] = y[5];x[1] = y[6];x[0] = y[7];crc16r[7:0] = ~x;//实际上是将crc16的低8位重新排了个序//到这里时,按照标准顺序排列的crc16已经存在crc16r中了if(crc16r !== {txmem[n], txmem[n+1]})//注意位对位的匹配,我这里已看不清了,因为它的crc16算法不明$display("ERROR: CRC Mismatch: Expected: %h, Got: %h%h (%t)", crc16r, txmem[n], txmem[n+1], $time);for(n=0;n<size-3;n=n+1)//把数据存到缓冲区去了,二级缓冲的样子,存到buffer1中了 buffer1[buffer1_last+n] = txmem[n+1];buffer1_last = buffer1_last+n;//修改buffer1的指针使它指向空白区// Check PIDx = txmem[0];if(x[7:4] !== ~x[3:0])//注意!==为不全等运算符$display("ERROR: Pid Checksum mismatch: Top: %h Bottom: %h (%t)", x[7:4], x[3:0], $time);pid = x[3:0];size=size-3;//减掉了pid和crc16endendtasktask send_token;//主机发送令牌包input [6:0] fa;input [3:0] ep;input [3:0] pid;reg [15:0] tmp_data;reg [10:0] x,y;//11位integer len;begintmp_data = {fa, ep, 5'h0};//被凑成16位了if(pid == `USBF_T_PID_ACK) len = 1;//看到这里我可以确定是主机发送的令牌包了,因为主机只有一种握手包就是ackelse len = 3;y = {fa, ep};//11位x[10] = y[4];//它这么变换的目的是什么????x[9] = y[5]; //是不是为了适应crc5输入的需要????不明白,crc5是按发送先后顺序计算的,我认为一点都不直观,不好x[8] = y[6];x[7] = y[7];x[6] = y[8];x[5] = y[9];x[4] = y[10];x[3] = y[0];x[2] = y[1];x[1] = y[2];x[0] = y[3];y[4:0] = crc5( 5'h1f, x );//算出来crc5了,注意到全1输入!!!为什么?还不是初始化吗,傻瓜!tmp_data[4:0] = ~y[4:0];tmp_data[15:5] = x;txmem[0] = {~pid, pid}; // PID,注意了,tmp_data中的数据是按位发送的先后顺序排列的,即倒序txmem[1] = { tmp_data[8],tmp_data[9],tmp_data[10],tmp_data[11], tmp_data[12],tmp_data[13],tmp_data[14],tmp_data[15]};txmem[2] = { tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3], tmp_data[4],tmp_data[5],tmp_data[6],tmp_data[7]};utmi_send_pack(len);//把要发送的令牌或握手包送出去了,要发送的数据存在txmem中endendtasktask send_sof;//传送帧开始包input [10:0] frmn;//给定要传送的帧号reg [15:0] tmp_data;reg [10:0] x,y;beginy = frmn;x[10] = y[0];x[9] = y[1];x[8] = y[2];x[7] = y[3];x[6] = y[4];x[5] = y[5];x[4] = y[6];x[3] = y[7];x[2] = y[8];x[1] = y[9];x[0] = y[10];tmp_data[15:5] = x;//注意,tmp_data是按发送的位先后顺序排列的y[4:0] = crc5( 5'h1f, x );tmp_data[4:0] = ~y[4:0];txmem[0] = {~`USBF_T_PID_SOF, `USBF_T_PID_SOF}; // PIDtxmem[1] = { tmp_data[8],tmp_data[9],tmp_data[10],tmp_data[11], tmp_data[12],tmp_data[13],tmp_data[14],tmp_data[15]};txmem[2] = { tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3], tmp_data[4],tmp_data[5],tmp_data[6],tmp_data[7]};txmem[1] = frmn[7:0];//这里展示了另一种装载txmem的算法,一样的txmem[2] = { tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3], tmp_data[4], frmn[10:8] };utmi_send_pack(3);endendtaskfunction [4:0] crc5;//搞清楚为什么送入的crc5是全一,见204行,傻猫还问,不是说了吗,那是初始化input [4:0] crc_in;input [10:0] din;reg [4:0] crc_out;//这个好象根本没用到begincrc5[0] = din[10] ^ din[9] ^ din[6] ^ din[5] ^ din[3] ^ din[0] ^ crc_in[0] ^ crc_in[3] ^ crc_in[4];crc5[1] = din[10] ^ din[7] ^ din[6] ^ din[4] ^ din[1] ^ crc_in[0] ^ crc_in[1] ^ crc_in[4];crc5[2] = din[10] ^ din[9] ^ din[8] ^ din[7] ^ din[6] ^ din[3] ^ din[2] ^ din[0] ^ crc_in[0] ^ crc_in[1] ^ crc_in[2] ^ crc_in[3] ^ crc_in[4];crc5[3] = din[10] ^ din[9] ^ din[8] ^ din[7] ^ din[4] ^ din[3] ^ din[1] ^ crc_in[1] ^ crc_in[2] ^ crc_in[3] ^ crc_in[4];crc5[4] = din[10] ^ din[9] ^ din[8] ^ din[5] ^ din[4] ^ din[2] ^ crc_in[2] ^ crc_in[3] ^ crc_in[4];endendfunctiontask send_data;//主机发送数据包input [3:0] pid;//给定包标识符input len;//给定数据包的payload长度input mode;//这个是什么?在协议中可找不到这么野蛮的东西!!测着玩的,别当真integer n, len, mode, delay;reg [15:0] crc16r;reg [7:0] x,y;begintxmem[0] = {~pid, pid}; // PIDcrc16r = 16'hffff;//初始化for(n=0;n<len;n=n+1) begin if(mode==1) y = buffer1[buffer1_last+n];//和主机接收时一样,都用的是buffer1 else y = n;//想不通它在传什么,0到len-1 x[7] = y[0]; x[6] = y[1]; x[5] = y[2]; x[4] = y[3]; x[3] = y[4]; x[2] = y[5]; x[1] = y[6]; x[0] = y[7]; txmem[n+1] = y;//要发送的数据送到发送接收仓:txmen,感觉象是码头 crc16r = crc16(crc16r, x);//一直在累积计算 endbuffer1_last = buffer1_last + n;//修改buffer1_last指针,使它指向下一片数据y = crc16r[15:8];x[7] = y[0];x[6] = y[1];x[5] = y[2];x[4] = y[3];x[3] = y[4];x[2] = y[5];x[1] = y[6];x[0] = y[7];txmem[n+1] = ~x;//整理成某种规定的格式再发送y = crc16r[7:0];x[7] = y[0];x[6] = y[1];x[5] = y[2];x[4] = y[3];x[3] = y[4];x[2] = y[5];x[1] = y[6];x[0] = y[7];txmem[n+2] = ~x;//注意这里变为n+2,因为没有for语句给的n=n+1了utmi_send_pack(len+3);//加3是因为有pid和crc16endendtaskfunction [15:0] crc16;//一个函数input [15:0] crc_in;input [7:0] din;reg [15:0] crc_out;begincrc_out[0] = din[7] ^ din[6] ^ din[5] ^ din[4] ^ din[3] ^ din[2] ^ din[1] ^ din[0] ^ crc_in[8] ^ crc_in[9] ^ crc_in[10] ^ crc_in[11] ^ crc_in[12] ^ crc_in[13] ^ crc_in[14] ^ crc_in[15];crc_out[1] = din[7] ^ din[6] ^ din[5] ^ din[4] ^ din[3] ^ din[2] ^ din[1] ^ crc_in[9] ^ crc_in[10] ^ crc_in[11] ^ crc_in[12] ^ crc_in[13] ^ crc_in[14] ^ crc_in[15];crc_out[2] = din[1] ^ din[0] ^ crc_in[8] ^ crc_in[9];crc_out[3] = din[2] ^ din[1] ^ crc_in[9] ^ crc_in[10];crc_out[4] = din[3] ^ din[2] ^ crc_in[10] ^ crc_in[11];crc_out[5] = din[4] ^ din[3] ^ crc_in[11] ^ crc_in[12];crc_out[6] = din[5] ^ din[4] ^ crc_in[12] ^ crc_in[13];crc_out[7] = din[6] ^ din[5] ^ crc_in[13] ^ crc_in[14];crc_out[8] = din[7] ^ din[6] ^ crc_in[0] ^ crc_in[14] ^ crc_in[15];crc_out[9] = din[7] ^ crc_in[1] ^ crc_in[15];crc_out[10] = crc_in[2];crc_out[11] = crc_in[3];crc_out[12] = crc_in[4];crc_out[13] = crc_in[5];crc_out[14] = crc_in[6];crc_out[15] = din[7] ^ din[6] ^ din[5] ^ din[4] ^ din[3] ^ din[2] ^ din[1] ^ din[0] ^ crc_in[7] ^ crc_in[8] ^ crc_in[9] ^ crc_in[10] ^ crc_in[11] ^ crc_in[12] ^ crc_in[13] ^ crc_in[14] ^ crc_in[15];crc16 = crc_out;//必不可少endendfunction/////////////////////////////////////////////////////////////////////// UTMI Low level Tasks//task utmi_send_pack;//这也是指主机发送input size;integer n,size;begin@(posedge clk);//等到一个时钟上升沿#1;tb_tx_valid = 1'b1;//先让待发送的数据有效for(n=0;n<size;n=n+1)//n从0到size-1,全部发送 begin tb_txdata = txmem[n];//送上前线 @(posedge clk);//等到下一个时钟上升沿 #2; while(!tb_tx_ready) @(posedge clk);//如果phy没有准备好传输,就等到下一个时钟上升沿,一直到发出去为止 #1; endtb_tx_valid = 1'b0;//发送完毕,通知phy,线上的数据无效@(posedge clk);//等一个时钟上升沿endendtasktask utmi_recv_pack;//这是指主机接收output size;integer size;beginsize = 0;while(!tb_rx_active) @(posedge clk);//如果没有检测到同步头,就等到下一个时钟上升沿来。while(tb_rx_active) begin #1; while(!tb_rx_valid & tb_rx_active) @(posedge clk);//当检测到同步头但是数据还是无效时,等下一个时钟上升沿来 if(tb_rx_valid & tb_rx_active) begin txmem[size] = tb_rxdata;//搞清楚txmen是什么缓冲区!存传来的数据 size = size + 1;//传送的字节数 end @(posedge clk);//无条件等到下一个时钟上升沿来 endendendtask
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -