【FPGA】组合逻辑电路三种建模方式(Verilog HDL 门级建模、Verilog HDL 数据流建模、组合电路行为级建模)

该文章已生成可运行项目,

目录

 

Verilog HDL 门级建模

各种逻辑门的表示和使用

门级建模书写实例

Verilog HDL 数据流建模

数据流建模

数据流建模书写实例

组合电路行为级建模

always语句

条件语句

多路分支语句

循环语句

for

while

repeat

forever

行为级建模示例


 

Verilog HDL 门级建模

可以理解为对逻辑电路中各个门依次进行描述二建模成组合逻辑电路

各种逻辑门的表示和使用

  • 多输入门(只允许有一个输出端,但可以有多个输入端):and(与门)、nand(与非门)、or(或门)、nor(或非门)、xor(异或门)、xnor(同或门)
  • 多输出门(只允许有一个输入端,但可以有多个输出端):buf(缓冲器)、not(反相器,非门)
  • 三态门(有一个输出,一个数据输入,一个控制输入):
    • bufif1:控制信号为高电平时,输入和输出相同,否则输出高阻态z
    • bufif0:控制信号为低电平时,输入和输出相同,否则输出高阻态z
    • notif1:控制信号为高电平时,输入和输出相反,否则输出高阻态z
    • notif0:控制信号为低电平时,输入和输出相反,否则输出高阻态z

输出的格式

//多输入门
Gate  Name(out, in1, in2, ..., inN);//Gate是上述六种多输入门中的一种,Name为自己命名的实例引用名(不需要声明,且可以省略),括号内的是输入输出端口(左边第一个端口必须是输出端口,其他端口均为输入)
//举例
and U1(out, in1, in2, in3);


//多输出门
Gate Name(out1, out2, ..., outN, in);//Gate是buf或者not,Name为自己命名的实例引用名(不需要声明,且可以省略),括号内的是输入输出端口(右边第一个端口必须是输入端口,其他端口均为输出)
//举例
buf B1(out1, out2, out3, in);

//三态门
Gate Name(out, in, ctrl);//Gate是四种三态门中的一种,Name为自己命名的实例引用名(不需要声明,且可以省略),括号内的是输入输出端口(从左到右依次为输出,数据输入,控制输入)
//举例
notif1 N1(out, in, ctrl);

门级建模书写实例

上一篇blog中提到的二选一数据选择器

e3a0083d5d7141159f2fdb6bb833f3dc.png

module TueBitSelector(
	input D0, D1, S,
	output Y
);
	wire Snot, A, B;
	not U1(Snot, S);
	and U2(A, D0, Snot);
	and U3(B, D1, S);
	or  U4(Y, A, B);
endmodule

仿真出的波形如图

b2f65e3b3eca4a17ba144cd4e3c38b4f.png

Verilog HDL 数据流建模

数据流建模

数据流建模使用的连续赋值语句由关键词assign开始,后面跟着由操作数和运算符等组成的逻辑表达式

可以简单理解为使用assign语句对输出信号进行赋值

用法如下:

        wire [位宽]signal1, signal2, ..., signalN;

        assign  signal1 = 逻辑表达式1;

        assign  signal2 = 逻辑表达式2;

        assign  signal3 = 逻辑表达式3;

        ...;

        assign  signalN = 逻辑表达式N;

注意:assign赋值语句只能对wire信号进行赋值,所以signal必须是wire类型的

assign赋值的语句运行时,只要逻辑表达式中的任何逻辑值发生变化,则该逻辑表达式的值就会被计算出来赋值给左边

数据流建模书写实例

e3a0083d5d7141159f2fdb6bb833f3dc.png

该二选一数据选择器Y对应的逻辑表达式为

(D0&(~S))|(D1&S)

故使用数据流建模方式可以将代码改写为

module TueBitSelector(
	input D0, D1, S,
	output wire Y
);
	assign Y = (D0&(~S))|(D1&S);
endmodule

仿真波形仍然如此

17f4272dc2bc4fd19d81ed230f2f9eec.png

组合电路行为级建模

在 Verilog HDL 中,从逻辑电路外部行为的角度对其功能和算法进行描述,称为行为建模。主要使用关键词为 initial 语句或 always 的两种过程化的结构来描述电路的行为

在一个模块的内部可以包含多个 initial 或 always,仿真时这些语句并行执行,即与它们在模块内部排列的顺序无关,都从仿真的 0 时刻开始执行。 initial(初始化)主要在测试模块中使用,通常用来描述激励信号,仿真时仅执行一次

initial 语句主要是面向仿真的过程语句,逻辑综合工具不支持 initial 语句。在这两种结构内部,经常会用到条件语句( if-else)、多路分支语句( case-endcase)和循环语句等比较抽象的编程语句,这些语句也称为过程化语句。

always语句

always 本身是一个无限循环语句,即不停地循环执行其内部的过程语句,直到仿真过程结束。但用它来描述硬件电路的逻辑功能时,通常在 always 后面紧跟着循环的控制条件,所以always 语句的一般用法如下:
 

