【深入浅出玩转FPGA学习6------FPGA重要设计思想及工程应用】

速度和面积互换原则

所谓速度,是指整个工程稳定运行所能够达到的最高时钟频率,它不仅和FPGA内部各个寄存器的建立时间、保持时间以及FPGA与外部器件接口的各种时序要求有关,而且还和两个紧邻的寄存器间(有紧密逻辑关系的寄存器)的逻辑延时、走线延时有关。所谓面积,可以通过一个工程运行所消耗的触发器(FF)、查找表(LUT)数量或者等效门数量来衡量。
速度和面积始终是一对矛盾的统一体。速度的提高往往需要以面积的扩增为代价,而节省面积也往往会造成速度的牺牲。因此,如何在满足时序要求(速度)的前提下最大程度地节省逻辑资源(面积)是摆在每个设计者面前的一个难题。
若从系统的角度来解释速度和面积的呼唤,可以如图所示。
在这里插入图片描述
在一个FPGA内部,占用一定的逻辑资源只能达到50Mbps的数据吞吐量。如果采用了串/并转换的思想,用3倍的逻辑资源来实现同样的功能,则能够达到150Mbps的数据吞吐量。这是从系统设计的角度来阐释速度和面积的互换原则,它很好地利用了FPGA的并行性.

乒乓操作及串/并转换设计

乒乓操作

乒乓操作是一个主要用于数据流控制的处理技巧,典型的乒乓操作如图所示。
在这里插入图片描述
外部输入数据流通过“输入数据选择控制”模块送入两个数据缓冲区中,数据缓冲模块可以为任何存储模块,比较常用的存储单元为双口RAM(Dual RAM)、SRAM、SDRAM、FIFO等。
在第1个缓冲周期,将输入的数据流缓存到“数据缓冲1”模块。在第2个缓冲周期,“输入数据选择控制”模块将输入的数据流缓存到“数据缓冲2”模块的同时,“输出数据选择控制模块将”数据缓冲1“模块第1个周期缓存的数据流送到”后续处理“模块进行后续的数据处理。在第3个缓冲周期,在”输入数据选择控制“模块的再次切换后,输入的数据流缓存到“数据缓冲1”,于此同时,“输出数据选择控制”模块也做出切换,将“数据缓冲2”模块缓存到第2个周期的数据送到“后续处理”模块。如此不断循环。
这里正是利用了乒乓操作完成数据的无缝缓冲与处理。乒乓操作可以通过“输入数据选择控制”和“输出数据选择控制”按节拍、相互配合地进行来回切换,将经过缓冲的数据流没有停顿地送到“后续处理”模块。
尝试将乒乓操作处理运用在液晶显示的控制模块上,如图所示。
在这里插入图片描述
对于外部接口传输的图像数据,以一帧图像为单位进行SDRAM的切换控制。当SDRAM1缓存图像数据时,液晶显示的是SDRAM2的数据图像;反之,当SDRAM2缓存图像数据时,液晶显示的是SDRAM1的数据图像;如此反复。这样处理的好处在于液晶显示的图像切换瞬间完成,掩盖了可能比较缓慢的图像数据流变化过程。

串/并转换

串/并转换是高速数据流处理的重要技巧之一。串/并转换的实现方法多种多样,根据数据的顺序与数量的要求,可以选用寄存器、双口RAM(Dual RAM)、SRAM、SDRAM、FIFO等实现。对于数量比较小的设计可以采用移位寄存器完成串/并转换。
在工程应用中,如何体现串/并转换设计的思想呢?怎样才能提高系统的处理速度呢?我们可以先来做一个串/并转换的框架型设计。如图所示,串行输入的数据通过FPGA内部的n个移位寄存器后,最后并行输出的是一个n位宽的并行总线数据。
在这里插入图片描述
移位一般是需要有时钟做同步的,也就是说,n个时钟采样到的串行数据需要在n个时钟周期后以并行的方式输出,这是最基本的串入并出的设计思想。对于串行接口大行其道的高速数据传输领域,这种简单的转换也是接口芯片的重要任务之一。但从FPGA系统设计的角度来看,串/并转换又有着更深的涵义。正如在速度和面积互换思想中提到的那个实例,利用3倍的面积换取了 3倍的吞吐量,它也是串/并转换思想的体现。

流水线设计

