FPGA逻辑设计回顾(2)那些年学习FPGA较为常见的疑问?

李锐博恩 2020-12-13 19:59:59 10372

前言

本文的内容是从众多参考资料上查到的,并深有同感,在初学FPGA的阶段,确实会遇到这样那样的问题,这些问题没有得到较好的回答,不仅影响对学习的兴趣,也会导致实践中的停滞。
本文节选出大家可能会遇到的部分问题,比较常见,并对其进行分析,当然分析也不一定是我的分析(部分来自参考资料),但一定是我比较认同的理解。
必须说明的是,由于很多使用Xilinx的初学者,可能使用的是比较低级的开发板,所以关于约束方面使用的还是UCF文件,不过没有关系,尽管如今大多数还是以SDC或者XDC为主,但了解UCF文件的约束方法,约束思想还是一致的,了解过去,才能更好的理解现在,乃至未来!

如何理解FPGA中的帧、字与比特?

这些概念中,字和比特更较为常见,即是我们所谓的word以及bit,帧即frame在图像领域更较为常见,下面给出解释:

  • 帧即一组字的集合;
  • 字即一组位的集合;
  • 位即任何二进制数据的基本单位-可以是1或0。

通常,生活中frame/word/bit指的就是帧,字以及位(比特),下面不予区分。

一般而言,word将是您要发送的任何数据的主要单位。例如,如果要发送RGB565编码的图像,则一个word可能是与单个像素对应的16bit值。

如果以多个word为块发送数据,那么您将拥有一个frame(帧)。对于图像,一帧将是一个完整的图像。例如,如果您正在处理320x240的图像,则每帧76800像素。如果每个数据字都是一个像素,那么每帧将有76800个字。

通常认为,一个word有16个比特,但这就是固定不变的了吗?看开头的解释,word就是一组bit的集合,有多少个bit可没说,于是相关资料也有如下解释:

对于m x n像素的图像,它包含m x n个像素,像素被认为是图像的最小组成部分。如果我们说图片是24位图像,则意味着图像的一个像素用24位表示,而RGB分量的强度分别用8位表示。因此,Bit是像素的最小组成部分。它是二进制数据的基本单位(0或1)。Word是广义术语。这取决于您要如何定义它。例如,在这里您可以用一个字代表一个像素。这意味着24位是您当前设计中的一个字。帧构成图像的所有像素。一帧缓冲以二进制数据的形式表示整个图像。在上面的示例中,它包含m x n个word或像素,也即m x n x 24个bit。

时钟实现设计警告?

案例如下:
在Xilinx 14.1上使用SPARTAN 3E-FT256,并且必须从板载50MHz时钟中生成25MHz时钟。通过数字时钟管理器(Digital Clock Manager)Digital Clock Manager来实现的。
UCF文件内容如下:

NET "CLK_50MHZ" LOC = "C8" | IOSTANDARD = LVCMOS33 ;   //GCLK 10
NET "CLK_50MHZ" PERIOD = 20.0ns HIGH 40%;              //DCM_X0Y1

例化的时钟资源管理器如下:

wire clk_ibufg;
wire clock;
wire CLK0_OUT;

IBUFG clk_ibufg_inst ( .I(CLK_50MHZ) , .O(clk_ibufg) );
BUFG  clk_bufg_inst  ( .I(clock) , .O(clk));

ClockManager1 clock_converter (
.CLKIN_IN(clk_ibufg), 
.CLKFX_OUT(clock), 
.CLK0_OUT(CLK0_OUT)
);

得到如下警告:

The following Clock signals are not routed on the dedicated global clock routing resources. This will usually result in longer delays and higher skew for the clock load pins. This could be the result of incorrect clock placement, more than 8 clocks feeding logic in a single quadrant of the device, or incorrect logic partitioning into the quadrant(s). Check the timing report to verify the delay and skew for this net Net Name: clock

时序报告

解读:
对于这个问题,其实是对Xilinx的时钟资源管理不了解导致的,可以用一句简短的话来说明,那就是Xilinx的时钟管理资源,包括低版本的DCM,PLL,或者是高版本的MMCM等,对时钟的处理都包含了约束以及时钟树的处理,包括上面的例化文件中的:

