• Verilog学习条件语句、循环语句、块语句与生成语句


    1.条件语句(if_else语句)

    3钟形式的if语句:

    1)if(表达式)语句。如

    if(a>b)

    out1 = int1;

    2)if(表达式)

    语句;

    else

    语句;如

    if(a>b)

    out1 = int1;

    else

    out1 = int2;

    3)if(表达式1)

    语句1;

    else if(表达式2) 语句2;

    else if(表达式3) 语句3;

    …………………...

    else if(表达式m) 语句m;

    else 语句n;

    条件语句必须在过程块语句中是用(initial和always语句),除了这两个语句引导的bedin end块中可以编写条件语句外,模块中的其他地方都不能编写。

    说明

    (1)3钟形式的if语句中if后面的表达式一般为逻辑表达式或关系表达式。判断若为0、Z、X按假处理,若为1,按真处理执行指定语句。

    (2)在每个else前面有一分号,整个语句结束处有一分号。

    (3)if和else后包含多个操作语句时要用begin_end包含成一个复合语句。

    (4)允许一定形式的表达式简写

    (5)else总是与它上面最近的if配对

    2.case语句

    case语句提供一种多分支选择语句,形式如下:

    (1)case(表达式)<case分支项> endcase

    (2)casez(表达式)<case分支项> endcase

    (3)casex(表达式)<case分支项> endcase

    case分支项格式如下

    分支表达式: 语句;

    default: 语句;

    说明:

    1)分支表达式又可以称为常量表达式。

    2)当控制表达式与分支表达式相等时就执行分支表达式后的语句,如没有相等的就执行default后的语句。

    3)default项可有可无,一个case语句只准有一个default项。

    4)每个case的分支表达式的值必须互不相等,否则就会出现问题。

    5)执行完case分项后的语句则跳出case语句结构,终止case语句。

    6)在用case语句表达式进行比较时只当信号对应位的值能明确进行比较时,比较才会成功,因此要详细说明case分项的分支表达式的值。

    7)case语句的所有表达式的值位宽必须相等。

    Casez语句用来处理不考虑高阻值z的比较过程

    casex语句用来处理不考虑高阻值X的比较过程

    如果用到if语句最好写上else项;

    如果用case语句最好写上default项。

    3.条件语句的语法

    If else表示的条件语句共有3种类型:

    //第一类条件语句

    if ( !lock ) buffer = data ;

    if ( enable ) out = in ;

    //第二类条件语句

    if (number_queued < MAX_Q_DEPTH)

    begin

    data_queue = data ;

    number_queued = number_queued + 1 ;

    end

    else

    $display ( " Queue Full. Try again " ) ;

    //第三类条件语句

    //根据不同的算术逻辑单元的控制信号 alu_control 执行不同的算术运算操作

    if ( alu_control = = 0 )

    y = x + z ;

    else if ( alu_control = = 1 )

    y = x - z ;

    else if ( alu_control = = 2 )

    y = x * z ;

    else

    $ display ( " Invalid ALU control signal ");

    reg [ 1: 0] alu_control ;

    case (alu_control)

    2 'd 0 : y = x + z ;

    2 'd 1 : y = x - z ;

    2 'd 2 : y = x * z ;

    default : $display ( "Invalid ALU control signal ") ;

    endcase

    4.多路分支语句

    case语句 case endcase default

    5.循环语句

    (1)forever语句:连续的执行语句。

    (2)repeat语句:连续执行一条语句n次。

    (3)while语句:执行一条语句直到某个条件不满足。如果一开始就不满足则语句一次也不执行。

    (4)for语句通过以下3个步骤决定语句的循环次数

    1)先给控制循环次数的变量赋初值。

    2)判定控制循环的表达式的值,为假则跳出循环语句,为真则执行指定的语句。

    3)执行一条赋值语句来修正控制循环变量次数的变量的值,返回第二步。

    forever语句格式

    Forever 语句;

    Forever begin 多条语句 end

    forever循环语句常用于生产周期性的波形,用来作为仿真测试信号。

    它与always语句不同之处在于不能独立写在程序中,而必须写在initial块中。

    repeat语句格式

    repeat(表达式)语句

    Repeat(表达式)begin多条语句;end

    在repeated语句中,其表达式通常为常量表达式。

    while语句格式

    while(表达式)语句;

    while(表达式)begin多条语句;end

    for语句格式

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

    例子:

    用for语句来初始化memory

    begin: init_mem

    reg[7:0] tempi;

    for(tempi=0;tempi<memsize;tempi=tempi+1)

    memory[tempi]=0;

    end

    用for语句来实现乘法器。

    parameter size = 8, longsize = 16;

    reg[size:1] opa, opb;

    reg[longsize:1] result;

    begin:mult

    integer bindex;

    result=0;

    for( bindex=1; bindex<=size; bindex=bindex+1 )

    if(opb[bindex])

    result = result + (opa<<(bindex-1));

    end

    用for语句对rega这八位二进制数中的值为1的位数进行计数

    begin: count1s

    reg[7:0] tempreg;

    count=0;

    for( tempreg=rega; tempreg; tempreg=tempreg>>1 )

    if(tempreg[0])

    count=count+1;

    end

    6.顺序块和并行块

    块语句类型

    (1)顺序块(也称过程块)

    关键字begin_end

    顺序块中的语句一条条按顺序执行,只有前面语句执行完才执行后面的语句(除了带有内嵌延时控制的非阻塞赋值语句)。

    如果语句包括延时或事件控制,那么延迟总是相对于前面那条语句执行完成的仿真时间的

    (2)并行块

    关键字fork_join

    并行块内的语句是并发执行的;

    语句的执行的顺序是由各自语句内延迟或事件控制决定的

    语句中的延迟或事件控制是相对于块语句开始执行的时刻而言的。

    (3)块语句的特点

    1.嵌套式

    块可以嵌套使用,顺序块和并行块能够混合在一起使用

    2.命名块

    命名块中可以声明局部变量;

    命名块是设计层次的一部分,命名块中声明的变量可以通过层次名引用进行访问;

    命名块可以被禁用例如停止其执行。

    //命名块

    module top ;

    initial

    begin : block1 //名字为block1的顺序命名块

    integer i ; //整型变量 i 是block1命名块的静态本地变量

    //可以用层次名top.block1.i 被其他模块访问

    ...

    ...

    end

    initial

    fork : block2 //名字为block2的并行命名块

    reg i ; //寄存器变量 i 是block2命名块的静态本地变量

    //可以用层次名top.block2.i 被其他模块访问

    ...

    ...

    join

    3.命名块的禁用

    通过关键字disable提供了一种中止命名块执行的方法。disable可以用来从循环中退出、处理错误条件以及根据控制信号来控制某些代码是否被执行。对块语句的禁用导致紧接在块后面的那条语句被执行。disable则可以禁用设计中的任何一个命名块。

    //在(矢量)标志寄存器的各个位中从低有效位开始找寻第一个值为1的位

    //从矢量标志寄存器的低有效位开始查找第一个值为1的位

    reg [15:0] flag;

    integer i; //用于计数的整数

    initial

    begin

    flag = 16'b 0010_0000_0000_0000;

    i = 0;

    begin: block1 //while循环声明中的主模块是命名块block1

    while(i < 16)

    begin

    if (flag[i])

    begin

    $display("Encountered a TRUE bit at element number %d", i);

    disable block1; // 在标志寄存器中找到了值为真(1)的位,禁用block1

    end

    i = i + 1;

    end

    end

    end

    7.生成块

    生成语句可以动态的生成verilog代码。这一声明语句方便了参数化模块的生成。当对矢量中的多个位进行重复操行时,或者当进行多个模块的实例引用的重复操作时。或者在根据参数的定义来确定程序中是否应该包括某段verilog代码的时候,使用生成语句能够大大简化程序的编写过程。

    生成语句能够控制变量的声明、任务或函数的调用,还能对实例引用进行全面的控制。编写代码时必须在模块中说明生成的实例范围,用generate_endgenerate来指定该范围。

    生成实例可以是以下的一个或多种类型:

    (1)模块;

    (2)用户定义原语;

    (3)门级原语;

    (4)连续赋值语句;

    (5)initial和always块。

    verilog语言允许在生成范围内声明下列数据类型:

    (1)net(线网)、reg(寄存器);

    (2)integer(整型数)、real(实型数)、time(时间型)、realtime(实数时间型);

    (3)event(事件)。

    不允许出现在生成范围之中的模块项声明包括:

    (1)参数、局部参数;

    (2)输入、输出和输入/输出声明;

    (3)指定块。

    生成模块的实例连接方法与常规模块实例相同。

    3种创建生成语句的方法:

    (1)循环生成;

    (2)条件生成;

    (3)case生成。

    循环生成语句:

    允许使用者对下面的模块或模块项进行多次实例引用:

    (1)变量声明;

    (2)模块;

    (3)用户定义的原语、门级原语;

    (4)连续赋值语句;

    (5)initial和always块。

    例子:

    //本模块生成两条N位总线变量的按位异或

    module bitwise_xor ( out , i0 , i1 ) ;

    //参数声明语句。参数可以重新定义

    parameter N = 32 ; // 缺省的总线位宽为32位

    //端口声明语句

    output [ N-1 : 0 ] out ;

    input [ N-1 : 0 ] i0 , i1 ;

    //声明一个临时循环变量。

    //该变量只用于生成块的循环计算。

    //Verilog仿真时该变量在设计中并不存在

    genvar j ;

    //用一个单循环生成按位异或的异或门(xor)

    generate

    for ( j = 0 ; j < N ; j = j + 1 )

    begin : xor_loop

    xor g1 (out [ j ] , i0 [ j ] , i1 [ j ] ) ;

    end // 在生成块内部结束循环

    endgenerate //结束生成块

    //另外一种编写形式

    //异或门可以用always块来替代

    // reg [ N-1 : 0] out ;

    // generate

    // for ( j = 0 ; j < N ; j = j + 1 )

    // begin : bit

    // always @ ( i0 [ j ] or i1 [ j ] ) out [ j ] = i0 [ j ] ^ i0 [ j ] ;

    // end

    // endgenerate

    endmodule

    //本模块生成一个门级脉动加法器

    module ripple_adder ( co , sum , a0 , a1 , ci ) ;

    //参数声明语句,参数可以重新定义。

    parameter N = 4 ; // 缺省的总线位宽为4

    //端口声明语句

    output [ N-1 : 0 ] sum ;

    output co ;

    input [N-1 : 0 ] a0 , a1 ;

    input ci ;

    //本地线网声明语句

    wire [N-1 : 0 ] carry ;

    //指定进位变量的第0位等于进位的输入

    assign carry [0] = ci ;

    //声明临时循环变量。该变量只用于生成块的计算。

    //由于在仿真前,循环生成已经展平,所以用Verilog对

    //设计进行仿真时,该变量已经不再存在。

    genvar i ;

    //用一个单循环生成按位异或门等逻辑

    generate for ( i = 0 ; i < N ; i = i + 1 ) begin : r_loop

    wire t1 , t2 , t3 ;

    xor g1 ( t1 , a0[ i ] , a1 [ i ] ) ;

    xor g2 ( sum [ i ] , t1 , carry [ i ] ) ;

    and g3 ( t2 , a0[ i ] , a1 [ i ] ) ;

    and g4 ( t3 , t1 , carry [ i ] ) ;

    or g5 (carry [ i + 1 ] , t2 , t3 ) ;

    end // 生成块内部循环的结束

    endgenerate //生成块的结束

    // 根据上面的循环生成,Verilog编译器会自动生成以下相对层次实例名

    // xor : r_loop[0].g1 , r_loop[1].g1 , r_loop[2].g1 , r_loop[3].g1 ,

    // r_loop[0].g2 , r_loop[1].g2 , r_loop[2].g2 , r_loop[3].g2 ,

    // and : r_loop[0].g3 , r_loop[1].g3 , r_loop[2].g3 , r_loop[3].g3 ,

    // r_loop[0].g4 , r_loop[1].g4 , r_loop[2].g4 , r_loop[3].g4 ,

    // or : r_loop[0].g5 , r_loop[1].g5 , r_loop[2].g5 , r_loop[3].g5

    // 上面生成的实例用下面这些生成的线网连接起来

    // Nets : r_loop[0].t1 , r_loop[0].t2 , r_loop[0].t3

    // r_loop[1].t1 , r_loop[1].t2 , r_loop[1].t3

    // r_loop[2].t1 , r_loop[2].t2 , r_loop[2].t3

    // r_loop[3].t1 , r_loop[3].t2 , r_loop[3].t3

    assign co = carry [ N ] ;

    endmodule

    条件生成语句

    有条件的调用(实例引用)以下verilog结构:

    (1)模块;

    (2)用户定义原语、门级原语;

    (3)连续赋值语句;

    (4)initial或always块。

    例子

    // 本模块实现一个参数化乘法器

    module multiplier ( product , a0 , a1 ) ;

    //参数声明,该参数可以重新定义

    parameter a0_width = 8 ;

    parameter a1_width = 8 ;

    //本地参数声明

    //本地参数不能用参数重新定义(defparam)修改 ,

    //也不能在实例引用时通过传递参数语句,即 #(参数1,参数2,...)的方法修改

    localparam product_width = a0_width + a1_width ;

    //端口声明语句

    output [ product_width - 1 : 0 ] product ;

    input [ a0_width - 1 : 0 ] a0 ;

    input [ a1_width - 1 : 0 ] a1 ;

    //有条件地调用(实例引用)不同类型的乘法器

    //根据参数a0_width 和 a1_width的值,在调用时

    //引用相对应的乘法器实例。

    generate

    if ( a0_width < 8 ) | | ( a1_width < 8 )

    cal_multiplier # ( a0_width , a1_width ) m0 ( product , a0 , a1 ) ;

    else

    tree_multiplier # ( a0_width , a1_width ) m0 ( product , a0 , a1 ) ;

    endgenerate //生成块的结束

    endmodule

    case生成语句

    可以调用一下verilog结构

    (1)模块;

    (2)用户定义原语、门级原语;

    (3)连续赋值语句;

    (4)initial或always块。

    例子

    //本模块生成N位的加法器

    module adder ( co , sum , a0 , a1 , ci );

    //参数声明,本参数可以重新定义

    parameter N = 4 ; // 缺省的总线位宽为4

    //端口声明

    output [ N-1 : 0 ] sum ;

    output co ;

    input [ N-1 : 0 ] a0 , a1 ;

    input ci ;

    // 根据总线的位宽,调用(实例引用)相应的加法器

    // 参数N在调用(实例引用)时可以重新定义,调用(实例引用)

    // 不同位宽的加法器是根据不同的N来决定的。

    generate

    case ( N )

    // 当N=1, 或2 时分别选用位宽为1位或2位的加法器

    1 : adder_1bit adder1 ( co , sum , a0 , a1 , ci ) ; // 1位的加法器

    2 : adder_2bit adder2 ( co , sum , a0 , a1 , ci ) ; // 2位的加法器

    // 缺省的情况下选用位宽为N位的超前进位加法器

    default : adder_cla # ( N ) adder3 ( co , sum , a0 , a1 , ci ) ;

    endcase

    endgenerate //生成块的结束

    endmodule

  • 相关阅读:
    oracle 导入数据时提示只有 DBA 才能导入由其他 DBA 导出的文件
    oracle 常用语句
    android udp 无法收到数据 (模拟器中)
    android DatagramSocket send 发送数据出错
    AtCoder ABC 128E Roadwork
    AtCoder ABC 128D equeue
    AtCoder ABC 127F Absolute Minima
    AtCoder ABC 127E Cell Distance
    CodeForces 1166E The LCMs Must be Large
    CodeForces 1166D Cute Sequences
  • 原文地址:https://www.cnblogs.com/CXATG/p/2594938.html
Copyright © 2020-2023  润新知