流水线设计可以从某种程度上提高系统频率,因此常用于高速信号处理领域。如果某个设计可以分为若干步步骤进行处理,而且整个数据处理过程是单向的,即没有反馈运算或者迭代运算、前一个步骤的输出即是下一个步骤的输入,就可以考虑采用流水线设计方法来提高系统的工作频率。
在很多高速信号处理领域都运用了流水线处理的方法,如高速通信系统、高速信号采集系统、图像处理系统甚至很多处理器和控制器等。流水线处理方法之所以能够在很大程度上提高数据流的处理速度,是因为它进行了处理模块的复制,也很好地体现了面积换速度地思想。
如图所示,典型地流水线设计是将原本一个时钟周期完成的较大地组合逻辑通过合理的切割后分为多个时钟周期完成。这样一来,该部分逻辑运行的时钟频率会有明显的提升,尤其当它是一条关键路径时,采用流水线设计后整个系统的性能都会得到提升。
在这里插入图片描述
如图所示,假设一个流水线设计需要4个步骤完成一个数据处理过程,那么从有数据输入(in1)的第1个时钟周期(1clk)开始,直到第4个时钟周期(4clk)才处理完第1个输入数据,但是在以后的每个时钟周期内都会有处理完成的数据输出。也就是说,流水线设计只在开始处理时需要一定的处理时间,以后就会不间断地输出数据,从而大大提高处理速度。如果该设计不采用流水线设计,那么处理一个数据就需要4个时钟周期,而采用流水线设计则能够提高近4倍的处理速度。
在这里插入图片描述

逻辑复制与模块复用

逻辑复制是一种通过增加面积来改善时序条件的优化手段,它最主要的应用是调整信号的扇出。如果某个信号需要驱动的后级逻辑信号较多,换句话说,也就是其扇出非常大,那么为了增加这个信号的驱动能力,就必须插入很多级的Buffer,这样就在一定程度上增加了这个信号的路径延时。这种情况下就可以复制生成这个信号的逻辑,用多路同频同相的信号驱动后续电路,是平均到每路的扇出变低,这样就不需要插入Buffer就能满足驱动能力增加的要求,从而节约该信号的路径延时。

EX1B

input a,b,c,d;
input sel;
output dout;
assigin dout = sel ? (a+b):(c+d);

如图所示,从EX1B代码综合出来的RTL视图来看,ADDER内部使用了两个加法器,分别做好了(a+b)和(c+d)的运算,然后把结果送到后端2选1选择器作为输入,所以此代码综合出了两个加法器和一个2选1选择器。
在这里插入图片描述

EX2B

input a,b,c,d;
input sel;
output dout;
wire ab,cd;
assign ab = sel ? a:c;
assign cd = sel ? b:d;
assign dout = ab + cd;

如图所示,从EX2B代码综合出来的RTL视图来看,这里使用了两个2选1选择器和一个加法器来实现。
在这里插入图片描述
相比两端不同的代码(其设计要求是一样的),EX1B占用的资源多一些,但是速度快些;而EX2B恰恰相反。有时大家似乎更倾向于EX2B的设计方式,因为它节约资源。但是从另一方面来看,EX1B正是一种逻辑复制的设计方法,因为这个设计的实现本来就只要一个加法器就可以了(如EX2B),但是为了加快速度,就需要进行逻辑复制(如EX1B)。EX1B就是利用了两个加法器,以增加面积为代价换来了速度。从另一个角度说,逻辑复制也可以说是面积换速度的一个特例。
需要说明的是,现在很多综合工具都可以自动设置最大扇出值,如果某个信号的扇出值大于最大扇出值,则该信号将会自动被综合工具复制。
模块复用恰恰是逻辑复制的一个逆过程,它的好处就在于节省面积,同时也要以速度的牺牲为代价。上面的实例中,EX2B相对于EX1B就是一个模块复用的过程。

模块化设计

模块化设计是FPGA设计中一个很重要的技巧,它能够使一个大型设计的分工协作、仿真测试更加容易,使代码维护或升级更加便利。
如图所示,一般整个设计的顶层只做例化,不做逻辑,然后一个顶层下面会有模块A、模块B、模块C等,模块A/B/C下又可以分多个子模块来实现。
在这里插入图片描述
如此一来,就可以将大规模复杂系统按照一定规则划分成若干模块,然后对每个模块进行设计输入与综合,并将实现结果约束在预先设置好的区域内,最后将所有模块的实现结果有机地组织起来,就能完成整个系统的设计。
对于顶层模块的设计,主管设计师需要完成顶层模块的设计输入与综合,这也是进行模块化设计实现阶段的第1步即初始预算。
对于子模块的设计,多个模块设计师相对独立地并行完成各自子模块地设计输入与综合,这也是进行模块化设计实现阶段的第2步即子模块的激活模式实现。
模块化设计的实现步骤是整个模块化设计流程中最重要、最特殊的,它包含:

