Menu Close

面向硬件的程序设计思维

在业内,很多资深工程师习惯把FPGA/CPLD器件称为逻辑器件,把相应的开发任务称为逻辑设计。究其原因就是FPGA器件的本质任务就是逻辑开发,开发过程就是用户的思维逻辑转换成数字电路逻辑,其中最有效的设计手段就是状态机。基于状态机模式,可以将所有的复杂数字电路功能转换成有条理的逻辑连接,不仅实现设计目的,还能达到可维护、可测试的高级效果。虽然目前FPGA已进入SoPC阶段,但逻辑开发阶段仍然是FPGA领域最重要的发展方向,并且也是SoPC存在和发展的基础,因此,本文重点介绍逻辑开发中的一些关键知识和设计方法,为后续的深入学习打好基础

Verilog HDL设计进阶

面向硬件的程序设计思维

所谓的面向硬件的设计思维指的是如何将具体功能形成硬件的RTL级模型,再选择具体的物理电路来实现,最后用合适的语言去实现,而不是凭空写verilog代码。可以说,Verilog代码。可以说,verilog是电路的一种适合管理的高级记录形式,不是传统意义上的编码语言。

程序的并行执行特点

和C/C++等顺序编程语言不同,HDL语言用于电路描述,代替着门电路和触发器电路。在任何时期,只要FPGA上电,芯片内部各个模块将同时工作,不会因为各个模块之间的先后不同而存在执行顺序的差异,这需要设计人员以并行思维来考虑算法结构。

模块内部的执行顺序比较复杂,在优秀的设计中模块内部是并行执行的,即使在“begin…end”语句内部。这里,不少读者可能存在疑问,“begin…end”语句不是串行执行的模块吗?下面对此进行详细解释。

“begin…end”之间存在阻塞赋值和非阻塞赋值两种方式,如果使用不当会存在冒险和竞争现象,必须遵循下面两条准则:

  1. 在描述组合逻辑的always块中使用阻塞赋值,则综合组合逻辑的电路结构;
  2. 在描述时序逻辑的always块中使用非阻塞赋值,则综合时序逻辑的电路结构。

在组合逻辑中,阻塞赋值只与电平有关,往往和触发沿没有关系,可以将其看成并行执行的,在时序逻辑中,非阻塞赋值是并行执行的,因此,优秀的HDL设计,其内部语句也是并行执行的。

例子:Verilog HDL语句并行执行特点的实例说明

module feizusefuzhi(clk, reset, a, b);

input clk;;

input reset;;

input [3:0]a;

output [3:0]b;

reg [3:0] tempal, tempa2, b;

always @ (posedge clk) begin

If(!reset) begin

temal1 <= 0;

temal2 <= 0;

b <= 0;

end

else begin

temal1 <= a + 1`b1;

temal2 <= temal1 + 1`b1;

b <= tempa2 + 1`b1;

end

end

endmodule

时钟是程序的执行控制器

上文解释了HDL程序的并行性,但在设计中需要像C/C++语言的串行控制功能,如先接收外部配置指令,然后接收数据并完成模块内部配置,再将配置结果反馈到外部,这需要通过时间的精确定位来获取严格的先后关系。那么怎么来实现呢?

其实很简单,假设全部时间需要5个时钟周期,那么利用一个周期为5的循环计数器来实现。在计数器为1的时候,完成事件1;在计数器为2的时候,完成事件2…如此循环即可。总结起来,就是按照时钟节拍来完成串行控制,当然,这样的电路在FPGA资源的利用上是存在浪费的,因为在执行事件1,用于执行事件2,3,4,5的逻辑处于等待状态,但其始终占用着逻辑资源。

时钟执行控制器的实例

module clk_model(clk, reset, a1, y1, y2);

input clk;

input reset;

input [7:0] a1;

output [7:0] y1,y2;

reg [7:0] y1, y2;

reg [2:0] cnt;

always @ (posedge clk) begin

If(!reset)begin

cnt <= 0;

y1 <= 0;

y2 <= 0;

end

else begin

if(cnt == 2`b11)

