前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FPGA 的布局规划艺术

FPGA 的布局规划艺术

作者头像
碎碎思
发布2021-09-07 15:14:05
5860
发布2021-09-07 15:14:05
举报
文章被收录于专栏:OpenFPGAOpenFPGA

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的物理实现工具使用专用用户约束文件(UCF\XDC)格式。下面的例子是最常用的布局布线约束语法。

代码语言: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则真经

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 OpenFPGA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • FPGA 的布局规划艺术
    • FPGA布局规划流程
      • IO分配
      • 布局规划锚桩模块
      • 布局规划剩余模块
      • 锁定核心元件
      • 布局规划微调
      • 布局布线约束
      • AREA_GROUP约束
      • 定向布线约束
      • PROHIBIT约束
      • 保存线网标号
      • 位置约束
      • 了解布线延迟
    • 穿过FPGA的“瓷砖”
      • 其他布局规划技巧
        • 参考文献
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档