本章目录:
- 1. 组合逻辑
- 1.1 方式一:always @(电平敏感信号列表)
- 1.2 方式二:assign 描述的赋值语句。
- 1.3 常见的组合逻辑电路模块
- 1.3.1 编码器
- 1.3.2 译码器
- 1.3.3 数据选择器
- 1.3.4 加法器
- 1.3.5 数值比较器
- 2. 时序逻辑
- 2.1 常见的时序逻辑电路模块
- 2.1.1 移位寄存器
- 2.1.2 计数器
- 2.1.3 序列信号发生器
- 3. 二者的不同点
- 4. 补充知识
- 4.1 阻塞/非阻塞(附有例题)
- 4.1.1 阻塞赋值
- 4.1.2 非阻塞赋值
- 4.1.3 区别
- 4.1.4 例题
- 4.2 Verilog 模块编程的 8 个原则
1. 组合逻辑
组合逻辑的特点是任意时刻的输出仅仅取决于该时刻的输入,与电路原本的状态无关,逻辑中不牵涉跳变沿信号的处理,组合逻辑的 verilog 描述方式有两种:
1.1 方式一:always @(电平敏感信号列表)
always 模块的敏感列表为所有判断条件信号和输入信号,但一定要注意敏感列表的完整性。在 always 模块中可以使用 if、case 和 for 等各种 RTL 关键字结构。由于赋值语句有阻塞赋值和非阻塞赋值两类,建议读者使用阻塞赋值语句“=”。always 模块中的信号必须定义为 reg 型,不过最终的实现结果中并没有寄存器。这是由于在组合逻辑电路描述中,将信号定义为reg 型,只是为了满足语法要求。
1.2 方式二:assign 描述的赋值语句。
信号只能被定义为 wire 型。
1.3 常见的组合逻辑电路模块
编码器、译码器、数据选择器、加法器、数值比较器。
1.3.1 编码器
编码器又分为普通编码器和优先编码器,二者区别如下:
- 输入信号不同
普通编码器一次只能输入一个信号,优先编码器可以同时输入几个信号。
- 输入信号优先级不同
在普通编码器中,任何时刻只允许输入一个编码信号,否则输出将发生混乱;优先编码器在设计时已经将各输入信号的优先顺序排好,当几个信号同时输入时,优先权最高的信号优先编码。优先级低的信号则不起作用。
- 处理能力不同
优先编码器相比普通编码器电路有更强的处理能力,因为其能处理所有的输入组合情况。
1.3.2 译码器
它的作用就是和编码器相反,一共有三种:
- 二进制译码器
- 二-十进制译码器
- 显示译码器
1.3.3 数据选择器
一般称为数据选择器(data selector)或者多路开关(multiplexer,MUX)
1.3.4 加法器
关于加法器也是重中之重,我之前已经写过相关的文章了
1.3.5 数值比较器
就是比较数值的,因为我们都是二进制数,要么为0要么为1,所以可以组合来判断大小。
2. 时序逻辑
时序逻辑是 Verilog HDL 设计中另一类重要应用,其特点为任意时刻的输出不仅取决于该时刻的输入,而且还和电路原来的状态有关。电路里面有存储元件(各类触发器,在 FPGA 芯片结构中只有 D 触发器)用于记忆信息,从电路行为上讲,不管输入如何变化,仅当时钟的沿(上升沿或下降沿)到达时,才有可能使输出发生变化。
2.1 常见的时序逻辑电路模块
移位寄存器、计数器、序列信号发生器
2.1.1 移位寄存器
2.1.2 计数器
之前写了很多关于计数器的题目以及应用,给出如下:
计数器相关题目
结合仿真软件的应用
2.1.3 序列信号发生器
序列信号发生器应用也十分广泛,同样给出传送门,如果不理解可以留言或私信解答问题:
序列检测
3. 二者的不同点
(1)在描述时序电路的 always 块中的 reg 型信号都会被综合成寄存器,这是和组合逻辑电路所不同的。
(2)时序逻辑中推荐使用非阻塞赋值“<=”。
(3)时序逻辑的敏感信号列表只需要加入所用的时钟触发沿即可,其余所有的输入和条件判断信号都不用加入,这是因为时序逻辑是通过时钟信号的跳变沿来控制的。
4. 补充知识
4.1 阻塞/非阻塞(附有例题)
4.1.1 阻塞赋值
阻塞赋值使用的赋值运算符为“=”。阻塞赋值的过程是立刻执行的,即阻塞赋值运算符右侧表达式求值完后立刻会更新至运算符左侧,并且这个执行的过程不受其他语句执行的影响,其后的语句只有当前的赋值操作执行完成后才能顺序执行。
4.1.2 非阻塞赋值
非阻塞赋值使用的赋值运算符为“<=”。非阻塞赋值执行过程为:在当前仿真时间槽(timeslot)开始分析计算获得右侧表达式的值,在当前时间槽执行结束时更新左侧表达式的值,在右侧表达式分析计算和左侧表达式被更新之间,任何其他事件都可以执行,同时也有可能修改已经计算完成的右侧表达式的值,即非阻塞赋值的过程不影响其他语句的执行.
4.1.3 区别
根据非阻塞赋值的特点,其赋值运算符左侧操作数只能为寄存器类型,因此非阻塞赋值只能用于过程性语句中(initial 和 always),不允许在连续赋值语句中使用非阻塞赋值。
所谓阻塞的概念是指在同一个 always 块中,其后面的赋值语句从概念上是在前一条赋值语句结束后开始赋值的。
4.1.4 例题
下面两段代码中 in、q1、q2 和 q3 的初值分别为 0、1、2、3,那么经历 1 个时钟周期后,上边代码 q3 的值和下边代码 q3 的值分别变成了()
always @(posedge clk) begin
q1 = in;
q2 = q1;
q3 = q2;
end
always @(posedge clk) begin
q1 <= in;
q2 <= q1;
q3 <= q2;
end
【A】0,0 【B】0,3 【C】2,0 【D】0,2
解析:“=”是阻塞赋值,当 clk 的上升沿到来时,in 的值赋给 q1,然后 q1 的值赋给 q2,然后 q2 的值赋给 q3。最终结果 q3 等于 in 的值,为 0。“<=”是非阻塞赋值,当 clk 的上升沿到来时,in 的值赋给 q1,同时 q1 的值赋给 q2,同时 q2 的值赋给 q3。最终结果 q3 等于 q2的值,为 2。
正确答案:D
4.2 Verilog 模块编程的 8 个原则
(1) 时序电路建模时,用非阻塞赋值。
(2) 锁存器电路建模时,用非阻塞赋值。
(3) 用 always 块建立组合逻辑模型时,用阻塞赋值。
(4) 在同一个 always 块中建立时序和组合逻辑电路时,用非阻塞赋值。
(5) 在同一个 always 块中不要既用非阻塞赋值又用阻塞赋值。
(6) 不要在一个以上的 always 块中为同一个变量赋值。
(7) 用$strobe 系统任务来显示用非阻塞赋值的变量值。
(8) 在赋值时不要使用#0 延时。