文章目录
- 前言
- 一、设计框图
- 二、模块介绍
- 三、上板验证
- 总结
前言
本文将通过使用SRIO IP核实现数据通信,重点在于打通数据链路,具体的协议内容设计并非重点,打通了链路大家自己根据设计需求来即可。
一、设计框图
看了前面高速接口的一些设计,大家应该也比较熟悉xilinx的高速接口设计风格了,无非就是时钟、复位、common还有IP核。
二、模块介绍
复位和时钟模块在上一篇介绍时钟和复位的时候进行了介绍。与之前高速接口不同的是RapidIO有一套自己的交互协议规范,所以在基于FPGA进行设计的时候,需要按照规范进行传输数据和解析数据。我们重点不在于这块,因为我没有接触过这方面的需求,所以暂时只是可以使IP核实现正常的通信即可。
以下是一个很简单的数据收发模块,参考FPGA奇哥:https://space.bilibili.com/497026889/?spm_id_from=333.999.0.0
该代码实现以下功能:
- 发起一次写事务
- 发起一次门铃事件
- 发起一次读事件
- 发起一次消息事件
由于我是在FPGA上进行通信,所以整个实验仅仅是实现了这些消息的传输过程,并没有所谓的DMA,中端处理等。
module SRIO_engine(
input i_clk ,
input i_rst ,
output m_axis_ireq_tvalid ,
input m_axis_ireq_tready ,
output m_axis_ireq_tlast ,
output [63:0] m_axis_ireq_tdata ,
output [7 :0] m_axis_ireq_tkeep ,
output [31:0] m_axis_ireq_tuser ,
input s_axis_iresp_tvalid ,
output s_axis_iresp_tready ,
input s_axis_iresp_tlast ,
input [63:0] s_axis_iresp_tdata ,
input [7 :0] s_axis_iresp_tkeep ,
input [31:0] s_axis_iresp_tuser ,
input s_axis_treq_tvalid ,
output s_axis_treq_tready ,
input s_axis_treq_tlast ,
input [63:0] s_axis_treq_tdata ,
input [7 :0] s_axis_treq_tkeep ,
input [31:0] s_axis_treq_tuser ,
output m_axis_tresp_tvalid ,
input m_axis_tresp_tready ,
output m_axis_tresp_tlast ,
output [63:0] m_axis_tresp_tdata ,
output [7 :0] m_axis_tresp_tkeep ,
output [31:0] m_axis_tresp_tuser
);
/******************************function*****************************/
/******************************parameter****************************/
/******************************mechine******************************/
localparam P_ST_IDLE = 0 ,
P_ST_WRITE = 1 ,
P_ST_DB = 2 ,
P_ST_READ = 3 ,
P_ST_MESSAGE = 4 ,
P_ST_END = 5 ;
reg [7 :0] r_st_current ;
reg [7 :0] r_st_next ;
reg [15:0] r_st_cnt ;
/******************************reg**********************************/
reg rm_axis_ireq_tvalid ;
reg rm_axis_ireq_tlast ;
reg [63:0] rm_axis_ireq_tdata ;
reg [7 :0] rm_axis_ireq_tkeep ;
reg [31:0] rm_axis_ireq_tuser ;
reg rs_axis_iresp_tready ;
reg rs_axis_treq_tready ;
reg rm_axis_tresp_tvalid ;
reg rm_axis_tresp_tlast ;
reg [63:0] rm_axis_tresp_tdata ;
reg [7 :0] rm_axis_tresp_tkeep ;
reg [31:0] rm_axis_tresp_tuser ;
reg [15:0] r_pkt_cnt ;
reg [7 :0] r_read_cmd ;
reg r_read_cmd_valid ;
reg r_read_triger ;
reg [15:0] r_treq_cnt ;
reg [15:0] r_read_cnt ;
/******************************wire*********************************/
wire w_m_axis_ireq_act ;
wire w_s_axis_iresp_act ;
wire w_s_axis_treq_act ;
wire w_m_axis_tresp_act ;
/******************************component****************************/
/******************************assign*******************************/
assign m_axis_ireq_tvalid = rm_axis_ireq_tvalid ;
assign m_axis_ireq_tlast = rm_axis_ireq_tlast ;
assign m_axis_ireq_tdata = rm_axis_ireq_tdata ;
assign m_axis_ireq_tkeep = rm_axis_ireq_tkeep ;
assign m_axis_ireq_tuser = rm_axis_ireq_tuser ;
assign s_axis_iresp_tready = rs_axis_iresp_tready ;
assign s_axis_treq_tready = rs_axis_treq_tready ;
assign m_axis_tresp_tvalid = rm_axis_tresp_tvalid ;
assign m_axis_tresp_tlast = rm_axis_tresp_tlast ;
assign m_axis_tresp_tdata = rm_axis_tresp_tdata ;
assign m_axis_tresp_tkeep = rm_axis_tresp_tkeep ;
assign m_axis_tresp_tuser = rm_axis_tresp_tuser ;
assign w_m_axis_ireq_act = m_axis_ireq_tvalid & m_axis_ireq_tready;
assign w_s_axis_iresp_act = s_axis_iresp_tvalid & s_axis_iresp_tready;
assign w_s_axis_treq_act = s_axis_treq_tvalid & s_axis_treq_tready;
assign w_m_axis_tresp_act = m_axis_tresp_tvalid & m_axis_tresp_tready;
/******************************always*******************************/
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_current <= P_ST_IDLE;
else
r_st_current <= r_st_next;
end
always@(*)
begin
case(r_st_current)
P_ST_IDLE :r_st_next <= r_st_cnt == 1000 ? P_ST_WRITE : P_ST_IDLE ;
P_ST_WRITE :r_st_next <= w_m_axis_ireq_act & rm_axis_ireq_tlast ? P_ST_DB : P_ST_WRITE ;
P_ST_DB :r_st_next <= w_m_axis_ireq_act & rm_axis_ireq_tlast ? P_ST_READ : P_ST_DB ;
P_ST_READ :r_st_next <= w_s_axis_iresp_act & s_axis_iresp_tlast ? P_ST_MESSAGE : P_ST_READ ;
P_ST_MESSAGE :r_st_next <= w_m_axis_ireq_act & rm_axis_ireq_tlast ? P_ST_END : P_ST_MESSAGE ;
P_ST_END :r_st_next <= P_ST_IDLE;
default :r_st_next <= P_ST_IDLE;
endcase
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_cnt <= 'd0;
else if(r_st_current != r_st_next)
r_st_cnt <= 'd0;
else
r_st_cnt <= r_st_cnt + 1;
end
//======================Initiator===========================//
//组包逻辑
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rs_axis_treq_tready <= 'd0;
else
rs_axis_treq_tready <= 'd1;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rs_axis_iresp_tready <= 'd0;
else
rs_axis_iresp_tready <= 'd1;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_ireq_tvalid <= 'd0;
else if(w_m_axis_ireq_act && rm_axis_ireq_tlast)
rm_axis_ireq_tvalid <= 'd0;
else if(r_st_current == P_ST_WRITE && r_st_cnt == 0)
rm_axis_ireq_tvalid <= 'd1;
else if(r_st_current == P_ST_DB && r_st_cnt == 0)
rm_axis_ireq_tvalid <= 'd1;
else if(r_st_current == P_ST_READ && r_st_cnt == 0)
rm_axis_ireq_tvalid <= 'd1;
else if(r_st_current == P_ST_MESSAGE && r_st_cnt == 0)
rm_axis_ireq_tvalid <= 'd1;
else
rm_axis_ireq_tvalid <= rm_axis_ireq_tvalid;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_ireq_tlast <= 'd0;
else if(w_m_axis_ireq_act && rm_axis_ireq_tlast)
rm_axis_ireq_tlast <= 'd0;
else if(r_st_current == P_ST_DB && r_st_cnt == 0)
rm_axis_ireq_tlast <= 'd1;
else if(r_st_current == P_ST_MESSAGE && w_m_axis_ireq_act)
rm_axis_ireq_tlast <= 'd1;
else if(r_st_current == P_ST_READ && r_st_cnt == 0)
rm_axis_ireq_tlast <= 'd1;
else if(r_st_current == P_ST_WRITE && r_pkt_cnt == 32 - 1)
rm_axis_ireq_tlast <= 'd1;
else
rm_axis_ireq_tlast <= rm_axis_ireq_tlast;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_ireq_tdata <= 'd0;
else if(r_st_current == P_ST_WRITE && r_st_cnt == 0)
rm_axis_ireq_tdata <= {8'd0,4'b0101,4'b0100,1'b0,2'b1,1'b0,8'd255,2'b0,34'd0};
else if(r_st_current == P_ST_DB && r_st_cnt == 0)
rm_axis_ireq_tdata <= {8'd0,4'b1010,4'd0,1'b0,2'b0,1'b0,8'd0,2'b0,2'b0,8'd0,8'd0,16'd0};
else if(r_st_current == P_ST_READ && r_st_cnt == 0)
rm_axis_ireq_tdata <= {8'd0,4'b0010,4'd4,1'b0,2'b0,1'b0,8'd255,2'b0,34'd0};
else if(r_st_current == P_ST_MESSAGE && r_st_cnt == 0)
rm_axis_ireq_tdata <= {4'd0,4'd0,4'b1011,4'd0,1'b0,2'b0,1'b0,8'd63,2'b0,34'd0};
else if(w_m_axis_ireq_act)
case(r_pkt_cnt)
0 :rm_axis_ireq_tdata <= {4{r_pkt_cnt}};
default :rm_axis_ireq_tdata <= {4{r_pkt_cnt}};
endcase
else
rm_axis_ireq_tdata <= rm_axis_ireq_tdata;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_pkt_cnt <= 'd0;
else if(r_pkt_cnt == 32 && w_m_axis_ireq_act)
r_pkt_cnt <= 'd0;
else if(r_st_current == P_ST_WRITE && w_m_axis_ireq_act)
r_pkt_cnt <= r_pkt_cnt + 1;
else
r_pkt_cnt <= r_pkt_cnt;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_ireq_tkeep <= 8'hff;
else
rm_axis_ireq_tkeep <= 8'hff;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_ireq_tuser <= 'd0;
else
rm_axis_ireq_tuser <= 'd0;
end
//==================================Target===========================//
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_treq_cnt <= 'd0;
else if(w_s_axis_treq_act && s_axis_treq_tlast)
r_treq_cnt <= 'd0;
else if(w_s_axis_treq_act)
r_treq_cnt <= r_treq_cnt + 1;
else
r_treq_cnt <= r_treq_cnt;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_cmd <= 'd0;
else if(w_s_axis_treq_act && r_treq_cnt == 0)
r_read_cmd <= s_axis_treq_tdata[55:48];
else
r_read_cmd <= r_read_cmd;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_cmd_valid <= 'd0;
else if(w_s_axis_treq_act && r_treq_cnt == 0)
r_read_cmd_valid <= 'd1;
else
r_read_cmd_valid <= 'd0;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_triger <= 'd0;
else if(r_read_cmd_valid && r_read_cmd == {4'b0010,4'd4})
r_read_triger <= 'd1;
else
r_read_triger <= 'd0;
end
/*----带数据的响应报文----*/
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_tresp_tvalid <= 'd0;
else if(w_m_axis_tresp_act && rm_axis_tresp_tlast)
rm_axis_tresp_tvalid <= 'd0;
else if(r_read_triger)
rm_axis_tresp_tvalid <= 'd1;
else
rm_axis_tresp_tvalid <= rm_axis_tresp_tvalid;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_tresp_tlast <= 'd0;
else if(w_m_axis_tresp_act && rm_axis_tresp_tlast)
rm_axis_tresp_tlast <= 'd0;
else if(r_read_cnt == 32 - 0)
rm_axis_tresp_tlast <= 'd1;
else
rm_axis_tresp_tlast <= rm_axis_tresp_tlast;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_tresp_tdata <= 'd0;
else if(r_read_triger)
rm_axis_tresp_tdata <= {8'd0,4'b1101,4'b1000,1'b1,2'd1,1'b0,8'd0,2'd0,34'd0};
else if(w_m_axis_tresp_act)
rm_axis_tresp_tdata <= {4{r_read_cnt - 1}};
else
rm_axis_tresp_tdata <= rm_axis_tresp_tdata;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_cnt <= 'd0;
else if(r_read_cnt == 32 && w_m_axis_tresp_act)
r_read_cnt <= 'd0;
else if(r_read_triger || (r_read_cnt && w_m_axis_tresp_act))
r_read_cnt <= r_read_cnt + 1;
else
r_read_cnt <= r_read_cnt;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_tresp_tkeep <= 'd0;
else
rm_axis_tresp_tkeep <= 8'hff;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
rm_axis_tresp_tuser <= 'd0;
else
rm_axis_tresp_tuser <= 'd0;
end
endmodule
三、上板验证
三次last信号分别表示了写事务、门铃以及读事务,发起端通过ireq通道发送,目的端通过treq接收。
这里是发起端通过iresp通道收到来自的目的端的带数据回应(针对于发起端发起的一次读事件,在目的端是通过tresp通道发送)
总结
完整工程可参考:https://github.com/shun6-6/SRIO_IP_design