1.初始预算,本阶段是实现步骤的第1步,对整个模块化设计起着指导性的作用。在初始预算阶段,项目管理者需要为设计的整体进行位置布局,只有布局 合理,才能够在奻大程度上体现模块化设计的优势;反之,如果因布局不合理而在较后的阶段 需要再次进行初始预算,则需要对整个实现步骤全面返工。

2.子模块的激活模式实现(ActiveModule lmpl叩entation),在该阶段,每个项目成员井行完成各自子模块的实现。

3.模块的最后合井(FinalAssembly),在该阶段项目管理者将顶层的实现结果和所有子 模块的激活模式实现结果有机地组织起来,完成整个设计的实现。

模块划分的基本原则是:子模块功能相对独立,模块内部联系尽量紧密,而模块间的连接尽拱简单。对于那些难以沛足模块划分准则且具有强内部关联的复杂设计,并不适合采用模 块化设计方法.
给出一个最简单的模块化应用实例,其顶层模块如下:

module my_uart_top(
					clk,rst_n,rs232_rx,rs232_tx
					);
	input clk;
	input rst_n;
	input rs232_rx;
	output rs232_tx;
	wire bps_start1,bps_start2;
	wire clk_bps1,clk_bps2;
	wire[7:0] rx_data;
	wire rx_int;
speed_select   speed_rx(
					.clk(clk),
					.rst_n(rst_n),
					.bps_start(bps_start1),
					.clk_bps(clk_bps1)
								);
my_uart_rx   my_uart_rx(
						.clk(clk),
						.rst_n(rst_n),
						.rs232_rx(rs232_rx),
						.rx_data(rx_data),
						.rx_int(rx_int),
						.clk_bps(clk_bps1),
						.bps_start(bps_start1)
						);
speed_select   speed_tx(
						.clk(clk),
						.rst_n(rst_n),
						.bps_start(bps_start2),
						.clk_bps(clk_bps2)
						);
my_uart_tx    my_uart_tx(
						.clk(clk),
						.rst_n(rst_n),
						.rx_data(rx_data),
						.rx_int(rx_int),
						.rs232_tx(rs232_tx),
						.clk_bps(clk_bps2),
						.bps_start(bps_start2)
						);
endmodule

一般情况下,不在顶层模块做任何逻辑设计,哪怕只是一个逻辑与操作,比较好的设计会明确地区分每一个模块单元。 上面这个设计是要实现一个串口自收发通信的功能,具体来说就是不断地检测串口接收信号 rs232_rx 是否有数据,如果接收到起始位就把数据保存,然后再转手把接收到的数据通过串口发送信号 rs232_tx 发回给对方。 即使是这样一个还不算太复杂的功能,如果都堆到一个模块里,代码不仅又臭又长,而且编写代码者如果不理好思路很容易就会写晕了,以后维护起来或者要移桢就更难了。
因此,模块化的设计势在必行,上面的代码就把这个设计分成了 4 个模块:

  1. my_uart_tx :串口数据接收模块,
  2. speed_tx ;串口数据接收时钟校准模块;
  3. My_ uart_rx :串口数据发送模块;
  4. speed_rx:串口数据发送时钟校准桢块。

