当前课程知识点:IC设计与方法 > 3、Verilog语法 > f)Always > 3-1-6 Always
刚才我们讲了连续赋值语句
用Verilog语言
进行组合逻辑电路设计的第一种手段
下面我们再来看第二种手段
过程语句
过程是用硬件描述语言来实现电路的
或者说实现组合逻辑电路的第二种手段
连续赋值语句
通常只用来实现比较简单的布尔逻辑
或者比较简单的组合逻辑电路
如果这个组合逻辑电路的功能
相对来说比较复杂
或者说不太容易用一句话
把它表述清楚的时候
这时候我们会用过程语句来实现
在过程里面通常我们会用到4种类型的操作
一种是赋值语句
分为阻塞赋值和非阻塞赋值
第二个
用if和case语句来完成一些多分支的执行情况
下面我们来详细的看一下过程
过程通常体现形式有两种
我们看一下幻灯片的右上角
和右下角的这两种形式
第一种形式
首先看过程的结构
它的关键字是always@
后面是过程所执行的条件
有点像C语言输入的变量
然后是begin跟end之间包含了一些语句块
这些语句块可以是
赋值语句、if语句、case语句等等
或者是if和case的嵌套
下面这段是过程语句的第二种形式
和上一种形式不同的是
上一种形式(过程的敏感表)是a或b或c
这些a、b、c是过程的输入信号
一个过程相当于一个小的电路模块
在这里边a、b、c是这个电路模块的输入信号
下面这种形式多了一个关键字是posedge
或者是negedge
表示在信号的上升沿或者是下降沿
这个过程才会执行
对比这两个(过程)我们可以看到
在上面这个条件
在下面这段代码里表示这些信号
任何一个信号的变化
这个过程都会执行
(这代表)什么物理意义呢
一个电路只要输入信号有变化
这个电路就需要去执行一遍
或者说电路的输出就要去改变
那这是什么电路呢
这就是组合逻辑电路
所以就是说 上面这种结构
这种方式是用来去描述一个组合逻辑电路
这里面的信号是这一小部分
这一小块组合逻辑电路的输入信号
那么下面这种形式是什么形式呢
大家再想一下
当某个信号的边沿发生变化的时候
内部才会去执行
其他时刻这个电路内部不去执行(没有任何动作)
回想一下我们在第一讲的时候讲的
一些基本设计方法
大家可以想到
是不是很像D触发器
D触发器只有在时钟沿变化的时候
D触发器的输出才有可能发生变化
其他的信号
例如输入的数据信号
或者说一些条件信号发生变化的时候
D触发器的输出并不会变化
只有当时钟沿到来的时候
输出才会变化
所以这种形式通常用来描述
基于D触发器的或者说类似D触发器
这样的时序逻辑电路
上面这种形式用来表示组合逻辑电路
在过程内部
我们常见的只有这4种方式
阻塞赋值、非阻塞赋值
(if)条件语句和case语句
通常我们设计组合逻辑电路的时候
建议大家或者说只允许大家使用阻塞赋值语句
当然不排除我们在看一些别人写的代码里
会有非阻塞赋值语句
我们后面再去讲具体是怎么回事
我们首先来看一下if语句
在这里面
我们不会对相关的语法去讲的特别细
我们只是结合具体的例子来看
因为在Verilog语言里所定义的语法知识
大多数情况下都跟C语言类似
我相信绝大多数同学
已经能够非常熟练地使用C语言了
所以我们对照着去看就可以了
if语句通常有两种形式
一个是双分支的if-else方式
第二种是多分支的if-else if-else
这种三分支的或者说更多分支的形式
我们来看一下实际的一个例子
比如说if
如果a大于b
输出结果res信号的值赋于1
否则 如果是a小于c
res是2 out是4
其他情况的时候res是3
这里面其实就是一个多分支的if语句
在这里面
我们可以注意一下
如果一个分支里边超过一条赋值语句
需要用begin和end把赋值语句包括在一起
这就是if语句的语法规则
在实际电路里面
我们可以把if语句再去嵌套if
我们在电路的内部
不一定只有赋值语句
可以把if语句和if去进行嵌套
或者说把if跟其他的
例如case语句进行嵌套
来完成比较复杂的电路
第二种比较常见的语句是case语句
刚才说了if语句比较适合设计二分支
或者说多分支的执行情况
case语句可以实现并行的多分支的情况
在if语句里面
分支的判断是根据判断条件
它的判断条件可以相对比较复杂
来实现多分支
case语句各个分支的条件是相同的
我们来看一下case的实例
我们不再结合着语法来看了
在这个例子里边
这是always语句块
在语句块里
有一个case语句
它的格式是从case到endcase
中间是一个case分支
在这个分支里
case语句块里面
判断的是信号op
根据信号op的值来决定到底执行哪一个分支
或者说根据信号op的值来决定
到底把哪些信号赋给out
为了让代码具备更强的可读性
我们这里面定义了几个助记符
用define来定义的
我们把2'b00、2'b01和2'b10分别定义给这三个操作符
也就是说
当op的值等于LOAD的时候
我们把输入的数据din送给out
如果操作是一个SUB减法操作的时候
我们把a减b送给out
我们也可以在写成
当加法操作的时候执行a加b操作
在做电路设计的时候有一条规则
通常这个规则的意思
是要求在写case语句的时候
通常最后一条语句必须是default语句
表示当op的值不是前面的这些情况的时候
其他情况
我们执行最后一条分支
也就是说
当op的值不是LOAD
不是SUB的时候
把a加b的值送给out
对照着刚才的if语句
case语句相当于
是一个具有多分支的多路选择器
说到多路选择器
我们来看一下
我们实际上在设计物理上的
多路选择器的时候都有哪些手段
第一种特别简单的多路选择器
我们看一下左边这段代码
这是我们前面在讲assign语句的时候
讲过assign语句有一种特别简单的形式
这种形式可以实现一个2选1的多路选择器
相当于是什么呢
相当于是一个条件判断语句
这是用always语句
大家从这个always开始看
一直到end的地方
这是一个always语句块
我们说了always语句用来实现一个
比较简单的组合逻辑电路
这块组合逻辑电路的信号是什么
它的输入信号是什么
是a、b和sel信号
内部的功能是什么
内部功能是根据sel的值来判断
当sel等于0的时候
把a送给out
else也就是sel是1的时候
把b给送out
所以这块语句块的功能
跟assign语句的功能是完全一样的
根据这个大家又可以得到一个结论
前面我们说过
assign语句是用来实现
组合逻辑电路的第一个手段
assign语句可以用来实现
比较简单的组合逻辑电路
always语句是用来实现
组合逻辑电路的第二个手段
可以用来实现比较复杂的组合逻辑电路
在这里我们说
它们之间是一一对应的
其实也就是说
assign语句是always的一个特例
它看起来(以及)写起来会比较简洁一点
在有些工程项目里面
大家会要求代码书写是完全同一个风格
这就是在某些工程项目里面的推荐写法
当然
如果电路特别简单
用这种方式可能代码看起来更简洁一点
刚才是一个2选1的多路选择器
我们再来看一下稍微复杂一点的
更多的多路选择器
假设我们设计的是一个多路选择器
它一共有4个输入端
然后根据选择端产生一个输出信号
所以
输入信号我们看输入有一个EN信号
有输入的4个信号
这4个信号都是8位的信号
要从4个信号里面选择一路输出
所以这个SEL信号
就不是1位的信号了
SEL信号是一个2位信号
输出信号是一个8位的信号
这个8位信号到底应该是wire类型
还是reg类型呢
要看这个信号到底是由谁来产生的
在我们这段代码里面
这个out信号是由一个always块来产生的
所以在前面定义的时候
就要把它定义成是reg类型
所以大家可以看
我们设计的是一个组合逻辑电路
组合逻辑电路的输出
根据需要
根据代码书写风格的需要
纯粹是因为根据它的风格需要
需要把它定义成是reg类型
这就是我们前面说的reg类型
跟register没有任何关系
纯粹是由于这种代码书写的风格
导致我们的out信号必须定义成是reg类型
下面我们再来看一下这个电路的功能
这个多路选择器的核心部分是一个case语句
根据SEL信号到底00/ 01/ 10
还是11来决定把输入的四个信号之一送给out
这里面还加了一个default
如果SEL信号是2位信号
只可能出现这4种情况
根本就不可能出现default这个情况了
实际上 我们在写代码的时候
从RTL级代码要求
要求大家必须写default分支
所以这段代码
实际工程里面会有两种书写风格
一种是我们幻灯片上所看到的这种方式
另一种方式就把第三种情况
直接用default替换掉
这样代码看起来会更规整一点
这是在EN信号有效的时候
电路输出是把输入的四者之一送给输出
这个多路选择器定义的比较复杂
当EN信号无效的时候
直接就把8位的全0送给输出了
大家可以关注一下这个8位的全0是怎么描述的
描述了8个1比特的0合成一个矢量
用这样的方式表述
当然大家也可以写成8个0
二进制的8个0
那这也是一种方式
用这种方式
我们电路的可改性
或者可读性就比较强了
将来大家如果想把位宽从8位变成16位的时候
只要在这里直接改了
就可以实现更多位宽的多路选择器了
再来看第三个例子
3-8译码器
3-8译码器的功能
我想大家都应该非常清楚
在大学本科的数字电路里面都应该讲过
根据输入的3位信号产生8个输出
从8根输出线中的某一位
输出一个有效电平
我们看这是一个译码器
输入的是一个3位的数据信号in
输出的是8位信号
由于我们的8位信号out是由always块产生的
所以我们需要把它定义成是reg类型
always块的@后面写的是输入信号
里面我们用了一个case语句产生8位输出(信号)
我们可以看一下
当输入的信号是3位的000的时候
它对应的是十进制的0
输出的是什么呢
是一个8位的高位全1
最低位是0
如果输入的是1的时候
第二位是零
也就是说
根据输入的8种不同情况
输出是在相应的有效位
输出一个低电平输出的3-8译码器
这也是一种典型的组合逻辑电路
那么我们可以做一个小结
怎么设计组合逻辑电路
怎么用条件判断语句if语句
以及case语句设计组合逻辑电路
大家看一下这些always块
一个是always后面的@
一定是信号原始的(输入数据)
把这个组合电路的所有输入信号
都要放在always块的(敏感表)里
这样才表示的是一个组合逻辑电路
第二个
如果我们用case语句或者if语句的时候
因为我们设计的是组合逻辑电路
所以我们需要把case语句的所有分支
或者if语句的所有分支全部要列出来
不能有漏的分支
一旦有漏的分支
这个电路就会产生其他的效果
全部列出来以后
要对输出信号赋值
在每一个分支里面
都要对这个输出信号赋值
什么意思呢
总结一下就是说
在case语句或者if语句里边的每一个分支
都要为输出信号产生一个确定的固定的值
否则
如果比如说我们中间有一行没有写
Verilog语言定义了
当这行没有写(的时候),表示这个语句保持原来的值不变
比如说这一行
3’d1这一行没有写
表示在这种情况out值要保持刚才的值不变
这样
这个电路就具备保持功能了
具备保持功能了就不是一个组合逻辑电路了
所以我们说在用always语句块
来实现组合逻辑电路(的时候)
内部可以是if case
以及if case的各种复杂的嵌套结构
我们作为设计人员
一定要保证每一个分支都会被写到
并且不能有漏写的地方
并且在每个分支里面
都要对输出信号或者
涉及到有多位输出信号的时候
它对所有的输入信号都产生固定的输出
后面我们有机会
还会给出具体的一些例子
-软件下载说明
-a) 集成电路的应用及市场
-a) 集成电路的应用及市场--作业
-b)集成电路的制造过程
-b)集成电路的制造过程--作业
-c)从CPU的发展看IC的进展
-c)从CPU的发展看IC的进展--作业
-d)从行业的发展看IC的进展
--Video
-d)从行业的发展看IC的进展--作业
-e)从ISSCC看IC的发展方向
--讲课视频
-e)从ISSCC看IC的发展方向--作业
-a)数字系统的实现方法 (ASSP/FPGA/ASIC的对比)
--讲课视频
-a)数字系统的实现方法 (ASSP/FPGA/ASIC的对比)
-b)组合逻辑电路
--Video
-2、数字集成电路设计方法--b)组合逻辑电路
-c)时序逻辑电路(1)
-d)时序逻辑电路(2)
-2、数字集成电路设计方法--d)时序逻辑电路(2)
-a)Verilog的历史和学习要点
--讲课视频
-b)端口、信号及数据类型
--讲课视频
-b)端口、信号及数据类型--作业
-c)逻辑电平及数据操作
--讲课视频
-3、Verilog语法--c)逻辑电平及数据操作
-d)Assign 语句
-e)Assign 举例
-f)Always
-f)Always--作业
-g)阻塞与非阻塞赋值
--Video
-3、Verilog语法--g)阻塞与非阻塞赋值
-h)D触发器的描述
--Video
-i)时序电路的设计
--Video
-i)时序电路的设计--作业
-j) 面向测试的Verilog语法(1)
-k) 面向测试的Verilog语法(2)
-k) 面向测试的Verilog语法(2)--作业
-a)电路设计实例1
--Video
-b)电路设计实例2
--讲课视频
-b)电路设计实例2--作业
-c)电路设计实例3
--讲课视频
-Modelsim仿真
-a)综合及相关基本概念
--Video
-a)综合及相关基本概念--作业
-b)综合及优化
--Video
-c)门级仿真
--门级仿真
-d)Quartus综合及分析(1)
--讲课视频
-e)Quartus综合及分析(2)
--讲课视频
-e)Quartus综合及分析(2)--作业
-f)Quartus综合及分析(3)
--Video
-g)Quartus综合及分析(4)
--Video
-g)Quartus综合及分析(4)--作业