Verilog 语法(二)···············简单入门

    经过数字逻辑电路课程的学习,大家已对多路选择器(数据选择器)有了一定的认识。本节将通过建模2选1的数据选择器,简单介绍Verilog的各级建模语言。

一、行为级建模 

    使用always块来对数据选择器进行描述,其后面的小括号为该always块的敏感列表(sensitive list),只要sl或a或b其中有一个变化时,就执行其后的语句。需要注意的是,always块内的输出out,必须定义为reg型变量,因为该值在同一块内可能多次变化。

module muxtwo (out,a,b,sl);
input a,b,sl;
output out;
reg out;
    always@ (sl or a or b)
        if(!sl) out=a;
        else out=b;
endmodule 

Verilog 语法(二)···············简单入门_第1张图片

RTL级语言为一种行为描述语言,只关心电路功能。

二、RTL建模

    需要用到2选1数据选择器的门级电路图。Verilog 语法(二)···············简单入门_第2张图片

    数据流建模,其标志多为并行的多个assign连续赋值语句,将对输入输出结点以及内部的各个结点的信号进行赋值定义操作。代码如下:

module muxtwo(out,a,b,sl);
input a,b,sl;
output out;
wire nsl,sela,selb;//定义内部结点
    assign nsl= ~sl;
    assign sela= a & nsl;
    assign selb= b & sl;
    assign out= sela | selb;
endmodule

三、门级建模

Verilog 语法(二)···············简单入门_第3张图片

    该电路的门级图如上,两者相不同的是,数据流建模代码只需要电路图中的结点名称,门级建模代码不仅需要各结点名称,而且需要各个具体的门器件名称,以便例化出该名称的对应门,并且描述该所需门的输入输出。代码如下:

module muxtwo(out,a,b,sl);
input a,b,sl;
output out;
wire nsl,sela,selb;
    not u1(nsl,sl);
    //not表示的是Verilog语言中自带的非门,该语句表示例化一个叫u1的非门,其输入是sl,输出是nsl。
    and #1 u2(sela,a,nsl);
    //#1表示的是该与门的输入到输出延迟1个时间单位。
    //and表示的是例化调用Verilog语言中自带的与门,其输入是nsl和a,输出是sela。
    and #1 u3(selb,b,sl);
    or #2 u4(out,sela,selb);
    //#2表示的是该或门的输入到输出延迟2个时间单位。
    //or表示的是例化调用Verilog语言中自带的或门,其输入是sela和selb,输出是out。
endmodule

四、Verilog语法的主要特点之一——模块例化

    模块例化是指,对低层次模块的调用。说白了就是在一个module......endmodule中需要使用其他的module......endmodule的功能,则通过调用模块名(调用方式见后)将该模块的功能移植到当前的主模块中。这个过程在主模块中只体现被调用(被例化)模块的输入和输出。使用原理就像C语言中的函数一样,调用时只关心函数的输入输出。同时,它其实是与C++中的“类与对象”同出一辙。

1. 门的例化:在刚刚的门级建模语句中,已经出现了对与门,或门,非门的例化,在此先介绍各个门在Verilog库中的名称: 

与门 and
或门 or
非门 not
与非门 nand
或非门 nor
异或门 xor
同或门 xnor
缓冲器 buf

     具体的,当拥有这些门后,该如何在语句中运用呢?下面是门的声明使用格式:

     <门类型> [延时] <门的例化名> (<输出1,输出2......>,<输入1,输入2......>);

如:xor g1 (out[j],i0[j],i1[j]);  //延时可以省略。

2. 模块的例化:模块的例化方式主要有两种:

①顺序例化:

格式:<模块名> <例化名>(端口信号与被例化模块的定义内的端口顺序相接);

   

注:该种方式例化,若有不需连接的端口,需要跳过并空出该端口在模块定义中的位置,如:(<例化块的端口信号名1>,,<例化块的端口信号名3>),跳过了例化块的端口信号名2。

②名称例化:

格式:<模块名> <例化名>(.<被例化模块的端口名1>(<例化块的端口信号名1>),

                                             .<被例化模块的端口名2>(<例化块的端口信号名2>),······);

例如,全加器 full_adder (a,b,c_out,sum); 的例化应用:

//顺序例化
full_adder m0 (a[0],b[0],c_out[0],sum[0]);
full_adder m1 (a[1],b[1],c_out[1],sum[1]);
full_adder m2 (a[2],b[2],c_out[2],sum[2]);
full_adder m3 (a[3],b[3],c_out[3],sum[3]);

//名称例化
full_adder m0 (.a(a[0]),.b(b[0]),.c_out(c_out[0]),.sum(sum[0]));
full_adder m1 (.a(a[1]),.b(b[1]),.c_out(c_out[1]),.sum(sum[1]));
full_adder m2 (.a(a[2]),.b(b[2]),.c_out(c_out[2]),.sum(sum[2]));
full_adder m3 (.a(a[3]),.b(b[3]),.c_out(c_out[3]),.sum(sum[3]));

//两种例化方式结果等价
//若令a=[0110],即a[0]=0,a[1]=1,......,b=[1100],c_out=0,
//则最后的结果可推得为,sum[3]=0,sum[2]=0,sum[1]=1,sum[0]=0,c_out=1

五、testbench入门

    testbench是一个模块的测试模块(激励块),就是给予所设计的模块一个或多个激励,测试所得到的结果是否满足所设定的功能。用来验证设计的模块的正确性。testbench为顶层模块,不会被其他模块例化,所以不需要有端口。

    对于前面的二选一数据选择器,写一个testbench:

module test;
    reg a,b,sl;
    wire out;
    muxtwo mux(out,a,b,sl); //例化数据选择器模块
    initial
        begin
         a=0; b=1; sl=0;
         #5 b=0;
         #5 b=1; sl=1;
         #5 a=1;
         #5 $finish;//系统函数,表示结束当前仿真
        end
    initial
         $monitor($time,"out=%b,a=%b,b=%b,sl=%b",out,a,b,sl);
         //每次out,a,b,sl的值有变化时,打印out,a,b,sl的值。(系统函数monitor之后介绍)
endmodule

其输出结果应该为:

time out a b sl
0 0 0 1 0
5 0 0 0 0
10 1 0 1 1
15 1 1 1 1
20 finish finish finish finish

你可能感兴趣的:(Verilog,语法干货,verilog)