SRIO系列-仿真测试

发布于:2024-04-25 ⋅ 阅读:(26) ⋅ 点赞:(0)

一、前言

前两篇已经讲述了SRIO协议的概况,以及xilinx SRIO IP核的使用方式,已经在搭建工程的过程中时钟和复位的注意事项。

二、设计框图

整个框图也是按照之前的工程进行搭建,首先时SRIO_Channel,由SRIO IP核和时钟、复位模块组成,这是在之前的工程搭建中一种采用的一种Channel结构。其次,SRIO Module是按照QPLL共享的方式去管理Channel,使得多个通道能够共享QPLL。最后,用户侧逻辑采用了一个SRIO Engine一共有4次的事务传输,分别是:

  1. 写事务。写256字节的数据。
  2. 发送Doorbell。通知写完成。
  3. 读事务。读取写入的数据
  4. 发送消息,通知读完毕。(消息包一直有负载)

三、SRIO Engine 

这部分参考FPGA奇哥的系列网课。


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        
);

// assign   s_axis_iresp_tready = 0    ;
// assign   s_axis_treq_tready  = 0    ;

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_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                w_m_axi_ireq_act                  ;
wire                w_s_axi_iresp_act                 ;
wire                w_s_axi_treq_act                  ;
wire                w_m_axi_tresp_act                 ;

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_axi_ireq_act    = m_axis_ireq_tready & rm_axis_ireq_tvalid;
assign   w_s_axi_iresp_act   = s_axis_iresp_tvalid & rs_axis_iresp_tready;
assign   w_s_axi_treq_act    = s_axis_treq_tvalid & rs_axis_treq_tready;
assign   w_m_axi_tresp_act   = m_axis_tresp_tready && rm_axis_tresp_tvalid;


localparam      P_ST_IDLE    = 5'b00001               ,
                P_ST_WRITE   = 5'b00010               ,
                P_ST_DB      = 5'b00100               ,
                P_ST_READ    = 5'b01000               ,
                P_ST_MESSAGE = 5'b10000               ;

reg [4: 0]       r_st_nstate                          ;
reg [4: 0]       r_st_cstate                          ; 
reg [15:0]       r_st_cnt                             ;  

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_st_cstate <= P_ST_IDLE; 
    else
        r_st_cstate <= r_st_nstate;
end

