首先Aurora采用AXIS接口
由于后续需要进行AXIS接口 不同时钟域的数据位宽转换(64bit和256bit之间的转换),因此分两次走。
第一种方法:采用AXIS数据位宽转换IP + AXIS跨时钟域IP
第二种方法:逻辑完成
下面记录逻辑实现方法。
为了能正常仿真,首先根据Aurora时序制造数据包。
s_tvlaid、s_tdata 通过计数器来创造,创造不同长度的数据包,其中包含非4的倍数的数据包、刚好4个数据的数据包,仅一个数据的数据包。
//生成计数器(辅助生成s_tvlaid、s_tdata)always @(posedge USER_CLK)if(SYS_RST)r_cnt50 <= 0;else if(r_cnt50 == 6'd50)r_cnt50 <= 0;else r_cnt50 <= r_cnt50 + 1'b1;//生成s_tvalidassign s_tvalid_en = (((r_cnt50 >= 6'd5) && (r_cnt50 <= 6'd15)) || ((r_cnt50 >= 6'd17)&& (r_cnt50 <= 6'd20)) || (r_cnt50 == 6'd40) ) ? 1 : 0;assign s_tvalid = r_tvalid;always @(posedge USER_CLK)if(s_tvalid_en)r_tvalid <= 'b1;elser_tvalid <= 'b0;//生成s_tdata assign s_tdata = r_tdata; always @(posedge USER_CLK)if(s_tvalid_en)r_tdata <= r_tdata + 64'h5; //64'hecff_bc1felser_tdata <= 'b0;//生成s_tlast_en assign s_tlast_en = ((r_cnt50 == 6'd15) || (r_cnt50 == 6'd20) || (r_cnt50 == 6'd40)) ? 1: 0 ; always @(posedge USER_CLK)if(s_tlast_en)r_tlast <= 'b1;elser_tlast <= 'b0;assign s_tlast = r_tlast; //生成s_tkeep assign s_tkeep = s_tlast ? 8'hff : 8'b0;
接下来就是AXIS接口 64bit转256bit
首先设计256bit移位寄存器
第一种方法:
//设计移位寄存器,先进的放低位always @(posedge USER_CLK)if(s_tvalid)r_s_tdata_SHIFT <= {s_tdata,r_s_tdata_SHIFT[255:64]}; else r_s_tdata_SHIFT <= r_s_tdata_SHIFT;
第二种方法:
reg [63:0] r1_s_tdata = 'b0;reg [63:0] r2_s_tdata = 'b0;reg [63:0] r3_s_tdata = 'b0;wire [255:0] s_data_256 ;//s_tdata打三拍always @(posedge USER_CLK)beginr1_s_tdata <= s_tdata ; r2_s_tdata <= r1_s_tdata;r3_s_tdata <= r2_s_tdata;endassign s_data_256 = {s_tdata,r1_s_tdata,r2_s_tdata,r3_s_tdata};
拼接后的波形图如下:
生成转换后的m_tvalid信号
由于64bit转256,所以比率是4:1
那么生成4计数器,从而指示转换成的256bit数据有效
//设计 4:1计数器 always @(posedge USER_CLK)beginif(s_tlast & s_tvalid )r_CNT2 <= 2'd0 ;else if(s_tvalid) r_CNT2 <= r_CNT2 + 1'b1 ;elser_CNT2 <= r_CNT2 ; end//生成 m_tvalidalways @(posedge USER_CLK)beginif(((r_CNT2 == 2'd3) || s_tlast) & s_tvalid) m_tvalid <= 1'b1 ; elsem_tvalid <= 1'b0 ; end
生成tlast信号,不管数据包是不是4的倍数,总会被移入256bit寄存器,转换后的m_tlast信号相当于是比之前的s_talst晚一拍
//生成m_tlast always @(posedge USER_CLK)beginif( s_tlast & s_tvalid) m_tlast <= 1'b1 ; elsem_tlast <= 1'b0 ; end
生成m_tkeep ,首先确定最后一个256bit数据,即m_tlast对应的256bit数据的m_tkeep值,这里根据移入寄存器的个数有关。
也就是说,当计数器为0的表示,还没移入数据;当为1移入第一个64bit数据,因此是八个字节有效,所以最后一个数据位置的m_tkeep的低八位为1,即可8‘hff,以此类推。
从而确定最终的m_tkeep值。
//生成m_tkeep always @(*)begincase(r_CNT2)2'd0 : r_tkeep_TEMP = { 8'h00 , 8'h00, 8'h00 , s_tkeep } ;2'd1 : r_tkeep_TEMP = { 8'h00 , 8'h00, s_tkeep , 8'hff } ;2'd2 : r_tkeep_TEMP = { 8'h00 , s_tkeep , 8'hff , 8'hff } ;2'd3 : r_tkeep_TEMP = { s_tkeep , 8'hff , 8'hff , 8'hff } ;default : r_tkeep_TEMP = 32'd0 ; endcaseend//s_tlast位置对应的tkeepalways @(posedge USER_CLK)beginif(s_tlast & s_tvalid)m_tkeep <= r_tkeep_TEMP ;elsem_tkeep <= 32'hffff_ffff;end
由于我们发的第一个数据包中有11个64bit数据,因此最后一拍256bit数据中仅包含3个64bit数据,所以24个字节有效,因此m_tkeep的高两位为0,剩下为f。
把拼接后的256bit数据取出来。
重点在于,取出的256bit数据要保证在m_tvalid时刻有效,不然是不符合axis接口时序的,后续没办法使用。
//把拼接数据取出reg [255:0] r_s_data_256 = 'b0 ;reg [255:0] data_256_1 = 'b0 ;wire [255:0] data_256_2 ;reg [255:0] r_STDATA = 'b0 ;reg [255:0] r_s_tdata_tmp = 'b0 ;reg [255:0] r_STDATA_1 = 'b0 ;always @(posedge USER_CLK)r_s_data_256 <= s_data_256;always @(posedge USER_CLK)if(m_tvalid)data_256_1 <= r_s_data_256;elsedata_256_1 <= data_256_1;assign data_256_2 = m_tvalid ? r_s_data_256 :'b0 ;always @(posedge USER_CLK)beginif(((r_CNT2 == 2'd3) || s_tlast) & s_tvalid)r_STDATA <= s_data_256;elser_STDATA <= r_STDATA;end //方法二always @(*)begincase(r_CNT2)2'd0 : r_s_tdata_tmp = { 8'h00 , 8'h00, 8'h00 , s_tdata } ;2'd1 : r_s_tdata_tmp = { 8'h00 , 8'h00, s_tdata , r_s_tdata_SHIFT[255:192] } ;2'd2 : r_s_tdata_tmp = { 8'h00 , s_tdata , r_s_tdata_SHIFT[255:128] } ;2'd3 : r_s_tdata_tmp = { s_tdata , r_s_tdata_SHIFT[255:64] } ;default : r_s_tdata_tmp = 256'd0 ; endcaseendalways @(posedge USER_CLK)beginif(((r_CNT2 == 2'd3) || s_tlast) & s_tvalid)r_STDATA_1 <= r_s_tdata_tmp;elser_STDATA_1 <= r_STDATA_1;end
简单记录一下该方法,后面还要用到,还需要在好好理解一下,尤其是转换前后tready信号,还是不大懂。