用于后面讲解的参考:
srio_gen2_0 your_instance_name (
.log_clk_in(log_clk_in), // input wire
.buf_rst_in(buf_rst_in), // input wire
.log_rst_in(log_rst_in), // input wire
.gt_pcs_rst_in(gt_pcs_rst_in), // input wire
.gt_pcs_clk_in(gt_pcs_clk_in), // input wire
.cfg_rst_in(cfg_rst_in), // input wire
.deviceid(deviceid), // output wire [15 : 0]
.port_decode_error(port_decode_error), // output wire
.s_axis_ireq_tvalid(s_axis_ireq_tvalid), // input wire
.s_axis_ireq_tready(s_axis_ireq_tready), // output wire
.s_axis_ireq_tlast(s_axis_ireq_tlast), // input wire
.s_axis_ireq_tdata(s_axis_ireq_tdata), // input wire [63 : 0]
.s_axis_ireq_tkeep(s_axis_ireq_tkeep), // input wire [7 : 0]
.s_axis_ireq_tuser(s_axis_ireq_tuser), // input wire [31 : 0]
.m_axis_iresp_tvalid(m_axis_iresp_tvalid), // output wire
.m_axis_iresp_tready(m_axis_iresp_tready), // input wire
.m_axis_iresp_tlast(m_axis_iresp_tlast), // output wire
.m_axis_iresp_tdata(m_axis_iresp_tdata), // output wire [63 : 0]
.m_axis_iresp_tkeep(m_axis_iresp_tkeep), // output wire [7 : 0]
.m_axis_iresp_tuser(m_axis_iresp_tuser), // output wire [31 : 0]
.m_axis_treq_tvalid(m_axis_treq_tvalid), // output wire
.m_axis_treq_tready(m_axis_treq_tready), // input wire
.m_axis_treq_tlast(m_axis_treq_tlast), // output wire
.m_axis_treq_tdata(m_axis_treq_tdata), // output wire [63 : 0]
.m_axis_treq_tkeep(m_axis_treq_tkeep), // output wire [7 : 0]
.m_axis_treq_tuser(m_axis_treq_tuser), // output wire [31 : 0]
.s_axis_tresp_tvalid(s_axis_tresp_tvalid), // input wire
.s_axis_tresp_tready(s_axis_tresp_tready), // output wire
.s_axis_tresp_tlast(s_axis_tresp_tlast), // input wire
.s_axis_tresp_tdata(s_axis_tresp_tdata), // input wire [63 : 0]
.s_axis_tresp_tkeep(s_axis_tresp_tkeep), // input wire [7 : 0]
.s_axis_tresp_tuser(s_axis_tresp_tuser), // input wire [31 : 0]
.s_axi_maintr_rst(s_axi_maintr_rst), // input wire
.s_axi_maintr_awvalid(s_axi_maintr_awvalid), // input wire
.s_axi_maintr_awready(s_axi_maintr_awready), // output wire
.s_axi_maintr_awaddr(s_axi_maintr_awaddr), // input wire [31 : 0]
.s_axi_maintr_wvalid(s_axi_maintr_wvalid), // input wire
.s_axi_maintr_wready(s_axi_maintr_wready), // output wire
.s_axi_maintr_wdata(s_axi_maintr_wdata), // input wire [31 : 0]
.s_axi_maintr_bvalid(s_axi_maintr_bvalid), // output wire
.s_axi_maintr_bready(s_axi_maintr_bready), // input wire
.s_axi_maintr_bresp(s_axi_maintr_bresp), // output wire [1 : 0]
.s_axi_maintr_arvalid(s_axi_maintr_arvalid), // input wire
.s_axi_maintr_arready(s_axi_maintr_arready), // output wire
.s_axi_maintr_araddr(s_axi_maintr_araddr), // input wire [31 : 0]
.s_axi_maintr_rvalid(s_axi_maintr_rvalid), // output wire
.s_axi_maintr_rready(s_axi_maintr_rready), // input wire
.s_axi_maintr_rdata(s_axi_maintr_rdata), // output wire [31 : 0]
.s_axi_maintr_rresp(s_axi_maintr_rresp), // output wire [1 : 0]
.gt_clk_in(gt_clk_in), // input wire gt_clk_in
.drpclk_in(drpclk_in), // input wire drpclk_in
.refclk_in(refclk_in), // input wire refclk_in
.buf_lcl_response_only_out(buf_lcl_response_only_out), // output wire
.buf_lcl_tx_flow_control_out(buf_lcl_tx_flow_control_out), // output wire
.idle2_selected(idle2_selected), // output wire
.idle_selected(idle_selected), // output wire
.buf_lcl_phy_buf_stat_out(buf_lcl_phy_buf_stat_out), // output wire [5 : 0]
.phy_clk_in(phy_clk_in), // input wire
.gt0_qpll_clk_in(gt0_qpll_clk_in), // input wire
.gt0_qpll_out_refclk_in(gt0_qpll_out_refclk_in), // input wire
.phy_rst_in(phy_rst_in), // input wire
.sim_train_en(sim_train_en), // input wire
.phy_mce(phy_mce), // input wire phy_mce
.phy_link_reset(phy_link_reset), // input wire
.force_reinit(force_reinit), // input wire
.phy_lcl_phy_next_fm_out(phy_lcl_phy_next_fm_out), // output wire [5 : 0]
.phy_lcl_phy_last_ack_out(phy_lcl_phy_last_ack_out), // output wire [5 : 0]
.link_initialized(link_initialized), // output wire
.phy_lcl_phy_rewind_out(phy_lcl_phy_rewind_out), // output wire
.phy_lcl_phy_rcvd_buf_stat_out(phy_lcl_phy_rcvd_buf_stat_out), // output wire [5 : 0]
.phy_rcvd_mce(phy_rcvd_mce), // output wire
.phy_rcvd_link_reset(phy_rcvd_link_reset), // output wire
.port_error(port_error), // output wire
.port_initialized(port_initialized), // output wire
.clk_lock_in(clk_lock_in), // input wire
.mode_1x(mode_1x), // output wire mode_1x
.port_timeout(port_timeout), // output wire [23 : 0]
.srio_host(srio_host), // output wire
.phy_lcl_master_enable_out(phy_lcl_master_enable_out), // output wire
.phy_lcl_maint_only_out(phy_lcl_maint_only_out), // output wire
.gtrx_disperr_or(gtrx_disperr_or), // output wire
.gtrx_notintable_or(gtrx_notintable_or), // output wire
.phy_debug(phy_debug), // output wire[223 : 0]
.srio_txn0(srio_txn0), // output wire
.srio_txp0(srio_txp0), // output wire
.srio_rxn0(srio_rxn0), // input wire srio_rxn0
.srio_rxp0(srio_rxp0), // input wire srio_rxp0
.srio_txn1(srio_txn1), // output wire
.srio_txp1(srio_txp1), // output wire
.srio_rxn1(srio_rxn1), // input wire srio_rxn1
.srio_rxp1(srio_rxp1), // input wire srio_rxp1
.srio_rxn2(srio_rxn2), // input wire srio_rxn2
.srio_rxp2(srio_rxp2), // input wire srio_rxp2
.srio_txn2(srio_txn2), // output wire
.srio_txp2(srio_txp2), // output wire
.srio_rxn3(srio_rxn3), // input wire srio_rxn3
.srio_rxp3(srio_rxp3), // input wire srio_rxp3
.srio_txn3(srio_txn3), // output wire
.srio_txp3(srio_txp3) // output wire srio_txp3
);
这里只介绍Basic Mode,Advanced Mode我没有用到过,应该也很少用,就不介绍了。
(1)Link Width:链路通道数量。
通过例化的IP模块我们可以看到,时钟端口简直太多了,log_clk、phy_clk、gt_pcs_clk、gt_clk、refclk、cfg_clk是应该要好好捋清楚一下。
(1)串行收发器还需要使用收发器专用时钟引脚的参考时钟(refclk),参考时钟频率是在core生成时选择的(可用选项取决于架构和line rate),如下图:(x是可选)。
gt_clk = Line Rate / 20b,PHY在两个时钟域上运行:phy_clk,这是主要的核心时钟,gt_pcs_clk,这是用于串行收发器接口。gt_clk不被PHY使用,但被串行收发器接口使用。gt_pcs_clk的速率是gt_clk的一半。一般情况下,phy_clk等于(gt_clk *Link Width)/4,core运行2x的话,phy_clk的频率是gt_clk的一半。如果core训练成1x mode,phy_clk必须切换到gt_clk速率的四分之一。具体如下图:LOG层运行在log_clk域上。为了获得最佳吞吐量,log_clk至少应该与phy_clk一样快。
(3) MMCM乘法器和分法器的值取决于reference clock frequency和line rate。在4x配置中,log_clk和gt_clk共享一个BUFG。在1x配置中,log_clk和phy_clk共享一个BUFG(不需要BUFGMUX,因为phy_clk速率只有一种可能)。此外,如果在Vivado IDE中选择了Unified Clock选项,log_clk和phy_clk需要相同的速率。这意味着可以删除log_clk/cfg_clk的BUFG,并且log_clk/cfg_clk被绑定到phy_clk。如下图:
SRIO分两种事务处理方式,事务目标是远端的放置在Initiator port 上(本地是事务发起者),事务的目标是本地的放置在Target port 上(远端是事务发起者)。由本地端点生成的请求被放置在启动器请求(ireq)通道上,在链路上传输。从远端设备接收到的响应会在启动器响应(iresp)通道上呈现给用户设计。core接收到的来自远程设备的请求会在目标请求(treq)通道上呈现给用户设计。对这些请求的响应(由用户设计生成)放置在Target Response (trep)通道上。
HELLO报文的size字段为传输的字节数减1(有效范围是0 ~ 255,对应真实的1 ~ 256字节)。就是说SRIO一包数据量最大为256B。
TID从0开始,每产生一个请求,增加1。
1. FTYPE2 - Request Class
所有请求事务都是AXI4-Stream接口上的一个节拍,并且只是编码的报头
(1)NREAD (TTYPE = 4'b0100). 标准的读事务。相关的响应是size字段中提供的大小。
2.FTYPE5 - Write Class
在AXI4-Stream接口上,所有写事务都在2到33拍之间,由编码的报头和最多32个dwords(每个dwords是8个bytes)的数据组成。
(1)NWRITE (TTYPE = 4'b0100).写事务,没有响应。标准写事务允许少于dword或多于dword写入(不是8bytes的整数倍)。接收端点应该执行写入到指定地址。由于这种数据包类型的无响应特性,TID被忽略。
(2)NWRITE_R (TTYPE = 4'b0101).写事务,等待响应。标准写事务允许子dword或多dword写入。接收端点应该执行写入到指定地址,然后将状态为OK或ERROR的单拍响应发送回发起端点。
3.FTYPE6 - Streaming Write Class
Streaming write 包允许端点元素在链接伙伴内存空间内修改大量数据。SWrite事务是跨链路接口的SRIO事务中最高效的,因此缺少其他事务中许多字段。SWrite只使用ftype、priority和address字段,不需要TID,因为对该报文类型不发送响应。不需要Size,因为所有事务都需要
是dwords倍数(SWrite 包携带的数据量只能是dwords倍数)。在AXI4-Stream接口上,Streaming write事务在2到33节拍之间,由编码头之后跟一个最大值32dwords数据字组成。
4.FTYPE10 - Doorbell Class
在进行数据传输之前要先看core输出的状态是否正常,正常的话才能开始传输数据。
port_decode_error :有效时表示收到不支持的事务,由于未启用User-Defined port而删除该事务。当下一个受支持的包类型到达任何用户界面时,该信号失效。这个信号在log_clk中是同步的。
port_error:表示端口收到了不可恢复的错误,处于错误状态。这个信号生效说明PHY层链接出现了问题。必须用sys_rst复位(sys_rst复位整个core,所有的状态进行复位),core进行初始化。
tuser:HELLO格式:在报文的第一个节拍有效,该信号由报文的源ID(31:16)和目的ID(15:0)组成。如果使用8位设备id,则每个设备id的最高位字节ID应该用0填充。
tkeep:字节限定符,指示数据的相关字节的内容是否有效。如果端口被配置为使用HELLO格式,这必须绑定到8'hFF。第7位对应于数据的最高有效字节(tdata[63:56]),位0对应最低有效字节(tdata[7:0])。