FPGA 的布局规划艺术

2021-09-07 15:14:05 浏览数 (1)

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则真经

0 人点赞