之前的课程中,我们实现了高速通信分层设计–FII-PRA006 开发板(Altera)的实验。 这一节课,我们要将整个工程移植到Xilinx FPGA上。 这里,我们选用FII-PRX100-D 开发板。
实验目的:
- 将Altera工程移植到Xilinx FPGA上
- 实现之前的高速通信设计
- 对比移植AlteraIP 到 Xilinx IP
- 实现相关的管脚约束
工程环境:
Vivado 2018.2
FII-PRX100-D 开发板 (ARTIX 100T XILINX FPGA)
本实验在高速通信分层设计—PRA006开发板实验(Altera)的基础上做出修改而成的,通篇以修改后的源代码呈现给大家,在每个程序后面有对应的相关修改的解释。
1 顶层工程代码:
`timescale 1 ns / 1 ps
//`define SIM
module top
#(
parameter IDLE = 10'b1010_1010_10
)
`ifdef SIM
();
parameter PERIOD = 20 ; //周期20
reg inclk ; // 模拟板级提供的输入时钟
initial begin
inclk = 1'b0;
#(PERIOD/2);
forever
#(PERIOD/2) inclk = ~inclk;
end
reg pll_rst; //实体模块PLL的rst信号
wire tx_p;
wire tx_n;
wire rx_p;
wire rx_n;
assign rx_p = tx_p;
assign rx_n = tx_n;
initial begin
pll_rst=1'b1;
#50 pll_rst=1'b0;
#50000;
$stop;
end
`else
(
input inclk,
output tx_p,
output tx_n,
input rx_p,
input rx_n,
output LED
);
`endif
wire pll_locked;
wire reset = !pll_locked;
(* mark_debug = "true" *)wire tx_rdy;
(* mark_debug = "true" *)reg [ 7: 0 ] tx_data;
(* mark_debug = "true" *)reg tx_en;
(* mark_debug = "true" *)reg tx_vld;
(* mark_debug = "true" *)wire tx_vld_ack;
(* mark_debug = "true" *)wire rx_data_vld;
(* mark_debug = "true" *)wire rx_data_rdy;
(* mark_debug = "true" *)wire ko;
(* mark_debug = "true" *)wire [ 7: 0 ] rx_data;
wire clk_100M;
localparam LEN = 16;
reg [ 7: 0 ] frame_len;
reg [ 2: 0 ] tx_st;
always@( posedge clk_100M or posedge reset )
if ( reset )
begin
tx_vld <= 1'b0;
tx_en <= 1'b0;
frame_len <= 0;
tx_data <= 0;
tx_st <= 0;
end
else
begin
case ( tx_st )
0:
begin
tx_vld <= 1'b0;
tx_en <= 1'b0;
tx_data <= 0;
frame_len <= 0;
tx_st <= 1;
end
1:
begin
tx_en <= 1'b0;
tx_vld <= 1'b1;
if ( frame_len == LEN )
begin
tx_vld <= 1'b0;
tx_st <= 3;
end
else if ( tx_rdy )
begin
tx_en <= 1'b1;
tx_st <= 2;
end
end
2:
begin
tx_en <= 1'b0;
frame_len <= frame_len + 1;
tx_data <= tx_data + 1;
tx_st <= 1;
end
3:
begin
frame_len <= 0;
tx_vld <= 1'b0;
tx_en <= 1'b0;
if ( tx_vld_ack )
tx_st <= 1;
end
default:
tx_st <= 0;
endcase
end
//=======================================================================================
(* mark_debug = "true" *)wire tx;
(* mark_debug = "true" *)wire rx;
IBUFDS #(
.DIFF_TERM ("TRUE"), // Differential Termination
.IBUF_LOW_PWR ("TRUE"), // Low power="TRUE", Highest performance="FALSE"
.IOSTANDARD ("LVDS_25") // Specify the input I/O standard
) IBUFDS_rx_inst (
.O (rx), // Buffer output
.I (rx_p), // Diff_p buffer input (connect directly to top-level port)
.IB (rx_n) // Diff_n buffer input (connect directly to top-level port)
);
OBUFDS #(
.IOSTANDARD ("LVDS_25"),// Specify the output I/O standard
.SLEW ("SLOW") // Specify the output slew rate
) OBUFDS_tx_inst (
.O (tx_p), // Diff_p output (connect directly to top-level port)
.OB (tx_n), // Diff_n output (connect directly to top-level port)
.I (tx) // Buffer input
);
hs_txrx
#(
.IDLE (IDLE)
)
hs_txrx_inst
(
.inclk (inclk),
.pll_rst (pll_rst),
.tx_rdy (tx_rdy),
.tx_vld (tx_vld),
.tx_data (tx_data),
.tx_en (tx_en),
.tx_vld_ack (tx_vld_ack),
.tx (tx),
.rx (rx),
.rx_data_vld(rx_data_vld),
.rx_data_rdy(rx_data_rdy),
.ko (ko),
.rx_data (rx_data),
.clk_100M (clk_100M),
.pll_locked (pll_locked)
);
`ifndef SIM
reg [31:0] led_cnt = 0;
always @ (posedge clk_100M)
led_cnt <= led_cnt + 1;
assign LED = led_cnt[25];
`endif
endmodule
Vivado工程的顶层代码中对外端口与Quartus工程中的对外端口设计不同。 Xilinx FPGA 使用IBUFDS,OBUFDS 原语实现单端信号rx,tx 到差分信号的转换,所以在端口上的定义为tx_p, tx_n; rx_p, rx_n。单端信号到差分信号的转换也可以使用Xilinx SelectIO IP 核实现。 本文使用IBUFDS,OBUFDS 原语。
在仿真程序中, 不再使用tx_rx 信号连接 发送和接收端口, 而是使用 assign rx_p = tx_p; assign rx_n = tx_n; 来实现。
2 修改hs_txrx.v代码:
/*
pll1 pll1_inst
(
.areset ( pll_rst ), //1'b0;
.inclk0 ( inclk ),
.c0 ( clk_100M ),
.c1 ( clk_400M ),
.locked ( pll_locked )
);
*/
pll1 pll1_inst
(
// Clock out ports
.clk_out1 (clk_100M), // output clk_out1
.clk_out2 (clk_400M), // output clk_out2
// Status and control signals
.reset (pll_rst), // input reset
.locked (pll_locked), // output locked
// Clock in ports
.clk_in1 (inclk) // input clk_in1
);
将Altera PLL替换为Xilinx clock IP。
Xilinx clock IP 例化如下:

图1

图2
3 修改tx_pmd.v代码:
module tx_PMD
(
input tx_in,
output tx_out
);
assign tx_out = tx_in;
/*
IO_TX IO_TX_INST
(
.tx_in ( tx_in ),
.tx_out ( tx_out )
);
*/
endmodule
在Quartus 工程中, 使用IO_TX IP 核, 当移植到Xilinx FPGA 时, 这里将不再使用IP核, 而是在top.v 文件中使用 OBUFDS 来实现.
4 修改recv_bit_pmd.v代码:
assign rx_out = rx;
/*
IO_RX IO_RX_inst
(
.rx_in ( rx ),
.rx_out ( rx_out )
);
*/
同样, 注释Quartus 工程中的IO_RX IP , 而是在top.v 文件中使用 IBUFDS 原语实现。
5 对比移植altera IP 到 Xilinx IP:
Quartus 工程 , 使用PLL IP核, IO_TX和IO_RX IP核 。 其中PLL 输入50M 时钟, 输出 100M, 400M 时钟。
Vivado 工程: 使用PLL IP核,IBUFDS 和 OBUFDS 原语。 其中PLL 也是输入50M 时钟, 输出为100M,400M 时钟,Xilinx需要使用xBUFDS (x 表示 I 或者 O)原语实现单端信号到差分信号的转换。
6 实现相关的管脚约束:
#==================================================
#clk
set_property -dict {PACKAGE_PIN D18 IOSTANDARD LVCMOS33} [get_ports inclk]
create_clock -period 20.000 -name OSC_CLK -waveform {0.000 10.000} [get_ports inclk]
set_property -dict {PACKAGE_PIN R7 IOSTANDARD LVCMOS33} [get_ports pll_rst]
set_property -dict {PACKAGE_PIN N23 IOSTANDARD LVCMOS33} [get_ports LED]
set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVDS_25 } [get_ports tx_p]
set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVDS_25 } [get_ports tx_n]
set_property -dict {PACKAGE_PIN K7 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_p]
set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_n]
Xilinx文档中相关阻抗匹配部分如下所示:

图3
set_property -dict {PACKAGE_PIN K7 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_p]
在管脚约束文件中定义管脚为lvds_25 标准, 同时使用DIFF_TERM 1或者DIFF_TERM TRUE,表示使用内部差分电阻。
注:在使用Artix 系列FPGA 使用LVDS差分功能时, 需要管脚连接的bank 电压 <= 2.5v 。 目前,我们使用tx_p, tx_n, rx_p, rx_n 都是连接在bank35中。 所以需要将bank35 的电压设置为 <= 2.5v ,否则FPGA 不会工作,因此这里选择bank35电压为1.8V。如图4所示:

图4
7 . FII-PRX100-D高速通信回环实验设置
- 原理图部分如图5,图6所示:

图5

图6
- 开发板硬件连线如图7所示:

图7
8 使用ILA (mark_debug)调试高速通信信号:

图8

图9
示波器波形:

图10
其中 紫色信号连接tx_p, 黄色信号连接 tx_n。 白色信号为 tx_p – tx_n 得到相关的差分信号。
由于通信工程当中的逻辑验证部分在之前的文章中已经介绍过,这里只演示了在线的硬件调试部分内容。
关于详细的实验内容,请参见对应的视频。
vivado 2018.2 工程代码:
[content_control]
[/content_control]