IBUFG clk_ibufg_inst ( .I(CLK_50MHZ) , .O(clk_ibufg) );
BUFG  clk_bufg_inst  ( .I(clock) , .O(clk));

全都是多此一举,且由此多此一举造成编译器的“困惑”,也就是说,例化的时钟管理模块内部已经将输入时钟上了时钟数资源,而不需要手动再来一次。

我们来看参考资料的解读:
因为你使用的是CoreGenerator向导,所以大多数低级的东西都可以作为向导的一部分被选择,这意味着你不需要手动实例化它们。

对于输出,由于您选择了自动,您不需要添加BUFG。否则DCM可能会为输出实例化一个BUFG,然后再为您的BUFG提供信号(即连续两个)。两个全局时钟缓冲区不应该放在一排,首先是因为没有必要,其次是因为这意味着信号必须从第一个BUFG离开它所在的全局时钟网络,才能到达第二个BUFG的输入,因此你的警告。

您还应该能够选择在DCM向导中使用IBUFG作为输入,这意味着您不需要手动实例化它。

继续提问:

我在综合的过程中得到一个说 "信号已分配但从未使用"。从数据手册上看,这个信号是用来采用反馈进行纠偏的。如何将它反馈到DCM中,并消除这个警告?因为在IP核生成模板上显示CLK0_OUT被自动送入CLK_FB。

解读:

从评论中你还提到了CLK0_OUT未被使用的警告。我只能假设你当时没有把它连接到任何地方。CLK0如你所说是用于反馈的,但根据Xilinx应用说明XAPP462(pg10),如果只使用CLKFX输出端口,你就不需要反馈,在你的情况下确实如此。

"没有反馈。如果只使用CLKFX或CLKFX180输出,则允许。"

如何正确使用板上差分时钟?

案例如下:

我的SP601评估板配有一个2.5 V LVDS差分200 MHz振荡器。到目前为止,我只使用了板子随附的单端时钟。我在如何格式化用户约束文件以使用差分时钟方面遇到麻烦。到目前为止,这是我的用户约束文件中的内容。

NET "clk_N" LOC = "K16"; ## 5 on U5 EG2121CA, 5 of U20 SI500D (DNP)
NET "clk_P" LOC = "K15"; ## 6 on U5 EG2121CA, 4 of U20 SI500D (DNP)

使用单端时钟时,我以前遇到的是:

NET "clk" LOC = "V10"; ## 5 on X2 USER OSC Socket
NET "clk" TNM_NET = "clk";
TIMESPEC "TS_clk" = PERIOD "clk" 37 ns HIGH 50%;

另外,在将时钟成功包含在用户约束文件中之后,我必须对代码进行哪些更改才能从单端时钟切换到差分时钟?最初,我有一个信号称为clk,并且触发了该信号的上升沿。现在我有两个信号,上升沿方法似乎不起作用。我应该发出一个新信号clk_1-- clk_2,两个差分信号在哪里clk_1和clk_2?我不知道更改时钟源是否会影响其余代码的编写方式。

问题解读:

对于差分时钟的约束,只需要约束一对中的一个,通常是P端,下面是Xilinx网站给出的回答:

Vivado Constraints - How do I constrain a differential clock or data pair in Vivado?

只有差分端口的P侧需要被约束。

该工具将把约束向前传播到IBUFGDS例化模块的输出。

如果两者都受到约束,工具将把它们作为两个独立的时钟定义,并分析它们之间的时钟间路径。

这可能导致不正确的要求。

同样,在输入延时和输出延时约束中,只需要对差分数据端口的P侧进行约束。

N侧路径的分析与P侧完全相同。

NET "clk_P" LOC = "K15" | IOSTANDARD=LVDS_33; ## 6 on U5 EG2121CA, 4 of U20 SI500D (DNP)
NET "clk_N" LOC = "K16" | IOSTANDARD=LVDS_33; ## 5 on U5 EG2121CA, 5 of U20 SI500D (DNP)
NET "clk_P" TNM_NET = "clk";
TIMESPEC "TS_clk" = PERIOD "clk" 5 ns HIGH 50%;