always @(敏感信号列表)        //敏感信号发生改变时或者条件变为真时,执行该循环

    begin:块名                //块名可以省略

        块内部局部变量的定义;

        过程赋值语句;

    end
//begin和end之间只有一条语句时,begin和end可以省略不写
//begin 和 end 将多条过程赋值语句包围起来,组成一个顺序语句块,块内的语句按照排列顺序依次执行,最后一条语句执行完后,执行暂停,然后 always 语句处于等待状态,等待下一个事件的发生。

注意:过程赋值语句中的左边的变量必须被定义成reg类型,右边的变量可以是任意数据类型

条件语句

这里与c语言中大致相同,具体格式如下,不在过多阐述

if (condition_expr1) true_statement1;
else if (condition_expr2) true_statement2;
else if (condition_expr3) true_statement3;
……
else default_statement;

注意:如果判断条件计算出为0,z或者x时,都按假处理

多路分支语句

这与C语言中的switch...case语句相似,但也有不同,具体格式和说明如下

case (case_expr)        //整个多路分支由case与endcase包裹
    item_expr1: statement1;//每一行由 值:功能 组成,并且只执行该值下的功能
                            //如果statement中的语句不止一句的话,则需要用begin...end组成一个顺序语句块
    item_expr2: statement2;
    ……
    default: default_statement;
endcase

另外, case 语句还有两种变体,即 casez 和 casex。

在 casez 语句中,将 z 视为无关值,如果比较的双方( case_expr 的值与 item_expr 的值)有一方的某一位的值是 z,那么该位的比较就不予考虑,即认为这一位的比较结果永远为“真”,因此只需关注其他位的比较结果。

在 casex语句中,将 z 和 x 都视为无关值,对比较双方( case_expr 的值与 item_expr 的值)出现 z 或 x的相应位均不予考虑。注意,对无关值可以用“?”表示。除了用关键词 casez 或 casex 来代替case 以外, casez 和 casex 的用法与 case 语句的用法相同。但由于综合器对这两个关键字的支持情况略有差异,因此建议使用完整的 case 结构,而不使用 casex 或 casez。

循环语句

for

for是一种条件循环语句,具体表达式如下

for(表达式1;表达式2;表达式3;)        语句块;

与C语言相似

表达式1用来给循环计数变量赋初值,只在第一次循环执行

表达式2是循环所需的条件

表达式3是修改循环变量的值,当修改后的值不满足表达式2时,则退出循环

while

while循环表达式如下

while(条件表达式)    语句块; 

当条件表达式为真时,while内语句块执行,为假时,不执行,且0,z,x均视为假

repeat

repeat循环表达式如下

repeat(循环次数表达式)    语句块;

repeat执行循环的次数由循环表达式计算得出,若时0,z,x,则循环0次

可以采用repeat循环产生时钟信号

module Clock;
    reg CP;
    initial begin
        CP=1'b0; //在0时刻, CP=0
        repeat(10) //循环次数为10
            #10 CP=~CP;
    end
endmodule

forever

forever是一种无限循环,其表达式如下

forever 语句块;

forever将不停执行后面的语句块,一般要在语句块中采取时序控制结构,不然后面的语句将永远无法执行

使用forever产生时钟信号的代码如下

`timescale 1ns/1ns //时间单位为ns,精度为1ns
module CP_gen();
    reg CP;
    initial begin
        CP=1'b1; //在0时刻, CP=1
        #50 forever
        #25 CP=~CP; //每隔25个ns, CP反相一次
        end
    initial
        #300 $stop; //到300ns时,结束循环
endmodule

行为级建模示例

在之前的二选一数据选择器中,测试模块就采用行为级建模


`timescale 1 ns/ 1 ns
module TueBitSelector_vlg_tst();
// constants                                           
// general purpose registers
reg eachvec;
// test vector input registers
reg D0;
reg D1;
reg S;
// wires                                               
wire Y;

// assign statements (if any)                          
TueBitSelector i1 (
// port map - connection between master ports and signals/registers   
	.D0(D0),
	.D1(D1),
	.S(S),
	.Y(Y)
);
initial begin
	S = 1'b0;
	D0 = 1'b0;
	D1 = 1'b0;
	#1 D0 = 1'b1;
	#1 D0 = 1'b0;
	#1 D1 = 1'b1;
	#1 D0 = 1'b1;
	#1 S  = 1'b1;
	#1 D0 = 1'b0;
	#1 D1 = 1'b0;
	#1 D0 = 1'b1;
	#1 D0 = 1'b0;
	#1 D1 = 1'b1;
	#1 D0 = 1'b1;
end
initial begin
	$monitor($time,":\tS=%b\tD1=%b\tD0=%b\tY=%b", S, D1, D0, Y);                       
end                                                
endmodule

 

 

 

本文章已经生成可运行项目
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不出寝室爱睡觉.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值