数字逻辑实践4->面向硬件电路的设计思维--FPGA设计总述
本文是对实验课上讲解的“面向硬件电路的设计思维”的总结,结合数字逻辑课本,进行提炼和整理。
主要来源是课件与本人整理,部分参考了网络大佬的博客。
本文主要介绍不同于之前软件设计思维的硬件设计思维,从非阻塞赋值、并行、面积速度转换、同步电路设计原则、模块划分设计、if-case对比等方面进行整理。
内容太多,我整理了好几天,在浩如烟海的网络前有点无力,想想是自己的实践不够,有一些问题没有亲身体验;也不能一蹴而就,得久久为功。所以这篇文章就当作一个Verilog学习与FPGA设计的总述性文章,后续继续学习我会加深对这些知识的理解。
00 阻塞赋值和非阻塞赋值
概念
回忆一下课本上的相关内容。
阻塞赋值:
"="
Verilog编译器按照这些语句在always块中的先后顺序依次执行。
如果一个变量通过阻塞赋值语句赋值,则这个新赋的值会在这个block中的后续语句中使用。
相当于串行
非阻塞赋值:
"<="
always块中所有非阻塞赋值的语句在求值时所用的值是最初进入always时各个变量已经具有的值。
换一个角度讲,"<="左侧的被赋值变量,只在always结束时统一被更新。
相当于并行
时序电路实例
阻塞赋值
先来看一看这段代码:
1 module example5_5 (x1, x2, x3, Clock, f, g);
2 input x1, x2, x3, Clock;
3 output reg f, g;
4 always @(posedge Clock)
5 begin
6 f = x1 & x2;
7 g=f | x3;
8 end
9 endmodule
可以看到关键点是g的表达式,由于是阻塞赋值,所以相当于:
g=(x1 & x2) | x3;
综合出的电路如图:

非阻塞赋值
1 module example5_6 (x1, x2, x3, Clock, f, g);
2 input x1, x2, x3, Clock;
3 output reg f, g;
4 always @(posedge Clock)
5 begin
6 f <= x1 & x2;
7 g <= f | x3;
8 end
9 endmodule
这个区别之处就在于这个g,是x3与前一个 f 进行"|"运算。

思考
将阻塞赋值的示例代码中的两个执行语句互换位置,会发生什么情况?
可以料见影响比较大。
可见阻塞赋值描述时序电路有风险。
组合逻辑实例
相反的,如果我们要实现 f = a1a0 + a2a1这样一个函数;
阻塞赋值
1 always @(A)
2 begin
3 f = A[1] & A[0];
4 f=f | (A[2] & A[1]);
5 end
非阻塞赋值
1 always @(A)
2 begin
3 f <= A[1] & A[0];
4 f <= f | (A[2] & A[1]);
5 end
可见这段代码有两个特征;
非阻塞赋值的结果在always结束后才可以看到
多次赋值时,后覆盖前。
这两个特征使得第二个f语句出现问题,因为第二个语句
f <= f | (A[2] & A[1]);
右侧的f的值是不可见的。
总结
对组合逻辑建模采用阻塞赋值
对时序逻辑建模采用非阻塞赋值
用多个always块分别对组合和时序逻辑建模
尽量不要在一个always块里面混合使用阻塞赋值和非阻塞赋值。如果在同一个块即为组合逻辑又为时序逻辑,应使用“非阻塞赋值”
01 程序是并行执行的
这里给的例子没怎么看懂。自己查了一下。
先说结论:
各个always块是并行执行的,
always块和initial块之间是并行执行的,
begin-end块内是顺序执行的,
但是非阻塞赋值(<=)是并行执行的,阻塞赋值(=)是顺序执行的,这条优先。且硬件思想的集中体现就是前面提到过的非阻塞赋值带来的并行执行语句。
再回去看例子:
1 module test ( clk, reset, a, b );
2 input clk;
3 input reset;
4 input [ 3:0 ] a;
5 output [ 3:0 ] b;
6
7 reg [ 3:0 ] tempa1, tempa2, b;
8
9 always @ ( posedge clk ) begin
10 if ( ! reset ) begin
11 tempa1<=0;
12 tempa2<=0;
13 b<=0;
14 end
15 else begin
16 tempa1<= a + 1’b1;
17 tempa2<= tempa1 + 1’b1;
18 b<= tempa2 + 1’b1;
19 end
20 end
21 endmodule
可以料见实现的电路:
下面借鉴了这篇文章

