功能描述-组合逻辑
主页-old > 教程中心 > 至简原理 > 书籍:FPGA至简原理与应用 >
2023-04-13 人气:  作者:admin

本节的文档编号:001100000061

需要看对应的视频,请点击视频编号: 001100000053

1、本节主要进行组合逻辑的介绍,包括:程序语句(assign语句、always语句),数字进制(二进制、不定态、高阻态),算数运算符(加、减、乘、除运算符),逻辑运算符(逻辑与、或、非运算符),按位逻辑运算符(单目按位与、或、非运算符,双目按位与、或、异或运算符),关系运算符,移位运算符(左移、右移运算符),条件运算符(三目运算符、if语句、case语句、选择语句等),拼接运算符;
2、ALTERA和VIVADO文档

第5节 功能描述-组合逻辑


5.1 程序语句

5.1.1assign语句

    assign语句是连续赋值语句,一般是将一个变量的值不间断地赋值给另一变量,两个变量之间就类似于被导线连在了一起,

习惯上当做连线用。assign语句的基本格式是:

assign a = b (逻辑运算符)c …;
assign语句的功能属于组合逻辑的范畴,应用范围可以概括为一下几点:
1)持续赋值;
2)连线;

3)对wire型变量赋值,wire是线网,相当于实际的连接线,

如果要用assign直接连接,就用wire型变量,wire型变量的值随时发生变化。

需要说明的是,多条assign连续赋值语句之间互相独立、并行执行。

5.1.2always语句

    always 语句是条件循环语句,执行机制是通过对一个称为敏感变量表的事件驱动来实现的,

下面会具体讲到。always 语句的基本格式是:

always @(敏感事件)begin
       程序语句
end

always是“一直、总是”的意思,@后面跟着事件。整个always的意思是:当敏感事件的条件满足时,

就执行一次“程序语句”。敏感事件每满足一次,就执行“程序语句”一次。


1
  
2
  
3
  
4
  
5
  
6
always   @(a or b or d)begin
  
     if(sel==0)
  
         c = a + b;
  
     else
  
         c = a + d;
  
end


    这段程序的意思是:当信号a或者信号b或者信号d发生变化时,就执行一次下面语句。

在执行该段语句时,首先判断信号sel是否为0,如果为0,则执行第3行代码。如果sel不为0,则执行第5行代码。

需要强调的是,abc任意一个发生变化一次,2行至5行也只执行一次,不会执行第二次。

此处需要注意,仅仅sel这个信号发生变化是不会执行第2行到5行代码的,通常这并不符合设计者的想法。

例如,一般设计者的想法是:当sel0c的结果是a+b;当sel不为0c的结果是a+d

但如果触发条件没有发生改变,虽然sel01,但此时c的结果仍是a+b。因此,这并不是一个规范的设计思维。


    因此,按照设计者的想法重新对代码进行设计:当信号a或者信号b或者信号d或者信号sel发生变化时,

就执行2行至5行。这样就可以确保sel信号值为0时,c的结果一定为a+b,当sel不为0时,c的结果一定是a+d

因此要在敏感列表中加入sel,其代码如下所示。


1
  
2
  
3
  
4
  
5
  
6
always   @(a or b or d or sel)begin
  
     if(sel==0)
  
         c = a + b;
  
     else
  
         c = a + d;
  
end


    当敏感信号非常多时很容易就会把敏感信号遗漏,为避免这种情况可以用“*”来代替。

这个“*”是指“程序语句”中所有的条件信号,即abdsel(不包括c),笔者也推荐这种写法,

其具体代码如下所示。



1
  
2
  
3
  
4
  
5
  
6
always   @(*)begin
  
     if(sel==0)
  
         c = a + b;
  
     else
  
         c = a + d;
  
end

   
    这种条件信号变化结果立即变化的always语句被称为“组合逻辑”。


1
  
2
  
3
  
4
  
5
  
6
always   @(posedge clk)begin
  
     if(sel==0)
  
         c <= a + b;
  
     else
  
         c <= a + d;
  
end


    上述代码敏感列表是“posedge clk”,其中posedge表示上升沿。也就是说,

clk0变成1的瞬间执行一次程序代码,即第25行,其他时刻c的值保持不变。

要特别强调的是:如果clk没有由0变成1,那么即使abdsel发生变化,c的值也是不变的。



1
  
2
  
3
  
4
  
5
  
6
always   @(negedge clk)begin
  
     if(sel==0)
  
         c <= a + b;
  
     else
  
         c <= a + d;
  
end

   

    可以看到上述代码的敏感列表是“negedge clk”,其中negedge表示下降沿。

也就是说,当clk1变成0的瞬间执行一次程序代码,即第25行,其他时刻c的值保持不变。

要特别强调的是,如果clk没有由1变成0,那么即使abdsel发生变化,c的值也是不变的。



1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
always   @(posedge clk or negedge rst_n)begin
  
     if(rst_n==1'b0)begin
  
         c <= 0;
  
     end
  
     else if(sel==0)
  
         c <= a + b;
  
     else
  
         c <= a + d;
  
end

    上述代码的敏感列表是“posedge clk or negedge rst_n”,也就是说,当clk0变成1的瞬间,

或者rst_n1变化0的瞬间,执行一次程序代码,即第28行,其他时刻c的值保持不变。


    这种信号边沿触发,即信号上升沿或者下降沿才变化的always,被称为“时序逻辑”,

此时信号clk是时钟。注意:识别信号是不是时钟不是看名称,而是看这个信号放在哪里,

只有放在敏感列表并且是边沿触发的才是时钟。而信号rst_n是复位信号,同样也不是看名字来判断,

而是放在敏感列表中且同样边沿触发,更关键的是“程序语句”首先判断了rst_n的值,

这表示rst_n优先级最高,一般都是用于复位。


设计时需要注意以下几点:
1、组合逻辑的always 语句中敏感变量必须写全,或者用“*”代替。


2、组合逻辑器件的赋值采用阻塞赋值“=,时序逻辑器件的赋值语句采用非阻塞赋值“<=”,

具体原因见“阻塞赋值和非阻塞赋值”一节内容。

相关视频:https://www.bilibili.com/video/BV1yf4y1R7gH?p=7


相关视频:https://www.bilibili.com/video/BV1yf4y1R7gH?p=7


上一篇:信号类型
下一篇:数字表示方式