如此划分,层次清晰而且思路明确,写起代码来更是游刃有余。先来说模块例化的一些细节吧,就拿speed_select模块例化来看。第1行的“speed_selectspeed_rx(",其中speed_select是要例化的模块名,是固定的;而speed_rx则是任意给这个模块取的名字,用它来区分例化多个相同的模块。就如speed_tx和speed_rx两个模块,因为它们的逻辑设计都是 一样的,所以写为一个模块,然后在例化的时候给不同的名称就可以了。这有点类似软件设计 中的子程序调用.但又有所不同,由于硬件设计的并行性,这里实现了逻辑复制的功能,实际上 在最后的硬件上是两个一模一样的speed_select逻辑,可以说它们是完全独立的。即便是对千硬件资源的消耗没有减少,采用拱块化设计以后也能从很大程度上减少设计者的重复劳动。
信号的例化是这样的.clk(clk),点号后的clk代表例化模块内部的信号(是固定的,必须和内部的信号名一致),而括号内的clk则是例化模块的外部连接,可以与例化模块内的信号名不同。
在编译后,可以从Project Navigator窗口中看到例化的子模块,如图所示:
在这里插入图片描述
另外,从QuartusII提供的RTL视图里,能够更深刻地感受到模块化带来的层次感,如图所示:
在这里插入图片描述

时钟设计技巧

时钟信号在很大程度上决定了整个设计的性能和可靠性,尽量避免使用FPGA内部逻辑时钟信号在很大程度上决定了整个设计的性能和可靠性,尽量避免使用FPGA内部逻辑出现毛刺,影响设计的功能实现:组合逻辑固有的延时也容易导致时序问题。

内部逻辑产生的时钟

若使用组合逻辑的输出作为时钟信号或异步复位信号,设计者必须对有可能出现的问题采取必要的预防措施。我们知道,在正常的同步设计中,一个时钟一个节拍的数据流控制能够,保证系统持续稳定的工作。但是,组合逻辑产生的时钟不可避免地会有毛刺出现,如果此时输人端口的数据正处于变化过程,那么它将违反建立和保持时间要求,从而影响后续电路的输出状态,甚至导致整个系统运行失败。
对于必须采用内部逻辑作时钟或者复位信号的应用,也还是有解决办法的。思路并不复杂,和异步复位、同步释放的原理是一样的。如图所示,在输出时钟或者复位信号之前,再用系统专用时钟信号(通常指外部晶振输人时钟或者PLL处理后的时钟信号)打一 拍,从而避免组合逻辑直接输出,达到同步处理的效果。对于输出的时钟信号或复位信号,奻好让它走全局时钟网络,从而减小时钟网络延时,提升系统时序性能.
在这里插入图片描述

分频时钟与使能时钟

设计中往往需要用到主时钟的若干分频信号作为时钟,即分频时钟。可别小看这个所谓的分频时钟,简简单单不加处理的乱用时钟那就叫时钟满天飞,是很不好的设计风格。言归正传,如果设计中确实需要用到系统主时钟的分频信号来降低频率时,该如何处理呢?
对于资源较丰富的FPGA,一般都有内嵌的多个PLL或者DLL专门用于时钟管理,利用它们就可以很容易地达到多个时钟的设计.输出时钟能够配置成设计者期望的不同频率和相位差(相对于输人时钟),这样的时钟分频是最稳定的。但是对于某些无法使用PLL或者 DLL资源的器件又该怎么办呢?推荐使用“使能时钟“进行设计,在“使能时钟”设计中只使用原有的时钟,让分频信号作为使能信号来用。
下面举一个实例来说明如何进行使能时钟的设计,该设计需要得到一个50MHz输入时钟的5分频信号即10MHz。

input clk;    //50Mhz时钟信号
input rst_n;   //写使能信号,低有效
reg[2:0] cnt;    //分频计数寄存器
wire en;    //使能信号,高电平有效
//5分频计数0~4
always @ (posedge clk or negedge rst_n)
			if(!rst_n) cnt <= 3'd0;
			else if (cnt<3'd4) cnt <= cnt +1'b1;
			else cnt <= 3'd0;
assign en=(cnt==3'd5);     //每5个时钟周期产生1个时钟周期高脉冲
//使用使能时钟
always @ (posedge clk or negedge rst_n)
			if(!rst_n) ...;
			else if(en)  ...;

如图所示,使能信号不直接作为时钟使用,而是作为数据输入端的选择信号,这样就避免了使用分频时钟。
在这里插入图片描述

门控时钟

组合逻辑中多用门控时钟,一般驱动门控时钟的逻辑都是只包含一个与门(或门),如果有 其他的附加逻辑,容易因竞争产生不希望的毛剌。如图所示,门控时钟通过一个使能信 号控制时钟的开或者关。当系统不工作时可以关闭时钟,整个系统就处于非激活状态,这样能够在某种程度上降低系统功耗。
在这里插入图片描述
然而,使用门控时钟并不符合同步设计的思想,它可能会影响系统设计的实现和验证。单纯从功能实现来看,使用使能时钟替代门控时钟是一个不错的选择;但是使能时钟在使能信号关闭时,时钟信号仍然在工作,它无法像门控时钟那样降低系统功耗。
是否有一种设计方法既可以降低系统功耗,又能够稳定可靠的替代门控时钟呢? Altera就提出了一种解决方案,且待我慢慢道来。 如图所示,对于上升沿有效的系统时钟 clk,它的下降沿先把门控信号(gating signal) 打一拍 ,然后再用这个使能信号 (enable) 和系统时钟(clk)相与后作为后续电路的门控时钟。
在这里插入图片描述
这样的门控时钟电路很好地解决了组合逻辑常见的一些问题。 它避免了毛刺的出现,同时也有效抑制了亚稳态可能带来的危害。 但是从另一个方面来说,如果这个设计的系统时钟 (clk) 占空比不是很稳定 ,或者输出的使能信号(eoable) 与时钟信号 (elk) 的逻辑过于复杂(不止这个例子中一个与门那么简单),那么它也会带来一些功能或时序上的问题。 总的来说,只要设计者控制好这个设计中时钟的占空比和门控逻辑复杂度,它还是比图 2.37 给出的门控时钟方案更可行。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周猿猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值