波形图:

可以看到强调的还是上面说过的非阻塞赋值的特点。
02 程序的可综合性
实验任务里总有这么一句:“用可综合的代码......”
什么是可综合性,什么又是不可综合性呢?
下面学习了这篇文章
这篇文章讲的挺多,但是我现在这个RTL级还没搞明白的菜鸟用不到这么多,基本筛选如下:
不可综合的Verilog语句:
initial
只能在test bench中使用,不能综合。
assign 和deassign
不支持对reg 数据类型的assign或deassign进行综合,支持对wire数据类型的assign或deassign进行综合。
fork join 不可综合,可以使用非块语句达到同样的效果。
这个块是并行执行的,但是不可综合。
敏感列表里同时带有posedge和negedge 如:(现在也碰不到
1 always @(posedge clk or negedge clk)
2 begin
3 ...
4 end
03 面积和速度的转换
这里我们说的面积:设计所占用的FPGA逻辑资源数目,一般用所消耗的触发器和查找表(还没学)来衡量。
速度:是指在芯片上可以稳定运行时能达到的最高频率
两者性能上的调配方法:
模块复用
串并变换

可以看到这种串并转换,用更大的面积(即多个子模块并行),达到高频率的效果。这一点后面还会再提到。
流水线
04 同步电路的设计原则
同步设计的优点:
可以有效避免毛刺的影响,提高设计的可靠性
可以简化时序分析过程
可以减少工作环境对设计的影响
设计原则:
(由于应用还不多,对这些体会还不深刻,简单记录:
单时钟
全局时钟网络的时钟是性能最优,最便于预测的时钟,具有最强的驱动能力
单时钟沿
混合时钟会使时序分析复杂、电路工作频率降低
避免使用门控时钟
即时钟不要与组合逻辑再进行组合,如下:

可能引起毛刺、偏移
在模块内部不要再产生时钟了。
05 模块划分的设计原则
封装复用
这有点像C++的封装。
上一层模块只负责下一层模块的依据(即原材料),而具体行为互不相关。
这样就保证了各个模块的相对独立性和内部结构的合理性,便于维护,也使得相同逻辑可以复用同一模块。
同步时序模块的寄存器划分原则
在设计时,应尽量将模块中的同步时序逻辑输出信号以寄存器的形式送出,以便于综合工具区分时序和组合逻辑;
并且时序输出的寄存器应符合流水线设计思路,能工作在更高的频率,以极大地提高模块吞吐量。
流水线设计思路是什么?
就是将组合逻辑系统地分割,并在各个部分(分级)之间插入寄存器,并暂存中间数据的方法。 目的是将一个大操作分解成若干的小操作,每一步小操作的时间较小,所以能提高频率,各小操作能并行执行,所以能提高数据吞吐率(提高处理速度)。
06 通用代码风格
逻辑复用与逻辑复制
对于我这个初学者来说,逻辑复用和逻辑复制十分相似,了解后就知道确实不同,主要是涉及性能衡量尺度:速度和面积的统筹。
逻辑复用是通过提高工作频率来节省面积的优化方法,经常用于存在多个资源可共享单元的设计中。
PS:相当于为了节省人力,而让一个人干三个人的活。

10MHZ乘法器

两个5MHZ乘法器
逻辑复制——面积换速度
逻辑复用是通过增加面积而改善设计时序的优化方法,经常用于调整信号的扇出。
举例就类似于上面的面积换速度

逻辑结构
链状结构
树状结构
if和case语句的使用原则
If语句指定了一个有优先级的编码逻辑,
而case语句生成的逻辑是并行的,不具有优先级。
这里的if的优先级就引起一些其他问题:
1 always@(in0,in1,in2,in3)
2 begin
3 sel = 2’b00 ;
4 if(in0) sel = 2’b00 ;
5 else if(in1) sel = 2’b01 ;
6 else if(in2) sel = 2’b10 ;
7 else if(in3) sel = 2’b11 ;
8 end
9 //当这里in0和in1都==1时,se1=2'b00而不是2'b01;
10 //这就是if-else的优先逻辑。而case是并行的,没有优先级。
if语句可以包含一系列的表达式;/有时甚至一个else就可以是一个二路选择器。
而case语句比较的是一个公共的控制表达式。整个语句块一起构成了一个多路选择器。
这个很好理解。
通常if-else结构速度较慢,但占用的面积小;
case语句结构速度较快,但占用的面积较大。
嵌套的if语句如果使用不当,就会导致设计的更长延时。
如果想利用if语句来实现那些对延时要求苛刻的路径,应将最高优先级给最迟到达的关键信号。(最小生成树思想)。
有时为了兼顾面积和速度,可以将if和case语句合用。
举例
1 //if-else实现四选一
2 module sdata_if (clk, reset, x, s, y);
3 input clk;
4 input reset;
5 input [3:0] x;
6 input [1:0] s;
7 output y;
8
9 reg y;
10 always@(posedge clk)begin
11 if(!reset)begin
12 y<=0;
13 end
14 else begin
15 if(s==2'b00)
16 y<=x[0];
17 else if (s==2'b01)
18 y<=x[1];
19 else if (s==2'b10)
20 y<=x[2];
21 else
22 y<=x[3];
23 end
24 end
25 endmodule
想象一下是什么电路?
就是一个四选一,需要两位的控制信号,这个控制信号就正好是s。

1 //case语句
2 module sdata_if (clk, reset, x, s, y);
3 input clk;
4 input reset;
5 input [3:0] x;
6 input [1:0] s;
7 output y;
8
9 reg y;
10 always@(posedge clk)begin
11 if(!reset)begin
12 y<=0;
13 end
14 else begin
15 case(s)
16 2'b00: y<=x[0];
17 2'b01: y<=x[1];
18 2'b10: y<=x[2];
19 2'b11: y<=x[3];
20 end
21 end
22 endmodule
23
24
实现电路也是类似上面的电路。

避免意外锁存器
锁存器在课本里学过,是用于存储一位数据的元件,电平触发。
其特点是:锁存器在不锁存数据时,输出随输入变化;但一旦数据锁存时,输入对输出不产生任何影响。
而我们在设计电路时,应该避免无意之间产生这种锁存器,否则会导致一些逻辑上的错误。
引起意外锁存器的原因
翻阅了很多网上的总结。有一些规则比较复杂,考虑到我现在的水平,我只记录对初入门水平够用且好理解的方面。后续继续学习可以深入了解更多。
if……else……结构中缺少else
case结构中的分支没有包含所有情况且没有default语句。
建议
如果使用if语句,最好写上else分支;
如果使用case语句,最好写上default语句。
即使需要锁存器,也通过else分支或default分支来显式说明。而不要利用语言特性触发生成(因为不可控)
内容真的好多,一时间难以完全消化...
上传于2021年11月25日23时
数字逻辑实践4->面向硬件电路的设计思维--FPGA设计总述的更多相关文章
- 数字逻辑实践6-> 从数字逻辑到计算机组成 | 逻辑元件总结与注意事项
00 一些前言 数字逻辑是计算机组成与体系结构的前导课,但是在两者的衔接之间并没有那么流畅,比如对面向硬件电路的设计思路缺乏.这篇总结是在数字逻辑和计组体系结构的衔接阶段进行的. 虽然这篇文是两门课的 ...
- 数字逻辑实践2->Verilog编写规范
来源:数字逻辑与Verilog设计实验课讲解,个人做的笔记与整理. 00 规范的重要性 良好的编程风格有利于减少消耗的硬件资源,提高设计的工作频率 . 提高系统的可移植性和可维护性. 程序的格式化能体 ...
- 数字逻辑实践3->EDA技术与Verilog设计
本文属于EDA技术概述类文章 1 EDA技术及其发展 概念 EDA(Electronic Design Automation),指的是以计算机为工作平台,以EDA软件工具为开发环境,以PLD期间或者A ...
- 数字逻辑实践5->Verilog语法 | wire 与 reg 的选择与特性
问题起因:最初学习数字逻辑设计理论的时候还没有注意到,在实验课上写代码的时候发现了一个问题: 对于源码模块的变量定义,何时定义为reg.何时定义为wire?它们各自又有什么特性和物理意义? 1. wi ...
- FPGA学习笔记(三)—— 数字逻辑设计基础(抽象的艺术)
FPGA设计的是数字逻辑,在开始用HDL设计之前,需要先了解一下基本的数字逻辑设计-- 一门抽象的艺术. 现实世界是一个模拟的世界,有很多模拟量,比如温度,声音······都是模拟信号,通过对模拟信号 ...
- 转载--关于FPGA设计数字信号处理电路的心得
FPGA使用的越来越广泛,除了可用于设计控制电路以为,数字信号处理电路更是FPGA的强项和难点.个人可以说才刚刚入门FPGA设计,也做过一些数字信号处理方面的电路设计,记录下个人心得体会. (一)善用 ...
- 小梅哥FPGA数字逻辑设计教程——基于线性序列机的TLC5620型DAC驱动设计
基于线性序列机的TLC5620型DAC驱动设计 目录 TLC5620型DAC芯片概述: 2 TLC5620型DAC芯片引脚说明: 2 TLC5620型DAC芯片详细介绍: 3 TLC ...
- uTenux\AT91SAM3S4C开发套件———硬件电路介绍
无论写什么嵌入式软件,我们都应该首先对硬件有所了解,这样更有助于我们写出高效精简的程序代码.本次活动我们使用的硬件平台是有悠龙公司提供的uTenux\AT91SAM3S4C开发套件,在悠龙公司的主页可 ...
- 数字逻辑与EDA设计
目录 第一章 数字逻辑基础 1.1数制与码制★★★ 数制 码制 1.2基本及常用的逻辑运算★★ 1.2逻辑函数表示方法★★ 1.3逻辑函数的化简★★★ 1.4常用74HC系列门电路芯片★ 第二章 组合 ...
随机推荐
- 工作日常-SQL不能乱写
前言:刚接手别人的项目没多久,在昨天的一次上线中无故躺坑,且该大兄弟已经离职,不得不帮他填坑,整完后,今天想搞一个总结,结论就是:SQL不能乱写. 搜索关键词:Cause: java.sql.SQLE ...
- iOS自定义拍照框拍照&裁剪(一)
卡片机时代 很重要的一点是,相机本身是没有方向概念的,它不理解拍摄的内容,只会以相机自己的坐标系去保存数据,下图展示了相机对"F"进行四个角度拍摄时返回的图片数据. 最初的卡片机时 ...
- Mybatis 二级缓存应用 (21)
[MyBatis 二级缓存] 概述:一级缓存作用域为同一个SqlSession对象,而二级缓存用来解决一级缓存不能夸会话共享,作用范围是namespace级,可以被多个SqlSession共享(只要是 ...
- 如何快速体验鸿蒙全新声明式UI框架ArkUI?
HDC2021将于10月22日在东莞松山湖正式开幕,大会将设立Codelab体验专区,超多好玩.有趣的Demo等你体验.想快速入门HarmonyOS?学习HarmonyOS新特性?以下几个Codela ...
- Vue3学习(七)之 列表界面数据展示
一.前言 昨晚可能是因为更新完文章后,导致过于兴奋睡不着(写代码确实太容易让人兴奋了),结果两点多才睡着,大东北果然还是太冷了. 不知道是不是因为膝盖和脚都是冰凉的,所以才导致很晚才能入睡? 刚眯了一 ...
- Less-32 宽字节
<!-- 下午整了半天Less-29~31,愣是没调好jsp环境,只好跳过. 难受.jpg !--> Less-32: 核心语句: 各种回显均存在. 第一句话指定了字符集为gbk. che ...
- mybatis学习笔记(1)基本环境
1.pom引入 <dependencies> <dependency> <groupId>org.mybatis</groupId> <artif ...
- 【Linux命令063】Linux非常简单常用的入门命令
Linux常用命令 这是一篇我在公众号上发布的文章,还算较为受欢迎. 博客园这边荒废好长时间了,主要是最近一年经常撰写的文章都是Linux相关的入门文章. 不知道是否能通过博客园的首页审核. 1.cd ...
- 基于docker-compose搭建sonarqube代码质量检测平台
一.需求 在我们开发的过程中,难免有时候代码写的不规范,或存在一些静态的bug问题,这个时候一个良好的代码检查工具就很有必要,而sonarqube正好可以满足整个要求. 二. docker-compo ...
- 镜头Lens Image circle像圈的解释是什么意思
Image circle镜头中指的是:像圈 像圈(image circle)是指入射光线通过镜头后,在焦平面上呈现出的圆形的明亮清晰的影像幅面,也称像面大小.镜头像圈由镜头光学结构决定,一旦设计完成, ...