always@(*)begin
    r_st_nstate = P_ST_IDLE;
    case(r_st_cstate)
        P_ST_IDLE:begin
            if(r_st_cnt == 1000)
                r_st_nstate =  P_ST_WRITE;
            else
                r_st_nstate =  P_ST_IDLE;
        end   
        P_ST_WRITE:begin
            if(w_m_axi_ireq_act && m_axis_ireq_tlast)
                r_st_nstate = P_ST_DB;
            else
                r_st_nstate = P_ST_WRITE;
        end  
        P_ST_DB:begin
            if(w_m_axi_ireq_act && m_axis_ireq_tlast)
                r_st_nstate = P_ST_READ;
            else
                r_st_nstate = P_ST_DB;            
        end     
        P_ST_READ:begin
            if(w_s_axi_iresp_act && s_axis_iresp_tlast)
                r_st_nstate = P_ST_MESSAGE;
            else
                r_st_nstate = P_ST_READ;              
        end   
        P_ST_MESSAGE:begin
            if(w_m_axi_ireq_act && m_axis_ireq_tlast)
                r_st_nstate = P_ST_IDLE;
            else
                r_st_nstate = P_ST_MESSAGE;              
        end
        default:begin
            r_st_nstate = P_ST_IDLE;
        end
    endcase    
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_st_cnt <= 'd0;
    else
        if(r_st_cstate != r_st_nstate)
            r_st_cnt <= 'd0;
        else
            r_st_cnt <= r_st_cnt + 1;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_cnt <= 'd0;
    else
        if(r_cnt == 32 && w_m_axi_ireq_act)
            r_cnt <= 'd0;
        else if(r_st_nstate == P_ST_WRITE && w_m_axi_ireq_act)//??
            r_cnt <= r_cnt + 1;
        else
            r_cnt <= r_cnt ;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_ireq_tdata <= 'd0;
    else
        if(r_st_nstate == P_ST_WRITE && r_cnt == 0)
            rm_axis_ireq_tdata <= {8'd0,4'b0110,4'd0,1'b0,2'b00,1'b0,8'hFF,1'b0,1'b0,34'b0};//流写
        else if(r_st_nstate == P_ST_DB && r_cnt == 0)
            rm_axis_ireq_tdata <= {8'd0,4'b1010,4'd0,1'b0,2'b00,1'b0,8'h00,1'b0,1'b0,34'b0};//门铃
        else if(r_st_nstate == P_ST_READ && r_cnt == 0)
            rm_axis_ireq_tdata <= {8'd0,4'b0010,4'b0100,1'b0,2'b00,1'b0,8'hFF,1'b0,1'b0,34'b0};//读
        else if(r_st_nstate == P_ST_MESSAGE && r_cnt == 0)
            rm_axis_ireq_tdata <= {4'd0,4'd0,4'b1011,4'b0000,1'b0,2'b00,1'b0,8'd63,1'b0,1'b0,34'b0};//消息
        else if(w_m_axi_ireq_act)
            case(r_cnt)
                0       : rm_axis_ireq_tdata <= {4{r_cnt}}  ;
                default : rm_axis_ireq_tdata <= {4{r_cnt}}  ;
            endcase
        else
            rm_axis_ireq_tdata <= rm_axis_ireq_tdata;
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_ireq_tlast <= 'd0;
    else
        if(rm_axis_ireq_tlast && w_m_axi_ireq_act)
            rm_axis_ireq_tlast <= 'd0;
        else if(r_st_nstate == P_ST_WRITE && r_cnt == 32 -1 )
            rm_axis_ireq_tlast <= 1'b1;
        else if(r_st_nstate == P_ST_DB && r_st_cnt == 0)
            rm_axis_ireq_tlast <= 1'b1;
        else if(r_st_nstate == P_ST_READ && r_st_cnt == 0)
            rm_axis_ireq_tlast <= 1'b1;
        else if(r_st_nstate == P_ST_MESSAGE && w_m_axi_ireq_act)
            rm_axis_ireq_tlast <= 1'b1;
        else
            rm_axis_ireq_tlast <= rm_axis_ireq_tlast ;
        
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_ireq_tvalid <= 'd0;
    else
        if(rm_axis_ireq_tlast && w_m_axi_ireq_act)
            rm_axis_ireq_tvalid <= 'd0;
        else if(r_st_nstate == P_ST_WRITE && r_st_cnt == 0)
            rm_axis_ireq_tvalid <= 1'b1;
        else if(r_st_nstate == P_ST_DB && r_st_cnt == 0)
            rm_axis_ireq_tvalid <= 1'b1;
        else if(r_st_nstate == P_ST_READ && r_st_cnt == 0)
            rm_axis_ireq_tvalid <= 1'b1;
        else if(r_st_nstate == P_ST_MESSAGE && r_st_cnt == 0)
            rm_axis_ireq_tvalid <= 1'b1;
        else
            rm_axis_ireq_tvalid <= rm_axis_ireq_tvalid;
        
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_ireq_tkeep <= 'd0;
    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 <= 8'h00;
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_treq_cnt <= 'd0;
    else 
        if(w_s_axi_treq_act && s_axis_treq_tlast)
            r_treq_cnt <= 'd0;
        else if(w_s_axi_treq_act)
            r_treq_cnt <= r_treq_cnt + 1;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_read_cmd <= 'd0;
    else 
        if(r_treq_cnt == 0 && w_s_axi_treq_act)
            r_read_cmd <= s_axis_treq_tdata[55:48];
        else 
            r_read_cmd <= r_read_cmd + 1;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_read_cmd_valid <= 'd0;
    else 
        if(r_treq_cnt == 0 && w_s_axi_treq_act)
            r_read_cmd_valid <= 1'b1;
        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 == 8'b0010_0100)
            r_read_triger <= 1'b1;
        else 
            r_read_triger <= 'd0;    
end



always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_tresp_tvalid <= 'd0;
    else
        if(rm_axis_tresp_tlast && w_m_axi_tresp_act)
            rm_axis_tresp_tvalid <= 'd0; 
        else if(r_read_triger)
            rm_axis_tresp_tvalid <= 1'b1;
        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(rm_axis_tresp_tlast && w_m_axi_tresp_act)
            rm_axis_tresp_tlast <= 'd0;
        else if(r_read_cnt == 31)
            rm_axis_tresp_tlast <= 1'b1;
        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'b0,2'b0,1'b0,8'd0,1'b0,1'b0,34'd0};
        else
            rm_axis_tresp_tdata <= {4{r_read_cnt - 1}};
end 

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_tresp_tkeep <= 'd0;
    else
        rm_axis_tresp_tkeep <= 'd0;
end 
 

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_tresp_tuser <= 'd0;
    else
        rm_axis_tresp_tuser <= 'd0;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_read_cnt <= 'd0;
    else
        if(r_read_cnt == 32 )
            r_read_cnt <= 'd0;
        else if(r_read_triger || w_m_axi_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)
        rs_axis_treq_tready <= 'd1;
    else
        rs_axis_treq_tready <= 1'b1;
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rs_axis_iresp_tready <= 'd1;
    else
        rs_axis_iresp_tready <= 1'b1;
end


    
endmodule

仿真图如下:

如图在ireq端口上首先发送写事务和数据,之后发起门铃事务,在之后发起读事务。

在iresp端口上返回读过来的数据

 最后读完数据后,可以发起消息事务,通知对端已经接收到数据

四、总结

本篇文章目的在于简单的实践一下SRIO IP核,所以操作非常简单。如果真的要去用SRIO协议,需要涉及的理论还是挺多的。


网站公告

今日签到

点亮在社区的每一天
去签到