在V4中如何使用局部时钟网络
2017-10-27 15:09
190 查看
在大多数FPGA中,使用全局时钟资源(BUFG)可以得到延迟小,一致性高的时钟资源,但是全局时钟资源一般是非常有限的,而且使用全局时钟资源处理IO同步问题显得有些大材小用,而且由于全局时钟考虑的是较大区域内的时钟延迟,在局部未必能做到最好。Xilinx在V4中提供了另一种时钟网络:局部时钟网络专门用于解决小范围,尤其是IO上的时钟同步问题。
V4使用具有时钟能力的IO(Clock
Capable I/O,简称为CC),进行局部的IO采样。CC按对出现,即可以做为差分局部时钟,也可以做为单端的局部时钟。通过IO时钟驱动器(I/O
Clock Buffer,简称BUFIO),在IO列中驱动局部时钟网络,对同一局部时钟域内的IO信号进行采样,从而达到以最小的延时采样相关信号的目的。CC可以采样的IO均分布在其周围,且属于同一个局部时钟域,在PCB上这些IO(包括CC)具有相似的布线轨迹和区域,受到的干扰也相差不多,使用CC对这些信号采样,可以得到最大的眼图。
局部时钟网络不依赖于全局时钟,但是BUFIO只能用于驱动IO,不能驱动任何逻辑资源(如CLB、BlockRAM等),通过CC采样后的IO信号还需要经过局部时钟驱动(Regional
Clock Buffer,简称BUFR)再次采样才能被内部逻辑使用。局部时钟的数据采样结构如图,描述了通过CC采样其周边IO信号并传递到内部逻辑的过程。BUFIO和BUFR均为V4独有的库原件,需要通过库原语方式添加到设计中使用,这些库原语的使用可参见ISE随工具文档v4ldl.pdf《Virtex-4
Libraries Guide for HDL Designs》。
具体如何使用局部时钟网络呢,下面以RGMII接口(不包括RGMII数据处理部分)。
module rgmii(rst,rx_clk, rx_data, rx_dv, tx_clk, tx_en, tx_data);
input rst;
input rx_clk;
input [3:0] rx_data;
input rx_dv;
input tx_clk;
output tx_en;
output [3:0] tx_data;
wire clk_buf;
wire inside_clk;
wire hrx_dv;
wire lrx_dv;
wire empty;
wire [3:0] hrx_data;
wire [3:0] lrx_data;
wire [7:0] data_out;
BUFIO BUFIO_inst (
.O(clk_buf), // Clock buffer output
.I(rx_clk) // Clock buffer input
);
BUFR #(
.BUFR_DIVIDE("BYPASS"), // "BYPASS", "1", "2", "3", "4",
"5", "6", "7", "8
.SIM_DEVICE("VIRTEX4") // Specify target device, "VIRTEX4"
or "VIRTEX5
) BUFR_inst (
.O(inside_clk), // Clock buffer output
.CE(1), // Clock enable input
.CLR(rst), // Clock buffer reset input
.I(clk_buf) // Clock buffer input
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst0 (
.Q1(hrx_data[0]), // 1-bit output for positive edge of clock
.Q2(lrx_data[0]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[0]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst1 (
.Q1(hrx_data[1]), // 1-bit output for positive edge of clock
.Q2(lrx_data[1]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[1]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst2 (
.Q1(hrx_data[2]), // 1-bit output for positive edge of clock
.Q2(lrx_data[2]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[2]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst3 (
.Q1(hrx_data[3]), // 1-bit output for positive edge of clock
.Q2(lrx_data[3]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[3]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst4 (
.Q1(hrx_dv), // 1-bit output for positive edge of clock
.Q2(lrx_dv), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_dv), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
rj_fifo rj_fifo(
.wr_clk(inside_clk),
.rd_clk(tx_clk),
.din({hrx_data,lrx_data}),
.rd_en(!empty),
.rst(rst),
.wr_en(hrx_dv & lrx_dv),
.dout(data_out),
.empty(empty),
.full()
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst0 (
.Q(tx_data[0]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[0]), // 1-bit data input (positive edge)
.D2(data_out[1]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst1 (
.Q(tx_data[1]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[2]), // 1-bit data input (positive edge)
.D2(data_out[3]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst2 (
.Q(tx_data[2]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[4]), // 1-bit data input (positive edge)
.D2(data_out[5]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst3 (
.Q(tx_data[3]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[6]), // 1-bit data input (positive edge)
.D2(data_out[7]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst4 (
.Q(tx_en), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(!empty), // 1-bit data input (positive edge)
.D2(!empty), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
endmodule
程序结构比较简单,通过BUFIO将接收时钟转变为局部时钟rx_clk,通过IOB中的双沿寄存器IDDR捕获PIN上的RGMII输入数据;通过BUFR将接收时钟转变为内部逻辑可用时钟inside_clk将接收的数据存入fifo,这样就完成了RGMII的信号接收。
RGMII的信号处理不需要用到局部时钟,只是使用发送时钟tx_clk将数据从fifo中读出,并通过IOB双沿寄存器发送出去即可,同时也需要将tx_clk发送到FPGA片外。
使用局部时钟可以节省全局时钟资源,在做复杂时钟系统时非常有用,比如需要做10个RGMII接口,就不得不用10个DCM(因为每个RGMII口的接收数据时钟rx_clk是不同源的);但使用局部时钟,就几乎不需要使用DCM。
当完成RGMII代码后,需要指定管脚位置,这样带来一个新问题:局部时钟只能作用同一个区域(region)中的IO,那么每个局部时钟在FPGA中的分布,以及影响哪些IO呢,我们以V4
LX 100-1148芯片来说明。
建立一个空的ucf文件,通过ISE的Assign
Package Pins功能打开指定管脚窗口,如下图:
打开后的界面如下图:
该界面隐含设置为使用不同的颜色显示FPGA的Bank,我们需要通过单击Show
Clock Region(上图红圈处)图标将其转换到使用不同颜色显示FPGA的不同局部时钟域。这样可以很方便的通过颜色了解哪些局部时钟(CC)影响哪些IO,相同颜色区域的任何一个CC都可以作用于同颜色区域里的任何IO,但不能作用于其它颜色区域里的IO。可以看到每个颜色区域(局部时钟域)内都有1-2对六边形标志的管脚(上图绿圈处),这些就是局部时钟(CC)管脚,,与其它圆形标志的普通IO是有区别的。
局部放大后得到下图,可以看到我们需要将局部时钟管脚分布在CC管脚上(六边形标志),需要注意,六边形标志的管脚是成对出现的,当使用单端信号做为局部时钟时(如LVTTL,LVCMOS等),只能将做为局部时钟的信号分布在标为P的CC管脚上,例如上图,我们将rxc_a(RGMII接收时钟,即前文例程中的rx_clk)分布在B28管脚上(IO_L25P_CC_LC_5);当使用差分信号做为局部时钟时(如LVDS等),将局部时钟的信号分布在成对P/N的CC管脚上,例如B28/C28(IO_L25P_CC_LC_5/IO_L25N_CC_LC_5)。
需要被局部时钟采样的管脚,例如RGMII中的接收数据信号rx_data和rx_dv都需要分布在深绿色的区域内。
RGMII的发送时钟没有使用局部时钟,在可任意分布,不受影响。
分布完后,通过布局布线如果出现错误,对照前文的注意事项看有哪些没有注意,再修改分布。如果布局布线不出错,就说明分布已经成功了。
V4使用具有时钟能力的IO(Clock
Capable I/O,简称为CC),进行局部的IO采样。CC按对出现,即可以做为差分局部时钟,也可以做为单端的局部时钟。通过IO时钟驱动器(I/O
Clock Buffer,简称BUFIO),在IO列中驱动局部时钟网络,对同一局部时钟域内的IO信号进行采样,从而达到以最小的延时采样相关信号的目的。CC可以采样的IO均分布在其周围,且属于同一个局部时钟域,在PCB上这些IO(包括CC)具有相似的布线轨迹和区域,受到的干扰也相差不多,使用CC对这些信号采样,可以得到最大的眼图。
局部时钟网络不依赖于全局时钟,但是BUFIO只能用于驱动IO,不能驱动任何逻辑资源(如CLB、BlockRAM等),通过CC采样后的IO信号还需要经过局部时钟驱动(Regional
Clock Buffer,简称BUFR)再次采样才能被内部逻辑使用。局部时钟的数据采样结构如图,描述了通过CC采样其周边IO信号并传递到内部逻辑的过程。BUFIO和BUFR均为V4独有的库原件,需要通过库原语方式添加到设计中使用,这些库原语的使用可参见ISE随工具文档v4ldl.pdf《Virtex-4
Libraries Guide for HDL Designs》。
具体如何使用局部时钟网络呢,下面以RGMII接口(不包括RGMII数据处理部分)。
module rgmii(rst,rx_clk, rx_data, rx_dv, tx_clk, tx_en, tx_data);
input rst;
input rx_clk;
input [3:0] rx_data;
input rx_dv;
input tx_clk;
output tx_en;
output [3:0] tx_data;
wire clk_buf;
wire inside_clk;
wire hrx_dv;
wire lrx_dv;
wire empty;
wire [3:0] hrx_data;
wire [3:0] lrx_data;
wire [7:0] data_out;
BUFIO BUFIO_inst (
.O(clk_buf), // Clock buffer output
.I(rx_clk) // Clock buffer input
);
BUFR #(
.BUFR_DIVIDE("BYPASS"), // "BYPASS", "1", "2", "3", "4",
"5", "6", "7", "8
.SIM_DEVICE("VIRTEX4") // Specify target device, "VIRTEX4"
or "VIRTEX5
) BUFR_inst (
.O(inside_clk), // Clock buffer output
.CE(1), // Clock enable input
.CLR(rst), // Clock buffer reset input
.I(clk_buf) // Clock buffer input
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst0 (
.Q1(hrx_data[0]), // 1-bit output for positive edge of clock
.Q2(lrx_data[0]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[0]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst1 (
.Q1(hrx_data[1]), // 1-bit output for positive edge of clock
.Q2(lrx_data[1]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[1]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst2 (
.Q1(hrx_data[2]), // 1-bit output for positive edge of clock
.Q2(lrx_data[2]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[2]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst3 (
.Q1(hrx_data[3]), // 1-bit output for positive edge of clock
.Q2(lrx_data[3]), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_data[3]), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE", "SAME_EDGE
// or "SAME_EDGE_PIPELINED
.INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) IDDR_inst4 (
.Q1(hrx_dv), // 1-bit output for positive edge of clock
.Q2(lrx_dv), // 1-bit output for negative edge of clock
.C(clk_buf), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D(rx_dv), // 1-bit DDR data input
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
rj_fifo rj_fifo(
.wr_clk(inside_clk),
.rd_clk(tx_clk),
.din({hrx_data,lrx_data}),
.rd_en(!empty),
.rst(rst),
.wr_en(hrx_dv & lrx_dv),
.dout(data_out),
.empty(empty),
.full()
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst0 (
.Q(tx_data[0]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[0]), // 1-bit data input (positive edge)
.D2(data_out[1]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst1 (
.Q(tx_data[1]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[2]), // 1-bit data input (positive edge)
.D2(data_out[3]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst2 (
.Q(tx_data[2]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[4]), // 1-bit data input (positive edge)
.D2(data_out[5]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst3 (
.Q(tx_data[3]), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(data_out[6]), // 1-bit data input (positive edge)
.D2(data_out[7]), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC
) ODDR_inst4 (
.Q(tx_en), // 1-bit DDR output
.C(tx_clk), // 1-bit clock input
.CE(1), // 1-bit clock enable input
.D1(!empty), // 1-bit data input (positive edge)
.D2(!empty), // 1-bit data input (negative edge)
.R(rst), // 1-bit reset
.S(!rst) // 1-bit set
);
endmodule
程序结构比较简单,通过BUFIO将接收时钟转变为局部时钟rx_clk,通过IOB中的双沿寄存器IDDR捕获PIN上的RGMII输入数据;通过BUFR将接收时钟转变为内部逻辑可用时钟inside_clk将接收的数据存入fifo,这样就完成了RGMII的信号接收。
RGMII的信号处理不需要用到局部时钟,只是使用发送时钟tx_clk将数据从fifo中读出,并通过IOB双沿寄存器发送出去即可,同时也需要将tx_clk发送到FPGA片外。
使用局部时钟可以节省全局时钟资源,在做复杂时钟系统时非常有用,比如需要做10个RGMII接口,就不得不用10个DCM(因为每个RGMII口的接收数据时钟rx_clk是不同源的);但使用局部时钟,就几乎不需要使用DCM。
当完成RGMII代码后,需要指定管脚位置,这样带来一个新问题:局部时钟只能作用同一个区域(region)中的IO,那么每个局部时钟在FPGA中的分布,以及影响哪些IO呢,我们以V4
LX 100-1148芯片来说明。
建立一个空的ucf文件,通过ISE的Assign
Package Pins功能打开指定管脚窗口,如下图:
打开后的界面如下图:
该界面隐含设置为使用不同的颜色显示FPGA的Bank,我们需要通过单击Show
Clock Region(上图红圈处)图标将其转换到使用不同颜色显示FPGA的不同局部时钟域。这样可以很方便的通过颜色了解哪些局部时钟(CC)影响哪些IO,相同颜色区域的任何一个CC都可以作用于同颜色区域里的任何IO,但不能作用于其它颜色区域里的IO。可以看到每个颜色区域(局部时钟域)内都有1-2对六边形标志的管脚(上图绿圈处),这些就是局部时钟(CC)管脚,,与其它圆形标志的普通IO是有区别的。
局部放大后得到下图,可以看到我们需要将局部时钟管脚分布在CC管脚上(六边形标志),需要注意,六边形标志的管脚是成对出现的,当使用单端信号做为局部时钟时(如LVTTL,LVCMOS等),只能将做为局部时钟的信号分布在标为P的CC管脚上,例如上图,我们将rxc_a(RGMII接收时钟,即前文例程中的rx_clk)分布在B28管脚上(IO_L25P_CC_LC_5);当使用差分信号做为局部时钟时(如LVDS等),将局部时钟的信号分布在成对P/N的CC管脚上,例如B28/C28(IO_L25P_CC_LC_5/IO_L25N_CC_LC_5)。
需要被局部时钟采样的管脚,例如RGMII中的接收数据信号rx_data和rx_dv都需要分布在深绿色的区域内。
RGMII的发送时钟没有使用局部时钟,在可任意分布,不受影响。
分布完后,通过布局布线如果出现错误,对照前文的注意事项看有哪些没有注意,再修改分布。如果布局布线不出错,就说明分布已经成功了。
相关文章推荐
- 如何使用JXTA技术建立P2P网络
- 如何发布WebService呢?使网络中其它机器能使用我的WebService
- 如何发布WebService呢?使网络中其它机器能使用我的WebService[转]
- 如何使用CallBack机制来实现局部更新(比ajax快)
- [Python系列实用教程]一、Python如何使用urllib2获取网络资源
- 如何使用Jpcap 包实现网络监听
- 如何使用Nagios实现网络监控?
- 如何使用Open Flash Chart制作精美的网络图表
- [WM][转]PPC中如何找到正在使用中的网络(源代码)
- 中国移动、中国联通使用的GSM1800MHz网络各自的频段如何划分?上下行频段各是多少?
- [WM]PPC中如何找到正在使用中的网络(源代码)
- 笔记本接有线网络如何使用无线共享?
- 如何使用robots.txt[摘自网络]
- windows2008下如何无法使用无线网络的解决方法
- Jpcap包的学习笔记(八)如何使用Jpcap 包实现网络监听(下部)
- 【转载自一起飞翔blog】PPC中如何找到正在使用中的网络(源代码)
- 如何使用PHP获取网络上文件
- 如何创建一个映射驱动器使用的网络连接对话框
- 如何使用 IPSec 阻止特定网络协议和端口
- 如何检查网络中是否有使用路由