zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    pagic Deno + React 驱动的静态网站生成器 入门
    antd Form.Item label添加解释信息
    deno可以通过url引入标准库,运行时自动下载,下载到哪里呢
    如何查看github开源项目star趋势
    使用deno开发post请求,get请求,监测文件变化自动重启(类似于nodemon)
    windows安装deno
    react 轮播图 react-slick
    display:flex 元素垂直居中,有间距,右对齐
    Java对map键名进行顺序排序后转为字符串
    IDEA快捷键大全
  • 原文地址:https://www.cnblogs.com/CXATG/p/2594938.html
Copyright © 2011-2022 走看看