FPGA 的布局规划艺术
布局规划是为设计增加布局布线约束的过程。一个大型高速设计的布局规划是实现时序收敛的关键。好的布局规划可以大大提高设计性能,并确保设计结果的质量。差的布局规划具有相反的效果,使其无法满足时序约束,并导致设计结果与预期不符。
有效的FPGA布局规划是一项要在实践中获得的技能。它需要优秀的设计知识和对性能目标、工具选择、FPGA结构和功能的深刻理解,以及基于时序分析结果必要的代码修改和设计约束能力。
布局规划能让设计者直接观察到设计综合后产生的结果适配到了FPGA器件的哪些地方,在ASIC领域这是一项专业化工程。有一个或多个工程师专门从事大的芯片的布局规划。相对来说,FPGA的布局规划简单得多,它通常由一个工程师设计完成。
布局规划不仅为大型、高利用、高速的设计所采用,小型的设计也采用布局规划。小型设计的布局规划可以简单到就指定一个布局约束。即使有的设计时钟频率低,并且满足时序,往往也需要工程师来做布局规划。
布局规划是与时序收敛、一定程度上又与逻辑设计紧密联系在一起的任务。建议在设计周期的早期开始准备。例如,布局规划的考虑在模块化设计过程中具有一定的份量。
Xilinx Plan Ahead是一个用于布局规划的主流工具。高级用户可以将布局约束直接添加到设计约束文件中,从而进行手动布局规划。Plan Ahead还支持自动布局规划。然而,经验表明,大型设计使用手动布局规划能产生更好的效果。
FPGA布局规划流程
FPGA设计布局规划一般包括如图1所示的步骤。
IO分配
FPGA设计中需要进行IO分配。锁定设计的所有IO是确定任何其他布局布线约束前的第一个需要完成的任务。如果不这样做可能会导致结果不够理想,同时也浪费时间。之后IO可能需要根据布局规划的改变而改变。
布局规划锚桩模块
所有IO分配完成后,下一步是布局规划所有的锚桩模块。这些模块的位置是不能改变的,如连接到IO的模块、与嵌入式FPGA元件接口的用户逻辑模块(如PCI Express接口)、以太网MAC或收发器。很多如复位控制器、存储器控制器、CPU这样的模块都可在FPGA芯片中心的附近布局。
布局规划剩余模块
对设计中其他模块的布局规划是增加布局布线约束、进行设计、分析时序报告、做出必要调整的迭代过程,一直要到时序收敛时才停止。这是花费时间最长的步骤,大型的高速设计需要花费几周时间。在此过程中,设计者可能需要更改现有的布局规划:布局规划区域的移动、增加或减少它们的面积,或在较低层对模块进行布局规划以改善间隔大小。
锁定核心元件
为保存结果,当设计满足时序要求且预计没有重大的设计变更时,建议锁定所有的BRAM、DSP和时钟管理模块,主要是为了改善后面设计中的一致性和运行时间。
布局规划微调
一些小的布局规划微调可能会发生在设计的后期,主要是由于时序约束的变化、提高或降低逻辑利用而增加的新特征或修复缺陷。
布局布线约束
布局布线约束作为输人提供给物理实现工具。Xilinx的物理实现工具使用专用用户约束文件(UCFXDC)格式。下面的例子是最常用的布局布线约束语法。
代码语言:javascript复制//-----------------------------------------------------------------------------
// Copyright (C) 2011 OutputLogic.com
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//-----------------------------------------------------------------------------
`timescale 1ns / 100ps
module constraints(input clk, reset,
output reg data_out_0,data_out_1);
always @(posedge clk) begin
if (reset) begin
data_out_0 <= 1'b0;
data_out_1 <= 1'b0;
end
else begin
data_out_0 <= ~data_out_0;
data_out_1 <= ~data_out_1;
end
end // always
endmodule // constraints
布局布线约束
代码语言:javascript复制
NET "data_out_0" LOC = P16;
NET "data_out_1" LOC = D6;
INST "data_out_0" AREA_GROUP = "data_out_0";
AREA_GROUP "data_out_0" RANGE=SLICE_X44Y40:SLICE_X45Y42;
AREA_GROUP "data_out_0" GROUP=CLOSED;
AREA_GROUP "data_out_0" PLACE=CLOSED;
CONFIG PROHIBIT=SLICE_X06Y0:X14Y20;
CONFIG PROHIBIT=P15;
NET "data_out_1_OBUF"
ROUTE="{3;1;6slx25csg324;477afbc1!-1;8040;6064;S!0;-845;-504!1;0;344!1;"
"-9743;1431!2;845;144;L!3;-16261;1!5;-22484;-4!6;-17991;3!7;-12477;5681!8;"
"0;12800!9;0;12800!10;0;12800!11;0;13872!12;0;12800!13;0;12800!14;0;12800!"
"15;0;13872!16;305;7589!17;0;3200!18;1855;1675!19;686;18!20;80;20!21;"
"-1490;2207!22;-1311;251;L!}";
NET "data_out_1" LOC=D6;
INST "data_out_1_OBUF" LOC=SLICE_X29Y41;
INST "data_out_1" LOC=SLICE_X29Y41;
AREA_GROUP约束
AREA_GROUP用于布局约束一组FPGA资源,如逻辑片、BRAM、DSP、MMCM等。它允许布局约束在FPGA的特定范围的区域内。AREA_GROUP的基本语法如下例所示。
代码语言:javascript复制INST "data_out_0" AREA_GROUP = "ag_data_out_0";
AREA_GROUP "ag_data_out_O" RANGE=SLICE_X44Y40:SLICE_X45Y42;
AREA_GROUP "ag_data_out_O" GROUP=CLOSED;
AREA_GROUP "ag_data_out_O" PLACE=CLOSED;
这个例子定义了一个名为“ag_data_out_0”的组,将寄存器data_out_0约束到逻辑片范围SLICE_X44Y40~SLICE_X45Y42。该组里的GROUP和PLACE属性确定组里的逻辑是否与组外逻辑相结合。使用GROUP和PLACE属性可提高编译的一致性,但由于仍闲置了一些逻辑资源未用,因此逻辑利用将更高。
定向布线约束
布线约束具有锁定特定路线的能力,只适用于少数高速布线场合。使用定向布线的一个例子是在存储器控制器中锁定与10引脚接口的布线,以控制延迟。详细布线约束的语法未有文档介绍。需要时使用FPGA编辑器来产生约束,具体方法是选择一个线网(net)信号,然后在Tools->Directed Routing Constraints dialog中选择合适的选项。
PROHIBIT约束
PROHIBIT约束不允许布局布线工具使用特定的FPGA资源,如逻辑片、BRAM、DSP、IO等。下面是禁止使用特定的IO引脚和一系列逻辑片的例子。
代码语言:javascript复制CONFIG PROHIBIT=SLICE_X06Y0:X14Y20;
CONFIG PR0HIBIT=P15;
PROHIBIT约束对于保留特定的逻辑区以供将来使用是非常必要的,对于简单的设计来说,它与AREA_GR0UP约束相反。
保存线网标号
保存线网标号(S)可以约束某些线网或信号不被移除,它用于设计的初始阶段,以防止未连接的模块输人和无负载的输出被移除。下面的例子中给出了其语法。
代码语言:javascript复制NET "data_out_1" S;
位置约束
L0C是将特定元件放人FPGA中的位置约束。例如在每一个设计中几乎都会使用IO的位置。
代码语言:javascript复制NET "data_out_0" LOC=16;
了解布线延迟
了解布线延迟是进行有效布局规划的一部分。布线延迟与FPGA系列和速度等级有关,还取决于资源在FPGA芯片上的布局方式。Xilinx的FPGA Virtex-6和Spartan-6具有柱状结构:IO、BRAM和DSP块组织成柱状。逻辑资源具有类似“瓷砖”的结构,在水平和垂直方向排列成网格。FPGA也可以包含无任何逻辑资源的区域,或者只包含一个大的嵌入式块,如PCI Express接口核。所有这些都可能影响到布线的信号延迟。
下面的例子用以说明最坏情况下的布线延迟。
代码语言:javascript复制
//-----------------------------------------------------------------------------
// Copyright (C) 2011 OutputLogic.com
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//-----------------------------------------------------------------------------
`timescale 1ns / 100ps
module routing(input data_in_0,data_in_1,data_in_2,data_in_3,
output data_out_0,data_out_1,data_out_2,data_out_3 );
assign data_out_0 = data_in_0; // horizontal route 水平布线
assign data_out_1 = data_in_1; // vertical route 垂直布线
assign data_out_2 = data_in_2; // diagonal route 对角布线
assign data_out_3 = data_in_3; // routing around 环绕布线
endmodule // routing
IO布局
代码语言:javascript复制
NET "data_in_0" LOC = N3;
NET "data_out_0" LOC = P16;
NET "data_in_1" LOC = P6;
NET "data_out_1" LOC = D6;
NET "data_in_2" LOC = V3;
NET "data_out_2" LOC = B16;
NET "data_in_3" LOC = C7;
NET "data_out_3" LOC = A8; // 04/13 @ 20:40:41
NET "data_out_0_OBUF"
ROUTE="{3;1;6slx25csg324;87fbbdf3!-1;-88976;-116360;S!0;2563;-1309!1;"
"2169;661!2;37;24!3;-12;78!4;-162;-218!5;-524;4!6;11804;-916!7;25940;4!8;"
"16261;-1!9;17991;-3!10;23160;4!11;16937;-1!12;18683;1!13;21792;0!14;"
"16860;156!15;488;-28!16;-3812;1064!17;686;-386!18;80;20!19;3880;-482!20;"
"4523;836;L!}";
该设计用于Spartan6 LX25FPGA该器件有一个不包含逻辑资源的区域,有一个信号被布线在这一区域周围。图2是在FPGA编辑器中看到的布线。
FPGA编辑器报告以下布线延迟:
代码语言:javascript复制# 水 平 布 线
net "data_out_0_OBUF":
7.267ns - comp.pin "data_out_0.O", site.pin "P16.O"
driver - comp.pin "data_in_0.I", site.pin "N3.I"
net "data_out_1_0BUF"
net "data_out_2_OBUF"
# 垂 直 布 线
net "data_out_1_OBUF":
9.957ns - comp.pin "data_out_1.O", site.pin "D6.O"
driver - comp.pin "data_in_1.I", site.pin "P6.I"
net "data_out_3_0BUF"
# 对 角 布 线
net "data_out_2_OBUF":
13.725ns - comp.pin "data_out_2.O", site.pin "B16.O"
driver - comp.pin "data_in_2.I", site.pin "V3.I"
# 环 绕 布 线
net "data_out_3_OBUF":
9.968ns - comp.pin "data_out_3.O", site.pin "A8.O"
driver - comp.pin "data_in_3.I", site.pin "C7.I"
net "data_out_0_0BUF"
在上面的例子中,布线延迟范围从7.267ns到13.724ns。例如,如果设计中采用了200MHz的时钟,某个布线延迟会超过时钟周期。如果这样的设计与两个模块相连接,并被布局在FPGA的不同角落,将不可能满足时序约束。复位控制器工作在200MHz,为设计的其余部分提供同步复位信号,即使布局在FPGA芯片的中间位置,也可能在满足时序上岀现问题。
穿过FPGA的“瓷砖”
由于信号穿越FPGA的“瓷砖”(tile)增加了布线延迟,因此降低了性能。下面举例进行说明,其中包含了4个16位的CRC32校验模块实例,彼此完全独立。每个实例有单独的数据、使能、时钟输人和输出。实例以这样一种方式布局:每个区域的面积都完全相同,但布局不同。区域大小的选择要使得每个实例的逻辑利用率大约是70%左右。此外,所有区域都是封闭的,它们只包含属于相应实例的逻辑。
以下是顶层模块的代码。
代码语言:javascript复制//-----------------------------------------------------------------------------
// Copyright (C) 2011 OutputLogic.com
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//-----------------------------------------------------------------------------
module crc_floorplan(input clk1,clk2,clk3,clk4,
input crc_en1,crc_en2,crc_en3,crc_en4,
input rst,
input [15:0] data_in,
output reg [31:0] crc_out1, crc_out2, crc_out3, crc_out4);
wire [31:0] crc_out1_i, crc_out2_i, crc_out3_i, crc_out4_i;
reg crc_en1_q, crc_en2_q, crc_en3_q, crc_en4_q;
reg [15:0] data_in1_q, data_in2_q, data_in3_q, data_in4_q;
// add register stage to inputs and outputs
always @(posedge clk1, posedge rst) begin
if(rst) begin
crc_out1 <= 32'h0;
data_in1_q <= 16'h0;
crc_en1_q <= 1'b0;
end
else begin
crc_out1 <= crc_out1_i;
data_in1_q <= data_in;
crc_en1_q <= crc_en1;
end
end // always
always @(posedge clk2, posedge rst) begin
if(rst) begin
crc_out2 <= 32'h0;
data_in2_q <= 16'h0;
crc_en2_q <= 1'b0;
end
else begin
crc_out2 <= crc_out2_i;
data_in2_q <= data_in;
crc_en2_q <= crc_en2;
end
end // always
always @(posedge clk3, posedge rst) begin
if(rst) begin
crc_out3 <= 32'h0;
data_in3_q <= 16'h0;
crc_en3_q <= 1'b0;
end
else begin
crc_out3 <= crc_out3_i;
data_in3_q <= data_in;
crc_en3_q <= crc_en3;
end
end // always
always @(posedge clk4, posedge rst) begin
if(rst) begin
crc_out4 <= 32'h0;
data_in4_q <= 16'h0;
crc_en4_q <= 1'b0;
end
else begin
crc_out4 <= crc_out4_i;
data_in4_q <= data_in;
crc_en4_q <= crc_en4;
end
end // always
crc crc1 ( .data_in_i(data_in1_q),
.crc_en_i(crc_en1_q),
.crc_out(crc_out1_i),
.rst(rst), .clk(clk1));
crc crc2 ( .data_in_i(data_in2_q),
.crc_en_i(crc_en2_q),
.crc_out(crc_out2_i),
.rst(rst), .clk(clk2));
crc crc3 ( .data_in_i(data_in3_q),
.crc_en_i(crc_en3_q),
.crc_out(crc_out3_i),
.rst(rst), .clk(clk3));
crc crc4 ( .data_in_i(data_in4_q),
.crc_en_i(crc_en4_q),
.crc_out(crc_out4_i),
.rst(rst), .clk(clk4));
endmodule // crc_floorplan
// crc32 for Ethernet
module crc(
input [15:0] data_in_i,
input crc_en_i,
output reg [31:0] crc_out,
input rst,
input clk);
reg [31:0] lfsr_q,lfsr_c;
reg [15:0] data_in;
reg crc_en;
always @(*) begin
lfsr_c[0] = lfsr_q[16] ^ lfsr_q[22] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ data_in[0] ^ data_in[6] ^ data_in[9] ^ data_in[10] ^ data_in[12];
lfsr_c[1] = lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[0] ^ data_in[1] ^ data_in[6] ^ data_in[7] ^ data_in[9] ^ data_in[11] ^ data_in[12] ^ data_in[13];
lfsr_c[2] = lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[13] ^ data_in[14];
lfsr_c[3] = lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[10] ^ data_in[14] ^ data_in[15];
lfsr_c[4] = lfsr_q[16] ^ lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[22] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[31] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[8] ^ data_in[11] ^ data_in[12] ^ data_in[15];
lfsr_c[5] = lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[26] ^ lfsr_q[29] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[10] ^ data_in[13];
lfsr_c[6] = lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[30] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[11] ^ data_in[14];
lfsr_c[7] = lfsr_q[16] ^ lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[21] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[31] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[7] ^ data_in[8] ^ data_in[10] ^ data_in[15];
lfsr_c[8] = lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[28] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[8] ^ data_in[10] ^ data_in[11] ^ data_in[12];
lfsr_c[9] = lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[9] ^ data_in[11] ^ data_in[12] ^ data_in[13];
lfsr_c[10] = lfsr_q[16] ^ lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[21] ^ lfsr_q[25] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[9] ^ data_in[13] ^ data_in[14];
lfsr_c[11] = lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[25] ^ lfsr_q[28] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[9] ^ data_in[12] ^ data_in[14] ^ data_in[15];
lfsr_c[12] = lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[22] ^ lfsr_q[25] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[9] ^ data_in[12] ^ data_in[13] ^ data_in[15];
lfsr_c[13] = lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[21] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[26] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[6] ^ data_in[7] ^ data_in[10] ^ data_in[13] ^ data_in[14];
lfsr_c[14] = lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[7] ^ data_in[8] ^ data_in[11] ^ data_in[14] ^ data_in[15];
lfsr_c[15] = lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[28] ^ lfsr_q[31] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[7] ^ data_in[8] ^ data_in[9] ^ data_in[12] ^ data_in[15];
lfsr_c[16] = lfsr_q[0] ^ lfsr_q[16] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[24] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[0] ^ data_in[4] ^ data_in[5] ^ data_in[8] ^ data_in[12] ^ data_in[13];
lfsr_c[17] = lfsr_q[1] ^ lfsr_q[17] ^ lfsr_q[21] ^ lfsr_q[22] ^ lfsr_q[25] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[1] ^ data_in[5] ^ data_in[6] ^ data_in[9] ^ data_in[13] ^ data_in[14];
lfsr_c[18] = lfsr_q[2] ^ lfsr_q[18] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[26] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[2] ^ data_in[6] ^ data_in[7] ^ data_in[10] ^ data_in[14] ^ data_in[15];
lfsr_c[19] = lfsr_q[3] ^ lfsr_q[19] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[3] ^ data_in[7] ^ data_in[8] ^ data_in[11] ^ data_in[15];
lfsr_c[20] = lfsr_q[4] ^ lfsr_q[20] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[28] ^ data_in[4] ^ data_in[8] ^ data_in[9] ^ data_in[12];
lfsr_c[21] = lfsr_q[5] ^ lfsr_q[21] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[29] ^ data_in[5] ^ data_in[9] ^ data_in[10] ^ data_in[13];
lfsr_c[22] = lfsr_q[6] ^ lfsr_q[16] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ data_in[0] ^ data_in[9] ^ data_in[11] ^ data_in[12] ^ data_in[14];
lfsr_c[23] = lfsr_q[7] ^ lfsr_q[16] ^ lfsr_q[17] ^ lfsr_q[22] ^ lfsr_q[25] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[6] ^ data_in[9] ^ data_in[13] ^ data_in[15];
lfsr_c[24] = lfsr_q[8] ^ lfsr_q[17] ^ lfsr_q[18] ^ lfsr_q[23] ^ lfsr_q[26] ^ lfsr_q[30] ^ data_in[1] ^ data_in[2] ^ data_in[7] ^ data_in[10] ^ data_in[14];
lfsr_c[25] = lfsr_q[9] ^ lfsr_q[18] ^ lfsr_q[19] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[2] ^ data_in[3] ^ data_in[8] ^ data_in[11] ^ data_in[15];
lfsr_c[26] = lfsr_q[10] ^ lfsr_q[16] ^ lfsr_q[19] ^ lfsr_q[20] ^ lfsr_q[22] ^ lfsr_q[26] ^ data_in[0] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[10];
lfsr_c[27] = lfsr_q[11] ^ lfsr_q[17] ^ lfsr_q[20] ^ lfsr_q[21] ^ lfsr_q[23] ^ lfsr_q[27] ^ data_in[1] ^ data_in[4] ^ data_in[5] ^ data_in[7] ^ data_in[11];
lfsr_c[28] = lfsr_q[12] ^ lfsr_q[18] ^ lfsr_q[21] ^ lfsr_q[22] ^ lfsr_q[24] ^ lfsr_q[28] ^ data_in[2] ^ data_in[5] ^ data_in[6] ^ data_in[8] ^ data_in[12];
lfsr_c[29] = lfsr_q[13] ^ lfsr_q[19] ^ lfsr_q[22] ^ lfsr_q[23] ^ lfsr_q[25] ^ lfsr_q[29] ^ data_in[3] ^ data_in[6] ^ data_in[7] ^ data_in[9] ^ data_in[13];
lfsr_c[30] = lfsr_q[14] ^ lfsr_q[20] ^ lfsr_q[23] ^ lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[30] ^ data_in[4] ^ data_in[7] ^ data_in[8] ^ data_in[10] ^ data_in[14];
lfsr_c[31] = lfsr_q[15] ^ lfsr_q[21] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[5] ^ data_in[8] ^ data_in[9] ^ data_in[11] ^ data_in[15];
end // always
always @(posedge clk, posedge rst) begin
if(rst) begin
lfsr_q <= 32'hffffffff;
crc_out <= 32'h0;
data_in <= 16'h0;
crc_en <= 1'b0;
end
else begin
lfsr_q <= crc_en ? lfsr_c : lfsr_q;
crc_out <= lfsr_q;
data_in <= data_in_i;
crc_en <= crc_en_i;
end
end // always
endmodule // crc
面积和周期约束
代码语言:javascript复制
NET "clk1" TNM_NET = "clk1";
TIMESPEC TS_clk1 = PERIOD "clk1" 3.33 ns HIGH 50 %;
NET "clk2" TNM_NET = "clk2";
TIMESPEC TS_clk2 = PERIOD "clk2" 3.33 ns HIGH 50 %;
NET "clk3" TNM_NET = "clk3";
TIMESPEC TS_clk3 = PERIOD "clk3" 3.33 ns HIGH 50 %;
NET "clk4" TNM_NET = "clk4";
TIMESPEC TS_clk4 = PERIOD "clk4" 3.33 ns HIGH 50 %;
INST "crc1*" AREA_GROUP = "crc1";
AREA_GROUP "crc1" RANGE=SLICE_X0Y47:SLICE_X3Y55;
AREA_GROUP "crc1" GROUP=CLOSED;
AREA_GROUP "crc1" PLACE=CLOSED;
INST "crc2*" AREA_GROUP = "crc2";
AREA_GROUP "crc2" RANGE=SLICE_X0Y2:SLICE_X17Y3;
AREA_GROUP "crc2" GROUP=CLOSED;
AREA_GROUP "crc2" PLACE=CLOSED;
INST "crc3*" AREA_GROUP = "crc3";
AREA_GROUP "crc3" RANGE=SLICE_X22Y3:SLICE_X23Y21;
AREA_GROUP "crc3" GROUP=CLOSED;
AREA_GROUP "crc3" PLACE=CLOSED;
INST "crc4*" AREA_GROUP = "crc4";
AREA_GROUP "crc4" RANGE=SLICE_X2Y23:SLICE_X21Y24;
AREA_GROUP "crc4" GROUP=CLOSED;
AREA_GROUP "crc4" PLACE=CLOSED;
图 3 说明了 4 个实例是如何在 Spartan-6 LX9 FPGA 上布局规划的。
实例crcl仅被布局在一个“瓷砖”中。
实例CrC2被布局为包含几个水平“瓷砖”的细长矩形。
实例crc3被布局为包含几个垂直“瓷砖”的细长矩形。
实例crc4被布局为包含几个水平和垂直“瓷砖”的区域。
表1是4个实例的性能测试结果。
crcl的性能最好,crc2和crc3的性能非常类似,crc4的性能最差。这个例子通过精心挑选设计和布局约束,仅用于说明穿越“瓷砖”对性能的影响。大多数实际设计包含的模块都可以适配到一个“瓷砖”中。不过,通常建议布局规划时模块适配的“瓷砖”应尽可能少。
其他布局规划技巧
- 避免布局规划区域重叠。
- 使用AREA.GROUP约束的GROUP和PLACE属性,防止区外逻辑被布局到规划区里。
- 布局规划区域的逻辑利用率限制在75%以下。
- 对于流水线数据,布局规划水平走。
- 对于长进位链,布局规划纵向走。
- 对于布局规划区域边界上的模块,所有输入和输出都要寄存。
参考文献
[1] Xilinx Constraints User Guide
[2]FPGA高手设计实战100则真经