文章目录
- 主体内容
- 1 模块的结构与调用
- 2 语句
- 2.1 结构语句
- 2.1.1 initial语句
- 2.1.2 always语句
- 2.2 赋值语句
- 2.2.1 阻塞赋值(=)
- 2.2.2 非阻塞赋值(<=)
- 2.3 条件语句
- 2.3.1 if 语句
- 2.3.2 case 语句
- 3 状态机
- 3.1 状态空间定义
- 3.2 状态跳转
- 3.3 下个状态判断
- 3.4 各个状态下的动作
- 3.5 状态机实例
- 参考资料
主体内容
1 模块的结构与调用
Verilog 的基本设计单元是“模块”(block)。
一个模块是由两部分组成的,一部分描述接口,另一部分描述逻辑功能。
//描述接口部分
module block(a,b,c,d); //(a,b,c,d)是端口定义input a,b; //IO说明output c,d;//描述逻辑功能
assign c = a | b;
assign d = a & b;endmodule
每个Verilog程序包括4个主要的部分:端口定义、IO说明、内部信号声明、功能定义。但其实端口定义和IO说明可以放到一起写,如下:
module flow_led(input sys_clk,input sys_rst_n,output reg [3:0] led);...endmoudle
注意!在Verilog中,当你定义一个模块的输入输出端口时,如果不显式地指定数据类型,那么这些端口默认的数据类型是wire
;output 信号可以是 wire 类型,也可以是 reg 类型(条件是在 always 或 initial 语句中被赋值);inout 一般为 tri(三态线)类型,表示有多个驱动源。
功能定义部分有三种方法:
1,assign语句 描述组合逻辑
2,always语句 描述组合/时序逻辑
3,例化实例元件 如:and #2 u1(q,a,b)
,这里的and是一个与门(verilog的关键字之一)
上述三种逻辑功能是并行的。注意!!!在always块中,逻辑是顺序执行的,而在多个always块之间是并行的。
在模块进行调用时,注意,输入可以是reg类型或者wire类型,但输出则必须是wire类型(因为其表示结构实体(例如门)之间的物理连线)
特别注意!如果例化的模块有参数的话,参数的例化要在"u_"之前。
2 语句
2.1 结构语句
2.1.1 initial语句
initial 语句它在模块中只执行一次。
它常用于测试文件的编写,用来产生仿真测试信号(激励信号),或者用于对存储器变量赋初值。
2.1.2 always语句
always语句一直在不断地重复运行,但是只有和一定的时间控制结合在一起才有作用。
always 的时间控制可以是沿触发,也可以是电平触发。可以是单个信号,也可以是多个信号,多个信号中间要用关键字 or 连接。(由关键词 or 连接的多个事件名或信号名组成的列表称为“敏感列表”。)always 语句后紧跟的过程块是否运行,要看它的触发条件是否满足。
沿触发的 always 块常常描述时序逻辑行为。
!穿插组合逻辑与时序逻辑的差别:
组合逻辑电路中,任意时刻的输出仅仅取决于该时刻的输入,与电路原来的状态无关。
时序逻辑电路中,任一时刻的输出不仅取决于当时的输入信号,而且还取决于电路原来的状态。或者说还与以前的输入有关,因此时序逻辑必须具备记忆功能。
2.2 赋值语句
Verilog HDL 语言中,信号有两种赋值方式,分别位阻塞赋值(blocking)和非阻塞赋值(Non blocking)。
2.2.1 阻塞赋值(=)
阻塞赋值可以认为只有一个步骤的操作,即计算 RHS 并更新 LHS 。所谓阻塞的概念是指,在同一个always块中,后面的赋值语句是在前一句赋值语句结束后才开始赋值的。
2.2.2 非阻塞赋值(<=)
非阻塞赋值的操作过程可以看作两个步骤: (1) 赋值开始的时候,计算 RHS ;(2) 赋值结束的时候,更新 LHS 。所谓非阻塞的概念是指,在计算非阻塞赋值的RHS以及更新LHS期间,允许其他的非阻塞赋值语句同时计算RHS和更新LHS。非阻塞赋值只能用于对寄存器类型的变量进行赋值,因此只能用在initial块和always块等过程块中。
2.3 条件语句
2.3.1 if 语句
if 语句的三种形式:
注意!条件语句必须在过程块中使用,过程块语句是指initial和always语句引导的块语句。
if 语句对表达式的值进行判断,若为0, x, z,则按假处理;若为1,按真处理。
if和else后面的操作语句可以用begin和end包含多个语句。
2.3.2 case 语句
case 语句又叫多分支选择语句。分支表达式的值互不相同,且所有表达式的位宽必须相等。由于verilog不同于C语言,逻辑值存在x和z,故判断要复杂很多,case语句的真值表如下图所示:
注意casez为比较时不考虑表达式中的高阻值,而casex为不考虑高阻值和不定值x。它们的真值表如下图所示:
3 状态机
有限状态机(Finite State Machine,简称FSM)对应在有限个状态之间按一定规律转换的时序电路。
两种状态机示意图如下图所示:
两者唯一的区别是对于Mealy状态机而言,状态机的输出既与当前状态有关,也与输入有关;而Moore状态机的输出只与当前状态有关。所以,Moore状态机只是Mealy状态机的一个特例。
状态机设计的四段论:1,状态空间定义;2,状态跳转;3,下个状态判断;4,各个状态下的动作。
3.1 状态空间定义
这里需要注意下面定义的状态寄存器需要与上面定义的参数位宽保持一致。
3.2 状态跳转
示例:
always @(posedge clk or negedge rst_n) beginif(!rst_n)current_state <= SLEEP;elsecurrent_state <= next_state;
end
3.3 下个状态判断
其中latch值的是锁存器,在数字电路里面,latch是一个电平触发的存储器,而触发器是一个边沿触发的存储器,在verilog代码编写中,一定要避免产生无谓的锁存器,锁存器只在组合逻辑里产生,它会造成我们生成的电路毛刺比较多。其它可能产生锁存器的情况:case表达式没有完全,如3位状态寄存器,但我们只有4个状态,也就是说有的状态没有用到,那就需要给个default
,否则也会生成锁存器。
3.4 各个状态下的动作
注意,下面的always语句由于是组合逻辑,所以也需要使用阻塞赋值。
3.5 状态机实例
按照上面流程写出的状态机叫做三段式状态机,一个三段式状态机的实例如下:
而事实上,三段式状态机可以在组合逻辑后再增加一级寄存器来实现时序逻辑输出,这样做有以下三个优点:
1,可以有效地滤去组合逻辑输出的毛刺;
2,可以有效地进行时序计算与约束;
3,另外对于总线形式的输出信号来说,容易使总线数据对齐,从而减小总线数据间的偏移,减小接收端数据采样出错的频率。
参考资料
1,正点原子领航者ZYNQ7020视频
2,《verilog HDL数字集成电路设计原理与应用(第二版)》 蔡觉平等
3,文心一言搜索结果