对P端进行位置约束,获得正确的IOSTANDARD,这将取决于时钟源,也许是LVPECL_25,LVPECL_33,LVDS_25或LVDS_33。参见Xilinx UG381。您可能还需要与IOSTANDARD一起设置DIFF_TERM = TRUE来启用内部100欧姆差分终端。检查电路板的布局/原理图,看是否已经有分立的终端电阻,在这种情况下,应将DIFF_TERM保持关闭状态或将DIFF_TERM = FALSE添加。

然后,您将需要实例化IBUFGDS而不是IBUFG,也许是这样的:

IBUFGDS ibufg_inst (.I(clk_P), .IB(clk_N), .O(clk_ibufg));
BUFG bufg_inst (.I(clk_ibufg), .O(clk));

然后像以前一样使用clk。如果您使用的是DCM或PLL,这无需上述两个原语的例化。

在定义时刻初始化还是使用复位初始化?

案例如下:

module rf(out1,ack,en,a,f,c,d,e,clka);
  input [7:0] a,f,c,d,e;
  input clka, en;
  output reg [7:0] out1;
  output reg ack;
  reg[7:0] b[1:5];
  reg [1:0] first=0; reg [2:0] k;

initial begin
  for (k = 1; k <6; k = k + 1) begin
    b[k] = 0;
  end
end

always @(negedge clka) begin
  if (en==1) begin 
    if (first==0) begin
      first<=1;
    end
    if (first==1) begin 
      first<=2;
      b[1]<=a;            
      b[2]<=f;               
      b[3]<=c;             
      b[4]<=d;            
      b[5]<=e; 
    end
  end
end
endmodule

我初始化reg first = 0; 这样对吗 ?因为它在仿真后给出正确的结果,但是当我们综合它时有什么问题吗?

问题解读:

这里只选择了部分问题,也给出部分回复,因为觉得设计有点怪。

在声明时初始化寄存器是完全可以综合的。它告诉编译器寄存器的开机值应该是多少。一般来说,反正寄存器的初始值总是0,如果你选择将它们设置为1,它基本上会使用泡推优化(bubble pushing optimisations )来反转寄存器的值,仍然使用0作为初始值(但就你的逻辑而言,它实际上是1)。

然而,对于数据总线以外的任何东西(由一些有效的信号限定),不建议这样做。因为如果你的逻辑中的其他地方有一个复位信号会发生什么。如果你的一半逻辑在某一点上被复位,而你的控制信号只有开机初始值而没有复位,那么你的两个信号就会不同步--一个是在一个很好的已知复位状态,另一个是在复位发生时的任何未知状态。
对于合格的数据信号,只要将有效的信号复位到已知的无效状态,一个不在乎/未知的值并不重要。

较好的做法是对所有的控制信号和有效信号使用一个复位信号,使其具有一个复位值,无论是同步的还是异步的。这样就不需要初始开机值的要求(你仍然可以添加,但不再需要)。开机值将由综合工具根据要求的复位值来决定。

另外,如果您的RTL以FPGA为目标,则将寄存器初始化为一个值是完全合法的,且使用initial块进行初始化也无所谓,但是无法在ASIC流程中综合。初始化值将成为位流文件的一部分(如果您习惯使用Xilinx术语),并将在“配置” FPGA时加载。实际上,Xillinx建议不要添加显式复位,因为复位信号必须布线到您的所有逻辑。但是,如果您打算稍后将其移植到ASIC,则必须添加一个复位(最好是同步)。

最后,补充一句,我想说的是,如果是考虑代码需要移植到ASIC,则最好不要使用initial块初始化或者定义时候初始化;如果不存在这个问题,尽管Xilinx建议不要添加显示复位信号,我想也不太符合大家的习惯,尽量做到统一,即使会稍微加重布线的负担,但是我想我们的设计难道还不能承受一种大众乃至其他平台推荐的复位方式吗?这是一个利弊权衡的问题,在我眼里,使用显示的复位信号进行初始化,利大于弊。(个人观点,不喜勿喷!)

参考文献

What does frame, word, and bit mean on a FPGA

Vivado Constraints - How do I constrain a differential clock or data pair in Vivado?

user_guides/ug381

Is it right to initialize a reg in verilog and apply condition with initial value of reg in Verilog?

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 97 7 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
李锐博恩
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区