cnt <= 2`b00;

else

cnt <= cnt + 1`b1;

case(cnt)

2`b00:begin

y1 <= a1 + 1`b1;

y2 <= y2;

end

2`b01:begin

y1 <= y1;

y2 <= y1 + 1`b1;

end

default:begin

y1 <= y1;

y2 <= y2;

end

endcase

end

end

endmodule

上面的代码中有3个加法器,即为变量y1、y2、以及cnt的计算都生成了加法器,但y1与y2的加法器却在时钟信号clk的控制工作,其工作时间是不连续的,每4个周期计算1次,且y1的计算永远在y2的计算之前。

程序的可综合性

IEEE的verilog HDL标准只是定义了verilog HDL语言本身的规范,其本身是面向HDL仿真的,并不是所有verilog HDL语言写的程序都是硬件可综合的。Verilog语言中可以被综合的语言称为可综合子集。每个厂商的综合工具所支持的可综合子集可能有所不同。下面以Xilinx综合工具XST为例来说明可综合的verilog HDL风格。

XST支持的verilog结构

  1. 线网类型:wire、tri、supply、supplu0等;
  2. 寄存器类型:reg、interger、time等;
  3. 连续赋值;
  4. 门原型和模块例化;
  5. Always模块、用户定义的task和function;
  6. Input、output和input端口;
  7. 运算符;
  8. 行为语句:如if-else-if、case、casex、casez、for、repeat、while、forever、begin、end、fork、join。
  9. 过程赋值(procedural assignments):阻塞赋值“=”,非阻塞赋值“<=”(同一个寄存器不能同时使用“<=”和”=”)
  10. 编译器指令:`define、`ifdef、`else、`endif、`include、`undef
  11. 其他:在本地“begin-end”模块中,赋值语句的左端和右端可以对向量进行可变参数的索引。

XST不支持的Verilog结构

  1. 线网类型:trireg、wor、trior、wand、tri0、tri1、strength;
  2. 寄存器类型:real;
  3. 单向和双向开关、pull-up、pull-down;
  4. 行为语句:deassign、wait;
  5. 命令的事件(Event)和事件触发。
  6. UDP和Specify模块
  7. Force、release和层次化的Net名称(仅用于仿真)

XST忽略的verilog结构

遇到下面这些语言结构时不会中断综合进程

  1. delay、delay控制、驱动强度
  2. 标量化、向量化(scalared、vectored)
  3. initial模块
  4. 除了`define、`ifdef、`else、`endif、`include、`undef之外的编译指令
  5. 对系统task和系统funtion的调用(仅用于仿真)

“面积”和“速度”的转换原则

这里的“面积”主要是指设计所占用的FPGA逻辑资源,即利用所消耗的触发器(FF)和查找表(LUT)来衡量。“速度”是指在芯片上稳定运行时能够达到的最高频率。面积和速度这两个指标始终贯穿着FPGA的设计,是设计质量评价的最终标准,本段主要讨论一个基本原则:面积和速度的交换。

面积和速度是一对对立和统一的矛盾体。一方面,要提高速度,就需要消耗更多的资源,即需要更大的面积;另一方面,为了减少面积,就需要降低处理速度。所以既要提高速度,又要减少面积,是不可能同时实现的。但在实际中,总是存在二者之间的平衡,也意味着二者可以互换。

面积和速度交换的具体操作很多,比如模块复用、乒乓操作、串并转换中利用这一互换原理进行设计。

给出一个实际开发中串并行变换的示例

假设数据速率是乘法器模块处理速度的3倍,那么由于乘法器模块的数据吞吐量满足不了要求,在这种情况下,就利用面积换速度的思想,复制3个乘法器模型。首先将输入数据进行串/并转换,然后利用这3个模块并行处理所分配到的数据,最后将处理结果并/串转换,达到数据速率的要求。这个例子只是对面换速度思想的一个简单举例,在具体操作过程中,还涉及很多方法和技巧,需要大家从大量实例中自己体会。

%title插图%num

串并转换的示意图

Posted in FPGA, FPGA, Verilog, Verilog
0 0 投票数
Article Rating
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论

相关链接