AURORA 仿真验证
定义:AURORA是一种高速串行通信协议,通常用于在数字信号处理系统和其他电子设备之间传输数据。它提供了一种高效的方式来传输大量数据,通常用于需要高带宽和低延迟的应用中。AURORA协议通常由Xilinx公司的FPGA器件支持,它使用了一种特殊的编码和时钟恢复机制来实现可靠的数据传输。
本实验仅仅演示了如何快速将AURORA使用起来,理论知识见以下参考文章:
Aurora IP简介-CSDN博客
Aurora 8B/10B IP核(2)----Aurora概述及数据接口(Framing接口、Streaming接口)_xinlinx中的aurora协议中端口解释-CSDN博客
IP 核设计
这里主要注意时钟的设计和线程的安排
Aurora的输入时钟:
GT Refclk:该时钟是收发器的参考时钟,由外部一对差分输入时钟输入进来,取125MHZ。
INT Clk:初始化时钟,作为复位信号的一个时钟,可以由锁相环直接得到,取50MHZ
例化IP核
module aurora_top(
input [0:3] RXP,
input [0:3] RXN,
output [0:3] TXP,
output [0:3] TXN,
input gt_refclk_p,
input gt_refclk_n,
input init_clk,
input reset,
input power_down,
input [2:0] loopback,
output channel_up,
output [0:3] lane_up,
output gt_pll_lock,
output user_clk_out,
output tx_out_clk,
//TX Interface
input [0:255] axi_tx_tdata,
input axi_tx_tvalid,
input [0:31] axi_tx_tkeep,
input axi_tx_tlast,
output axi_tx_tready,
//RX Interface
output [0:255] axi_rx_tdata,
output axi_rx_tvalid,
output [0:31] axi_rx_tkeep,
output axi_rx_tlast
);
aurora_64b66b_0 u_aurora_64b66b_0 (
.rxp (RXP), // input wire [0 : 3] rxp
.rxn (RXN), // input wire [0 : 3] rxn
.reset_pb (reset), // input wire reset_pb
.power_down (power_down), // input wire power_down
.pma_init (1'b0), // input wire pma_init
.loopback (loopback), // input wire [2 : 0] loopback
.txp (TXP), // output wire [0 : 3] txp
.txn (TXN), // output wire [0 : 3] txn
.hard_err (), // output wire hard_err
.soft_err (), // output wire soft_err
.channel_up (channel_up), // output wire channel_up
.lane_up (lane_up), // output wire [0 : 3] lane_up
.tx_out_clk (tx_out_clk), // output wire tx_out_clk
.gt_pll_lock (gt_pll_lock), // output wire gt_pll_lock
.s_axi_tx_tdata (axi_tx_tdata), // input wire [0 : 255] s_axi_tx_tdata
.s_axi_tx_tkeep (axi_tx_tkeep), // input wire [0 : 31] s_axi_tx_tkeep
.s_axi_tx_tlast (axi_tx_tlast), // input wire s_axi_tx_tlast
.s_axi_tx_tvalid (axi_tx_tvalid), // input wire s_axi_tx_tvalid
.s_axi_tx_tready (axi_tx_tready), // output wire s_axi_tx_tready
.m_axi_rx_tdata (axi_rx_tdata), // output wire [0 : 255] m_axi_rx_tdata
.m_axi_rx_tkeep (axi_rx_tkeep), // output wire [0 : 31] m_axi_rx_tkeep
.m_axi_rx_tlast (axi_rx_tlast), // output wire m_axi_rx_tlast
.m_axi_rx_tvalid (axi_rx_tvalid), // output wire m_axi_rx_tvalid
.mmcm_not_locked_out (), // output wire mmcm_not_locked_out
.gt0_drpaddr (10'd0), // input wire [9 : 0] gt0_drpaddr
.gt1_drpaddr (10'd0), // input wire [9 : 0] gt1_drpaddr
.gt2_drpaddr (10'd0), // input wire [9 : 0] gt2_drpaddr
.gt3_drpaddr (10'd0), // input wire [9 : 0] gt3_drpaddr
.gt0_drpdi (16'd0), // input wire [15 : 0] gt0_drpdi
.gt1_drpdi (16'd0), // input wire [15 : 0] gt1_drpdi
.gt2_drpdi (16'd0), // input wire [15 : 0] gt2_drpdi
.gt3_drpdi (16'd0), // input wire [15 : 0] gt3_drpdi
.gt0_drprdy (), // output wire gt0_drprdy
.gt1_drprdy (), // output wire gt1_drprdy
.gt2_drprdy (), // output wire gt2_drprdy
.gt3_drprdy (), // output wire gt3_drprdy
.gt0_drpwe (1'b0), // input wire gt0_drpwe
.gt1_drpwe (1'b0), // input wire gt1_drpwe
.gt2_drpwe (1'b0), // input wire gt2_drpwe
.gt3_drpwe (1'b0), // input wire gt3_drpwe
.gt0_drpen (1'b0), // input wire gt0_drpen
.gt1_drpen (1'b0), // input wire gt1_drpen
.gt2_drpen (1'b0), // input wire gt2_drpen
.gt3_drpen (1'b0), // input wire gt3_drpen
.gt0_drpdo (), // output wire [15 : 0] gt0_drpdo
.gt1_drpdo (), // output wire [15 : 0] gt1_drpdo
.gt2_drpdo (), // output wire [15 : 0] gt2_drpdo
.gt3_drpdo (), // output wire [15 : 0] gt3_drpdo
.init_clk (init_clk), // input wire init_clk
.link_reset_out (), // output wire link_reset_out
.gt_refclk1_p (gt_refclk_p), // input wire gt_refclk1_p
.gt_refclk1_n (gt_refclk_n), // input wire gt_refclk1_n
.user_clk_out (user_clk_out), // output wire user_clk_out
.sync_clk_out (), // output wire sync_clk_out
.gt_rxcdrovrden_in (1'b0), // input wire gt_rxcdrovrden_in
.sys_reset_out (), // output wire sys_reset_out
.gt_reset_out (), // output wire gt_reset_out
.gt_refclk1_out (), // output wire gt_refclk1_out
.gt_powergood () // output wire [3 : 0] gt_powergood
);
endmodule
上面只是例化了这个IP核,把有用的信号引出来
TB仿真
module tb_aurora(
);
wire [0:3]RXP;
wire [0:3]RXN;
wire [0:3]TXP;
wire [0:3]TXN;
reg locked;
wire channel_up;
wire [0:3]lane_up;
wire axi_tx_tready;
wire user_clk_out;
wire channel_up1;
wire [0:3]lane_up1;
wire user_clk_out1;
reg [0 : 255] axi_tx_tdata;
reg axi_tx_tvalid;
wire [0 : 255] axi_rx_tdata;
wire axi_rx_tvalid;
reg clk_125m;
wire clk_125m_p;
wire clk_125m_n;
//125MHZ时钟
initial clk_125m = 1;
always #4 clk_125m = ~clk_125m;
//产生差分时钟
OBUFDS #(
.IOSTANDARD("DEFAULT"), // Specify the output I/O standard
.SLEW("SLOW") // Specify the output slew rate
) OBUFDS_inst (
.O(clk_125m_p), // Diff_p output (connect directly to top-level port)
.OB(clk_125m_n), // Diff_n output (connect directly to top-level port)
.I(clk_125m) // Buffer input
);
wire clk_50M;
wire locked_0;
//50M时钟
clk_wiz_50M instance_name
(
// Clock out ports
.clk_out50M(clk_50M), // output clk_out50M
// Status and control signals
.locked(locked_0), // output locked
// Clock in ports
.clk_in1_p(clk_125m_p), // input clk_in1_p
.clk_in1_n(clk_125m_n) // input clk_in1_n
);
//接收AURORA
aurora_top u_aurora_64b66b_rev(
.RXP (RXP), // input [0:3]
.RXN (RXN), // input [0:3]
.TXP (TXP), // output [0:3]
.TXN (TXN), // output [0:3]
.gt_refclk_p (clk_125m_p), // input
.gt_refclk_n (clk_125m_n), // input
.init_clk (clk_50M), // input
.reset (~locked), // input
.power_down (1'b0), // input //Drives the Aurora 64B/66B core to reset
.loopback (3'b000), // input [2:0]
.channel_up (channel_up), // output
.lane_up (lane_up), // output [0:3]
.gt_pll_lock (), // output
.user_clk_out (user_clk_out), // output
.tx_out_clk (), // output
//TX Interface
.axi_tx_tdata (), // input [0:255]
.axi_tx_tvalid (), // input
.axi_tx_tkeep (), // input [0:31]
.axi_tx_tlast (), // input
.axi_tx_tready (), // output
//RX Interface
.axi_rx_tdata (axi_rx_tdata), // output [0:255]
.axi_rx_tvalid (axi_rx_tvalid), // output
.axi_rx_tkeep (axi_rx_tkeep), // output [0:31]
.axi_rx_tlast (axi_rx_tlast) // output
);
//发送AURORA
aurora_top u_aurora_64b66b_set(
.RXP (TXP), //input [0:3]
.RXN (TXN), //input [0:3]
.TXP (RXP), //output [0:3]
.TXN (RXN), //output [0:3]
.gt_refclk_p (clk_125m_p), //input
.gt_refclk_n (clk_125m_n), //input
.init_clk (clk_50M), //input
.reset (~locked), //input
.power_down (1'b0), //input //Drives the Aurora 64B/66B core to reset
.loopback (3'b000), //input [2:0]
.channel_up (channel_up1), //output
.lane_up (lane_up1), //output [0:3]
.gt_pll_lock (), //output
.user_clk_out (user_clk_out1), //output
.tx_out_clk (), //output
//TX Interface
.axi_tx_tdata (axi_tx_tdata ), // input [0:255]
.axi_tx_tvalid (axi_tx_tvalid ), // input
.axi_tx_tkeep (32'hffff_ffff), // input [0:31]
.axi_tx_tlast (1'b0), // input
.axi_tx_tready (axi_tx_tready), // output
//RX Interface
.axi_rx_tdata (), //output [0:255]
.axi_rx_tvalid (), //output
.axi_rx_tkeep (), //output [0:31]
.axi_rx_tlast () //output
);
initial begin
axi_tx_tdata = 256'h0;
axi_tx_tvalid = 1'b0;
locked = 1'b0;
#5000;
axi_tx_tdata = 256'h123456879abcdef;
axi_tx_tvalid = 1'b1;
locked = 1'b1;
end
endmodule
代码分析:
-
首先,产生一个125MHZ的时钟
clk_125m
-
然后生成差分时钟
clk_125m_p ,clk_125m_n
-
使用锁相环产生50MHZ时钟
clk_50M
-
接下来例化了两次AURORA,一个是接收,另一个是发送
上面的tb代码,仿真了两个AURORA传输数据的功能
备注:reset_pb拉高5us,然后再拉低