首先说明,下面的内容为阅读FPGA之道这本书的摘要,由需要的可以评论。
1.组合逻辑电路和时序逻辑电路
数字电路根据逻辑功能的不同分为两大类:组合逻辑电路和时序逻辑电路
1.组合逻辑电路:数字电路任意时刻的输出仅仅取决于该时刻的输入
2.时序逻辑电路:数字电路的输出不仅取决于当前时刻的输入还取决于数字电路原来的状态
组合电路好理解,就是只要输入变换,那么相应的输出也会变换,但是时序逻辑电路如下如所示,相同的输入输出不同,输出同时还取决于原来的状态,就是时序电路。
可以看出,两种类型并不是完全的割裂开来,更像一种包含的关系,即时序电路中肯定有组合电路的成分存在,但组合电路中绝对不可能有时序逻辑的存在,更加容易的理解方式就是组合电路是没有记忆的,而时序电路是由记忆的。
2.编写纯净的组合或时序逻辑
在FPGA设计中,如果去掉存储功能的结构(寄存器,RAM,FIFO),那么剩下的就是纯组合逻辑电路,因此将具有存储功能的结构称为纯时序逻辑电路。
组合逻辑范例书写
2.1 组合电路编写需要注意的点)
2.1.1 避免出现锁存
上述例子中,输出为a,输入为sel和b,当sel =
1时,输出a取决于输入b,可当sel为逻辑0的时候,从语法上看,此时应为保持最近的sel = 1
时b的值,而与当前的b无关,因此在综合的时候引入了锁存器(即存储单元),所以看似是一个组合电路,实际在综合后为时序电路。
同时锁存器是毛刺敏感的,如果sel信号的质量不好,会造成输出信号a的不稳定,其次FPGA中是没有锁存器这个资源的,通常是通过一个触发器加逻辑门来实现的,比较浪费资源;第三,锁存器的引入会导致时序分析的困难。
解决方案:在书写代码,务必确保代码覆盖到所有组合逻辑的所有的分支,以避免锁存器的引入。因此争取的写法是:
2.1.2 注意语句的顺序
组合电路中是不存在反馈电路的,所以电信号在组合逻辑中的传递方向是固定从输入端到输出端,因此,在书写组合逻辑时,最好按照电信号的传递顺序来安排串行组合逻辑中的语句顺序。
2.2 纯时序电路编写要注意的点
范例中可以看多,相对于组合逻辑最大的不同就是敏感时钟边沿事件,但这也是有一定的约束的首先需要注意的问题是避免敏感双沿
2.2.1 避免敏感双沿
一个寄存器要么在上升沿要么在下降沿,不可能同时敏感时钟的两种双边沿事件,这是由其中所对用的触发器的结构和工作原理决定的,类似的always@(posedge clk, negedge clk)代码是不可综合的,这是与对应的触发器的结构和工作原理决定的,其中还看了DDR,DDR(Double data rate)可以在上升沿和下降沿同时传递和采样,但是DDR是通过使用两个不同敏感触发沿的触发器加上MUX电路协作实现的。这个错误我在笔试中犯过,所以要特别注意。
2.2.2 组合和时序不要混写
为什么一定要这样做呢?回答是,这是因为要使综合前仿真和综合后仿真一致的缘故,否则也有可能综合出正确的逻辑,但前后仿真的结果就会不一致。
1)在时序always中使用阻塞赋值
在时序电路中推荐使用非阻塞赋值方法,如果使用阻塞赋值,会导致一些隐患
在时序电路的always块中,无论是阻塞还是非阻塞,等号左边的变量都会被综合成触发器,
always@(posedge clk)
begin
n = a&b;
m <= a&b;
end
m 和 n 的结果是一样的
但由于always块是串行执行的,但又由于非阻塞赋值不是立即执行的,是敏感信号触发时同时执行,无所谓先后,在时序电路中打乱语句的顺序,寄存器之间的关系不会改变,但一旦阻塞和非阻塞混用,阻塞赋值符号是立即实现的,这种情况下,语句的顺序就很重要,下面两段代码综合后的结果不同
在第一个的示例中,n的输出在上升沿后就等于a&b,使用了阻塞,m的输出等于n的新值,m,n是一样的;而在第二个示例中,m等于存储的旧的值,n赋值的是新值。
由此可见,最大的隐患就是会导致电路结构发生本质的变化。
2)在组合always中使用非阻塞
在组合逻辑中,推荐全部使用阻塞赋值的方式,组合always敏感列表中不可能出现边沿敏感事件,所以如果使用了非阻塞的赋值也不会相应综合出寄存器,所以编译结果仍然是纯组合逻辑,这种不规范的写法会出现前仿真和后仿真结果不一致的问题
2.3 可综合风格的Verilog模块编程的八大原则
可以解决在综合和仿真后出现的90%~100%的冒险竞争问题
- 时序电路建模时,用非阻塞赋值。
- 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。
- 用always块建立组合逻辑模型时,用阻塞赋值
- 在同一个always块中不要既用非阻塞赋值又用阻塞赋值。
- 锁存器电路建模时,用非阻塞赋值
- 不要在一个以上的always块中为同一个变量赋值
- 用$strobe系统任务来显示用非阻塞赋值的变量值
- 在赋值时不要使用 #0 延迟
3.阻塞赋值和非阻塞赋值
阻塞赋值:用=表示,阻塞赋值语句不允许任何别的verilog语句的干扰,在一个always块中,其后面的赋值语句从概念上是在前一句赋值语句结束后再开始的,也就是说直到现行的赋值完成,才允许别的赋值语句的执行,一般可综合的阻塞赋值操作不能设定延迟,赋值语句只是概念上的先后,而无实质上的延迟,加上延迟不可综合,使得仿真和综合不一样。再安排组合逻辑时序时要安排好顺序,注意避免出现竞争和冒险的情况,典型的例子如下:
[例1]. 用阻塞赋值的反馈振荡器
module fbosc1 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always @(posedge clk or posedge rst)
if (rst) y1 = 0; // reset
else y1 = y2;
always @(posedge clk or posedge rst)
if (rst) y2 = 1; // preset
else y2 = y1;
endmodule
非阻塞赋值:用小于等于号<=表示,非阻塞赋值运行其他的Verilog同时进行操作,再赋值时刻开始时,计算非阻塞赋值左值表达式,再赋值时刻结束时,更新非阻塞赋值的表达式。
4. Verilog HDL 有下列四种基本的值来表示硬件电路中的电平逻辑:
0:逻辑 0 或 “假”
1: 逻辑 1 或 “真”
x 或 X:未知
z 或 Z:高阻
x 意味着信号数值的不确定,即在实际电路里,信号可能为 1,也可能为 0。
z意味着信号处于高阻状态,常见于信号(input, reg)没有驱动时的逻辑结果。例如一个 pad 的 input 呈现高阻状态时,其逻辑值和上下拉的状态有关系。上拉则逻辑值为 1,下拉则为 0 。
缓冲器/非门 (buf / not)对应的输入输出的关系