本文主要介绍一个对AXIS数据进行处理和进行功能仿真的例子
1 功能代码
本例子的功能为从输入的AXIS数据包中提取出每一帧第一个时钟周期数据包的前16bit,根据这16bit的数值判断是否为特定的数据包,并随数据包一起输出标识信号。
- 第一个数据包的前16bit为0x5555,则标识也为0x5555,拉高标识有效信号。
- 第一个数据包的前16bit为其它数值,则标识为0x0000,拉高标识有效信号。
在本例子中,每一帧的识别通过tvalid的上升沿确定。为了解决帧连续tvalid没有上升沿的情况,在tlast上升沿的时候将tvliad_1d信号拉低,生成一个上升沿。为了解决一帧数据流中间存在无效数据会产生tvalid上升沿的情况,使用state信号标识是否为同一帧数据。
module preproccess #(
parameter USER_META_DATA_WIDTH = 16,
parameter TDATA_NUM_BYTES = 64
) (
input s_axis_aclk,
input s_axis_aresetn,
// AXIS Slave port
input [TDATA_NUM_BYTES*8-1:0] s_axis_tdata,
input [TDATA_NUM_BYTES-1:0] s_axis_tkeep,
input s_axis_tvalid,
input s_axis_tlast,
output s_axis_tready,
output [USER_META_DATA_WIDTH-1:0] meta,
output meta_valid,
// AXIS Master port
output [TDATA_NUM_BYTES*8-1:0] m_axis_tdata,
output [TDATA_NUM_BYTES-1:0] m_axis_tkeep,
output m_axis_tvalid,
input m_axis_tready,
output m_axis_tlast
);
reg s_axis_tready_r;
reg [USER_META_DATA_WIDTH-1:0] meta_r;
reg meta_valid_r;
reg [TDATA_NUM_BYTES*8-1:0] m_axis_tdata_r;
reg [TDATA_NUM_BYTES-1:0] m_axis_tkeep_r;
reg m_axis_tvalid_r;
reg m_axis_tlast_r;
assign s_axis_tready = s_axis_tready_r;
assign meta = meta_r;
assign meta_valid = meta_valid_r;
assign m_axis_tdata = m_axis_tdata_r;
assign m_axis_tkeep = m_axis_tkeep_r;
assign m_axis_tvalid = m_axis_tvalid_r;
assign m_axis_tlast =m_axis_tlast_r;
reg s_axis_tvalid_1d;
wire s_axis_tvalid_raise;
reg s_axis_tlast_1d;
wire s_axis_tlast_raise;
always @(posedge s_axis_aclk or negedge s_axis_aresetn) begin
if (!s_axis_aresetn) begin
s_axis_tvalid_1d <= 1'b0;
s_axis_tlast_1d <= 1'b0;
end
else if (s_axis_tlast_raise) begin //解决连续数据流tvalid一直有效的情况
s_axis_tvalid_1d <= 1'b0;
end
else begin
s_axis_tvalid_1d <= s_axis_tvalid;
s_axis_tlast_1d <= s_axis_tlast;
end
end
assign s_axis_tvalid_raise = ({s_axis_tvalid, s_axis_tvalid_1d} == 2'b10) ? 1 : 0;
assign s_axis_tlast_raise = ({s_axis_tlast, s_axis_tlast_1d} == 2'b10) ? 1 : 0;
reg state; //状态
always @(posedge s_axis_aclk or negedge s_axis_aresetn) begin
if (!s_axis_aresetn) begin
state <= 1'b1;
end
else if (s_axis_tlast_raise) begin
state <= 1'b1;
end
else if (s_axis_tvalid_raise) begin
state <= 1'b0;
end
else begin
state <= state;
end
end
wire flag; //每一帧第一个数据包的标识,解决一帧数据流中间tvalid信号无效的情况
assign flag = s_axis_tvalid_raise && state;
always @(posedge s_axis_aclk or negedge s_axis_aresetn) begin
if (!s_axis_aresetn) begin
s_axis_tready_r <= 1'b0;
m_axis_tvalid_r <= 1'b0;
m_axis_tkeep_r <= 64'd0;
m_axis_tdata_r <= 512'd0;
m_axis_tlast_r <= 1'b0;
meta_valid_r <= 1'b0;
meta_r <= 16'd0;
end
else if (m_axis_tready) begin
s_axis_tready_r <= 1'b1;
m_axis_tvalid_r <= s_axis_tvalid;
m_axis_tdata_r <= s_axis_tdata;
m_axis_tkeep_r <= s_axis_tkeep;
m_axis_tlast_r <= s_axis_tlast;
if (flag) begin
meta_valid_r <= 1'b1;
if (s_axis_tdata[15:0] == 16'h5555) begin
meta_r <= s_axis_tdata[15:0];
end
else begin
meta_r <= 16'd0;
end
end
else begin
meta_valid_r <= 1'b0;
meta_r <= 16'd0;
end
end
else begin
s_axis_tready_r <= 1'b0;
m_axis_tvalid_r <= 1'b0;
m_axis_tkeep_r <= 64'd0;
m_axis_tdata_r <= 512'd0;
m_axis_tlast_r <= 1'b0;
meta_valid_r <= 1'b0;
meta_r <= 16'd0;
end
end
endmodule
2 仿真代码
为了验证代码功能的正确性,仿真了五种情况。仿真代码使用systemverilog实现,功能代码使用verilog实现,需要说明的是在block design中,使用verilog实现的代码可以直接以模块的方式添加到bd中,而systemverilog却不行。但是systemverilog存在很多的优势,如在本例子,赋值不需要指明位宽,而且‘1代表将所有位都置1,在tkeep信号中比较实用。
- 第一帧数据标识为0x5555
- 第二帧数据与第一帧数据连续,标识为0x1111
- 第三帧数据与第二帧数据之间不连续
- 第四帧数据中间存在无效信号
- 第五帧数据紧接第四帧
module preproccess_tb ();
localparam TDATA_NUM_BYTES = 64;
localparam USER_META_DATA_WIDTH = 16;
// Clocks & Resets
logic s_axis_aclk = 1'b1;
logic s_axis_aresetn = 1'b0;
// Metadata
logic [USER_META_DATA_WIDTH-1:0] meta;
logic meta_valid;
// AXI Slave port
logic [TDATA_NUM_BYTES*8-1:0] s_axis_tdata;
logic [TDATA_NUM_BYTES-1:0] s_axis_tkeep;
logic s_axis_tvalid;
logic s_axis_tlast;
logic s_axis_tready;
// AXI Master port
logic [TDATA_NUM_BYTES*8-1:0] m_axis_tdata;
logic [TDATA_NUM_BYTES-1:0] m_axis_tkeep;
logic m_axis_tvalid;
logic m_axis_tready;
logic m_axis_tlast;
always begin
#5 s_axis_aclk = !s_axis_aclk;
end
initial begin
#10 begin
s_axis_aresetn <= 1;
m_axis_tready <= 0;
s_axis_tvalid <= 0;
s_axis_tdata <= 0;
s_axis_tkeep <= 0;
s_axis_tlast <= 0;
end
#10 begin
m_axis_tready <= 1;
end
#10 begin //第一帧
s_axis_tvalid <= 1;
s_axis_tdata <= {{448{1'b0}}, 64'h1111_1111_5016_5555};
s_axis_tkeep <= '1;
s_axis_tlast <= 0;
end
#10 begin
s_axis_tvalid <= 1;
s_axis_tdata <= {512{1'b0}};
s_axis_tkeep <= '1;
s_axis_tlast <= 1;
end
#10 begin //连续的第二帧
s_axis_tvalid <= 1;
s_axis_tdata <= {{448{1'b0}}, 64'h1111_1111_1111_1111};
s_axis_tkeep <= '1;
s_axis_tlast <= 0;
end
#10 begin
s_axis_tvalid <= 1;
s_axis_tdata <= {512{1'b0}};
s_axis_tkeep <= '1;
s_axis_tlast <= 1;
end
#10 begin
s_axis_tvalid <= 0;
s_axis_tdata <= 0;
s_axis_tkeep <= 0;
s_axis_tlast <= 0;
end
#10 begin //非连续的第三帧
s_axis_tvalid <= 1;
s_axis_tdata <= {{448{1'b0}}, 64'h1111_1111_5016_5555};
s_axis_tkeep <= '1;
s_axis_tlast <= 0;
end
#10 begin
s_axis_tvalid <= 1;
s_axis_tdata <= {512{1'b1}};
s_axis_tkeep <= '1;
s_axis_tlast <= 1;
end
#10 begin
s_axis_tvalid <= 0;
s_axis_tdata <= 0;
s_axis_tkeep <= 0;
s_axis_tlast <= 0;
end
#10 begin //中间非连续的第四帧
s_axis_tvalid <= 1;
s_axis_tdata <= {{448{1'b0}}, 64'h1111_1111_5016_5555};
s_axis_tkeep <= '1;
s_axis_tlast <= 0;
end
#10 begin
s_axis_tvalid <= 0;
s_axis_tdata <= 0;
s_axis_tkeep <= 0;
s_axis_tlast <= 0;
end
#10 begin
s_axis_tvalid <= 1;
s_axis_tdata <= {512{1'b1}};
s_axis_tkeep <= '1;
s_axis_tlast <= 1;
end
#10 begin //后续的第五帧
s_axis_tvalid <= 1;
s_axis_tdata <= {{448{1'b0}}, 64'h1111_1111_5016_5555};
s_axis_tkeep <= '1;
s_axis_tlast <= 0;
end
#10 begin
s_axis_tvalid <= 1;
s_axis_tdata <= {512{1'b1}};
s_axis_tkeep <= '1;
s_axis_tlast <= 1;
end
#10 begin
s_axis_tvalid <= 0;
s_axis_tdata <= 0;
s_axis_tkeep <= 0;
s_axis_tlast <= 0;
end
end
preproccess #(
.USER_META_DATA_WIDTH (USER_META_DATA_WIDTH),
.TDATA_NUM_BYTES (TDATA_NUM_BYTES)
) preproccess_i (
.s_axis_aclk (s_axis_aclk),
.s_axis_aresetn (s_axis_aresetn),
.meta (meta),
.meta_valid (meta_valid),
.s_axis_tdata (s_axis_tdata),
.s_axis_tkeep (s_axis_tkeep),
.s_axis_tvalid (s_axis_tvalid),
.s_axis_tlast (s_axis_tlast),
.s_axis_tready (s_axis_tready),
.m_axis_tdata (m_axis_tdata),
.m_axis_tkeep (m_axis_tkeep),
.m_axis_tvalid (m_axis_tvalid),
.m_axis_tready (m_axis_tready),
.m_axis_tlast (m_axis_tlast)
);
endmodule
3 功能仿真
功能仿真的结果如下图所示,与预期的结果一致