从零开始学FPGA -- Verilog模块调用、阻塞与非阻塞赋值、状态机

在编写各种语言时,正确良好的注释是必不可少的,一般我们最少要保证3:1的代码注释比例,即3句代码至少一个注释。Verilog有两种注释方式:
单行注释:以 // 开头
多行注释:以 /* 开始,以 */ 结束

一、Verilog调用模块

Verilog的基本设计单元是“模块”。一个模块是由两部分组成的,一部分描述接口,另一部分描述逻辑功能。每个Verilog程序包括4个主要的部分:端口定义、IO说明、内部信号声明、功能定义。

例如下面的代码:

module yuanlaishini(a,b,c,d);
	input a,b;
	output c,d;
reg [23:0] counter;
assign c = a | b;
assign d = a & b;

endmodule

每个模块都是以module开始,endmodule结束。yuanlaishini为模块名,在实际中我们应该起一个比较“正经”的名字,最好是能体现模块功能的名字。上述例子中(a,b,c,d)即为端口定义,描述了本模块都有哪些端口,input a,b;与output c,d; 即为IO说明,reg [23:0] counter为内部信号声明;assign在前面已介绍过,它是一种给wire类型赋值的,assign这两句即为功能定义

功能定义有三种方法:assign语句是来描述组合逻辑;always语句是来描述组合/时序逻辑;例化实例元件(如:and #2 u1(q,a,b);)
上述三种逻辑功能是并行的,这也是FPGA最重要的一个特点,在C语言中,谁在前面谁先执行,但在verilog中无论多个always或assign如何放置,他们都是并行同时执行的。在always块中,逻辑是顺序执行的,而多个always块之间是并行的。

那么不同模块之间如何调用呢?
我们考虑一个简单的全加器模块:
在这里插入图片描述

module add(a,b,cin,s,cout);
	input a,b,cin;
	output cout,s;
	assign {cout,s} = a + b + cin;
endmodule

若一个模块temp需要调用adder模块时,temp中的与adder想连的端口需要与adder中声明的端口顺序一致(第一种调用方式)。调用首先写被调用模块的名称(add) ,随后的是实例名(my_add,用户自己定义)
然后按adder中端口的顺序写下实例的端口名即可。

module temp(B,A,COUT,CIN,Sum);
...
    add  my_add(A,B,CIN,Sum,Cout);
...
endmodule

若不需要全部的端口则如下调用:

add my_add(A , , CIN , , COUT);

此实例中没有引用add中的b,s两个端口,故省略,但逗号一定要保留。

第二种调用端口顺序可以随意摆放,同样以调用adder模块为例。

module temp(B,A,COUT,CIN,Sum);
...
...
 add  my_add(.a(A), .s(Sum), .b(B), .cout(Cout), .cin(CIN));
...
endmodule

可以看出我们用.a .b代表原模块里的端口,而调用后的端口名为括号中的A B。

推荐使用第二种调用方式,比较清楚直观,代码维护也很方便。

二、阻塞与非阻塞赋值

根据逻辑功能的不同特点,可以将数字电路分成两大类:组合逻辑电路 和 时序逻辑电路。

组合逻辑电路中,任意时刻的输出仅仅取决于该时刻的输入,与电路原来的状态无关。

时序逻辑电路中,任一时刻的输出不仅取决于当时的输入信号,而且还取决于电路原来的状态。或者说还与以前的输入有关,因此时序逻辑必须具备记忆功能。
组合逻辑
组合逻辑
在这里插入图片描述
时序逻辑

边沿触发的 always 块常常描述时序逻辑行为(例如下图中代码)。
在这里插入图片描述
posedge代表上升沿,negedge代表下降沿。两个都是Verilog语言中的关键字

电平触发的 always 块常常描述组合逻辑行为(例如下图中代码)。
在这里插入图片描述
阻塞赋值(blocking),如 b = a;
所谓阻塞的概念是指,在同一个always块中,后面的赋值语句是在前一句赋值语句结束后才开始赋值的。
在这里插入图片描述
上述代码含义就是:always一直运行检测clk(时钟信号)是否出现了上升沿(posedge)或者rst_n(复位信号)出现了下降沿(negedge),如果出现则进入程序。当*!rst_n*时,即rst_n为0时,执行第一个begin end块里的代码,也可以从下图看到rst_n为0时a=1,b=2,c=3。而当 rst_n为1时,并且同时clk出现上升沿时(必须进入程序),我们开始执行第二个begin else块里的代码。
在这里插入图片描述
如上面的例子,我们本来是想让a=0,b=a=1, c=b=2,但是由于使用了阻塞赋值,导致a b c 都成了0, 这是因为在同一个always块中,后面的赋值语句是在前一句赋值语句结束后才开始赋值的。那么想实现a=0,b=a=1, c=b=2应该怎么做呢,那就是使用非阻塞赋值。
非阻塞赋值(Non_Blocking),如 b <= a;
所谓非阻塞的概念是指,在计算非阻塞赋值的RHS(右边表达式)以及更新LHS(左边表达式)期间,允许其他的非阻塞赋值语句同时计算RHS和更新LHS。
在这里插入图片描述
在这里插入图片描述
我们可以看到此时达到了我们的目标,在rst_n为高电平,clk出现上升沿时,a赋值0,b赋值1,c赋值2。下一个clk上升沿时,再同时给a,b,c赋值即变成了a=0,b=0,c=1。

一般我们在描述组合逻辑的 always 块中用阻塞赋值 = ,综合成组合逻辑的电路结构; 这种电路结构只与输入电平的变化有关系。

在描述时序逻辑的 always 块中用非阻塞赋值 <=,综合成时序逻辑的电路结构; 这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值的变化。

注意:
在同一个always块中不要既用非阻塞赋值又用阻塞赋值
不允许在多个always块中对同一个变量进行赋值!

三、状态机

假设下面是用FPGA实现一个电子密码锁,其密码是8023,我们要如何描述这个过程?
在这里插入图片描述
我们可以使用下面这个转换状态图来描述,按顺序检测8-0-2-3,只要过程中有一个是错误的,就表示无法解锁。这个过程描述就是一个简单的状态机表示方法。
在这里插入图片描述
状态机一般指有限状态机(Finite State Machine,简称FSM),在有限个状态之间按一定规律转换的时序电路。
在这里插入图片描述
上图是典型的三段式状态机
状态寄存器由一组触发器组成,用来记忆状态机当前所处的状态,状态的改变只发生在时钟的跳变沿。

状态是否改变、如何改变,取决于组合逻辑F的输出,F是当前状态和输入信号的函数。

状态机的输出是由输出组合逻辑G提供的,G也是当前状态和输入信号的函数。

在这里插入图片描述
三段式状态机可以在组合逻辑后再增加一级寄存器来实现时序逻辑输出,其好处有:
(1) 可以有效地滤去组合逻辑输出的毛刺;
(2)可以有效地进行时序计算与约束;
(3) 另外对于总线形式的输出信号来说,容易使总线数据对齐,从而减小总线数据间的偏移,减小接收端数据采样出错的频率。

三段式状态机Verilog的实现

//第一个always块,时序逻辑,描述现态转移到次态
always @ (posedge clk or negedge rst) begin
    if(rst_n) 
        current_state<=S0;
    else
        current_state<=next_state;
end

//第二个always块,组合逻辑,描述状态转移的条件
always @ (current_state) begin
    case(current_state)
    S0:begin
        if(condition1)        next_state <= S1;//状态转移
        else if (condition2)  next_state <= S2;//状态转移
        else next_state <= S0;
        end
    S1:begin
        if(condition3)       next_state <= S3;//状态转移
        else if (condition4) next_state <=S4; 
        …
        end
    ……
    default: begin
            if(condition0)   next_state <= S0;//状态转移
           end
    endcase
end
//第三个always块,时序逻辑,描述输出
always @ (posedge clk or negedge rst) begin
if(rst)
    out0;
else
    case(current_state)
    S0: out0;
    S1: out1;
    ….
    default:Out0;
    endcase
end

参考:
正点原子FPGA开发指南
llxxyy507,Verilog调用模块注意事项, CSDN 原文链接
李硕LeeSure, 状态机(二):Verilog状态机实现,CSDN 原文链接


2019年3月29日 沙坡村职业技术学院

猜你喜欢

转载自blog.csdn.net/YDC123458/article/details/88901904