1. Aurora_ip介绍(以8b/10b为例)
1.功能:两个fpga之间进行通讯的工具
2.区别: 8b/10b,axi_stream的数据位宽是32bit(我设置的)
64b/66b,axi_stream的数据位宽是64bit(我设置的)
为什么64b的比8b的好呢?
因为8b的浪费了20%的带宽(也就是速度慢了)
一般来说小数据量用8b就可以了,大数据量就得用64b了,具体还是要看项目的要求
ip核的设置
另外界面就不放了,那俩保持默认,或者你想初学时想要时钟少一点就看看第三个界面的设置吧,我懒得搞了
话不多说,直接放程序(初学者,我就不放过fifo的了,这个不过fifo的程序接收数据的时候跳了一下,别直接用哦,好好研究一下吧
AURORA_TOP.V
module Aurora_TOP #(
parameter DATA_LEN = 32 ,//这俩我是为了可以随时更改aurora的模式(8b或者64b的)
parameter KEEP_LEN = 4
) (
input usr_rst ,//系统复位信号
input usr_clk ,//系统时钟,这里使用是为了产生aurora需要的两个复位信号,和init_clk直接连到一起的
input i_gt_clk_p ,//gt差分时钟,125mhz的
input i_gt_clk_n ,
input i_init_clk ,//初始化时钟,50mhz的
output o_aurora_txp ,//看名字
output o_aurora_txn ,
input i_aurora_rxp ,//看名字
input i_aurora_rxn
);
wire s_reset ;
wire s_gt_reset ;
wire s_user_clk ;
wire [DATA_LEN-1:0] s_axi_tx_tdata ;
wire [KEEP_LEN-1:0] s_axi_tx_tkeep ;
wire s_axi_tx_tlast ;
wire s_axi_tx_tvalid ;
wire s_axi_tx_tready ;
wire [DATA_LEN-1:0] s_axi_rx_tdata ;
wire [KEEP_LEN-1:0] s_axi_rx_tkeep ;
wire s_axi_rx_tlast ;
wire s_axi_rx_tvalid ;
wire s_channel_up ;
wire s_lane_up ;
wire s_hard_err ;
wire s_soft_err ;
wire s_frame_err ;
//产生aurora需要的复位信号
AURORA_RST u_Aurora_rst(
.usr_clk ( usr_clk ),
.usr_rst ( usr_rst ),
.o_reset ( s_reset ),
.o_gt_reset ( s_gt_reset )
);
//很简单的一个axi的程序
AURORA_AXI u_Aurora_axi(
.usr_clk ( s_user_clk ),
.usr_rst ( usr_rst ),
.i_channel_up ( s_channel_up ),
.o_axi_tx_tdata ( s_axi_tx_tdata ),
.o_axi_tx_tkeep ( s_axi_tx_tkeep ),
.o_axi_tx_tlast ( s_axi_tx_tlast ),
.o_axi_tx_tvalid ( s_axi_tx_tvalid ),
.i_axi_tx_tready ( s_axi_tx_tready ),
.i_axi_rx_tdata ( s_axi_rx_tdata ),
.i_axi_rx_tkeep ( s_axi_rx_tkeep ),
.i_axi_rx_tlast ( s_axi_rx_tlast ),
.i_axi_rx_tvalid ( s_axi_rx_tvalid )
);
//初学时无关的输入都设置为0(我也是初学者,还不是很懂那些输入信号)
aurora_8b10b_0 u_aurora_8b10b_0 (
.reset ( s_reset ),
.gt_reset ( s_gt_reset ),
.gt_refclk1_p ( i_gt_clk_p ),
.gt_refclk1_n ( i_gt_clk_n ),
.init_clk_in ( i_init_clk ),
.drpclk_in ( i_init_clk ),
//speed = 3.125,lane_width = 4 --> data_width = 32
//because 8b/10b,so data_width = 32*(10/8) = 40
//so o_user_clk = 3.125g/40 = 78.125mhz,输出的user时钟,给子模块当时时钟用的
.user_clk_out ( s_user_clk ),
.channel_up ( s_channel_up ),//o
.lane_up ( s_lane_up ),//o
.s_axi_tx_tdata ( s_axi_tx_tdata ),//i
.s_axi_tx_tkeep ( s_axi_tx_tkeep ),//i
.s_axi_tx_tlast ( s_axi_tx_tlast ),//i
.s_axi_tx_tvalid ( s_axi_tx_tvalid ),//i
.s_axi_tx_tready ( s_axi_tx_tready ),//o
.m_axi_rx_tdata ( s_axi_rx_tdata ),//o
.m_axi_rx_tkeep ( s_axi_rx_tkeep ),//o
.m_axi_rx_tlast ( s_axi_rx_tlast ),//o
.m_axi_rx_tvalid ( s_axi_rx_tvalid ),//o
.hard_err ( s_hard_err ),//o
.soft_err ( s_soft_err ),//o
.frame_err ( s_frame_err ),//o
.rxp ( i_aurora_rxp ),//i
.rxn ( i_aurora_rxn ),//i
.txp ( o_aurora_txp ),//o
.txn ( o_aurora_txn ),//o
.sync_clk_out ( ),
.gt_reset_out ( ),
.gt_refclk1_out ( ),
.loopback ( 3'b000),
.drpaddr_in ( 'd0 ),
.drpen_in ( 'd0 ),
.drpdi_in ( 'd0 ),
.drprdy_out ( ),
.drpdo_out ( ),
.drpwe_in ( 'd0 ),
.power_down ( 1'b0 ),
.tx_lock ( ),
.tx_resetdone_out ( ),
.rx_resetdone_out ( ),
.link_reset_out ( ),
.pll_not_locked_out ( ),
.sys_reset_out ( ),
.gt0_qplllock_out ( ),
.gt0_qpllrefclklost_out ( ),
.gt_qpllclk_quad2_out ( ),
.gt_qpllrefclk_quad2_out( )
);
endmodule
AURORA_RST.V(这个是借鉴哪个博主的,忘了)
module AURORA_RST (
input usr_clk ,
input usr_rst ,
output o_reset ,
output o_gt_reset
);
parameter GT_RESET_START = 128 ;//说了她最少得拉低128个时钟
parameter GT_RESET_END = 256 ;//另一个复位只要比上面长就行,256=128*2,就是凭心里咋舒服咋来
parameter RESET_MAX = GT_RESET_END + GT_RESET_START;
reg r_reset ;
reg r_gt_reset ;
reg [10:0] r_start_cnt ;
wire s_start ;
reg [10:0] r_cnt ;
assign s_start = (r_start_cnt < RESET_MAX - 1 && r_start_cnt > 'd0);
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_start_cnt <= 'd0;
end else begin
if(r_start_cnt == RESET_MAX - 1) begin
r_start_cnt <= r_start_cnt;
end else begin
r_start_cnt <= r_start_cnt + 1'b1;
end
end
end
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_cnt <= 'd0;
end else if(s_start) begin
if(r_cnt == RESET_MAX - 1) begin
r_cnt <= 'd0;
end else begin
r_cnt <= r_cnt + 1'b1;
end
end else ;
end
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_gt_reset <= 1'b0;
end else begin
if(r_cnt == GT_RESET_START - 1) begin
r_gt_reset <= 1'b1;
end else if (r_cnt == GT_RESET_END - 1 || r_cnt == 0 ) begin
r_gt_reset <= 1'b0;
end
end
end
assign o_gt_reset = r_gt_reset;
always @ (posedge usr_clk) begin
if (s_start) begin
r_reset <= 1'b1;
end else begin
r_reset <= 1'b0;
end
end
assign o_reset = r_reset;
endmodule
AURORA_AXI.V,这个就不多介绍了,很简单的(当时学的时候主要是初始化有点烦)
module AURORA_AXI #(
parameter DATA_LEN = 32 ,
parameter KEEP_LEN = 4
) (
input usr_clk ,
input usr_rst ,
input i_channel_up ,
output [DATA_LEN-1:0] o_axi_tx_tdata ,
output [KEEP_LEN-1:0] o_axi_tx_tkeep ,
output o_axi_tx_tlast ,
output o_axi_tx_tvalid ,
input i_axi_tx_tready ,
input [DATA_LEN-1:0] i_axi_rx_tdata ,
input [KEEP_LEN-1:0] i_axi_rx_tkeep ,
input i_axi_rx_tlast ,
input i_axi_rx_tvalid
);
localparam NUM = 63 ;
localparam C_TXIDLE = 4'h0 ;
localparam C_TXDATA = 4'h1 ;
localparam C_TXEND = 4'hf ;
localparam C_RXIDLE = 4'h0 ;
localparam C_RXDATA = 4'h1 ;
localparam C_RXEND = 4'hf ;
reg [ 3:0] r_t_now ;
reg [ 3:0] r_t_next ;
reg [ 3:0] r_r_now ;
reg [ 3:0] r_r_next ;
reg [DATA_LEN-1:0] r_axi_tx_tdata ;
reg [DATA_LEN-1:0] r_axi_rx_tdata ;
reg [10:0] r_tx_cnt ;
reg r_axi_tx_tlast ;
reg r_axi_tx_tvalid ;
assign o_axi_tx_tkeep = 4'hf;
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_t_now <= C_TXIDLE;
end else begin
r_t_now <= r_t_next;
end
end
always @ (*) begin
r_t_next = C_TXIDLE;
case (r_t_now)
C_TXIDLE : begin
if(i_channel_up) begin
r_t_next = C_TXDATA;
end else begin
r_t_next = C_TXIDLE;
end
end
C_TXDATA : begin
if(o_axi_tx_tlast && o_axi_tx_tvalid && i_axi_tx_tready) begin
r_t_next = C_TXEND;
end else begin
r_t_next = C_TXDATA;
end
end
C_TXEND : begin
r_t_next = C_TXIDLE;
end
default : r_t_next = C_TXIDLE;
endcase
end
always @(posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_axi_tx_tlast <= 1'b0;
end else begin
if(i_axi_tx_tready && o_axi_tx_tvalid) begin
if(r_tx_cnt == 'd63) begin
r_axi_tx_tlast <= 1'b1;
end else begin
r_axi_tx_tlast <= 1'b0;
end
end else ;
end
end
assign o_axi_tx_tlast = r_axi_tx_tlast;
always @(posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_axi_tx_tvalid <= 1'b0;
end else begin
if(i_axi_tx_tready) begin
if(r_t_next == C_TXDATA) begin
r_axi_tx_tvalid <= 1'b1;
end else begin
r_axi_tx_tvalid <= 1'b0;
end
end else ;
end
end
assign o_axi_tx_tvalid = r_axi_tx_tvalid;
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_tx_cnt <= 'd0;
end else begin
if(r_t_next == C_TXDATA && i_axi_tx_tready) begin
r_tx_cnt <= r_tx_cnt + 'd1;
end else if(r_t_next == C_TXEND) begin
r_tx_cnt <= 'd0;
end
end
end
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_axi_tx_tdata <= 'dz;
end else begin
if(r_t_next == C_TXDATA && i_axi_tx_tready) begin
r_axi_tx_tdata <= r_axi_tx_tdata + 'd1;
end else if(r_t_next == C_TXIDLE) begin
r_axi_tx_tdata <= 'd0;
end
end
end
assign o_axi_tx_tdata = r_axi_tx_tdata;
always @ (posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_r_now <= C_RXIDLE;
end else begin
r_r_now <= r_r_next;
end
end
always @ (*) begin
r_r_next = C_RXIDLE;
case (r_r_now)
C_RXIDLE : begin
if(i_axi_rx_tvalid) begin
r_r_next = C_RXDATA;
end else begin
r_r_next = C_RXIDLE;
end
end
C_RXDATA : begin
if(i_axi_rx_tlast) begin
r_r_next = C_RXEND;
end else begin
r_r_next = C_RXDATA;
end
end
C_RXEND : begin
r_r_next = C_RXIDLE;
end
default : r_r_next = C_RXIDLE;
endcase
end
always @(posedge usr_clk or posedge usr_rst) begin
if(usr_rst) begin
r_axi_rx_tdata <= 'dz;
end else begin
if(i_axi_rx_tvalid) begin
r_axi_rx_tdata <= i_axi_rx_tdata;
end else begin
r_axi_rx_tdata <= 'dz;
end
end
end
endmodule