• Verilog HDL基础语法


    Verilog HDL基础语法

    语言简介

    verilog HDL是一种硬件描述语言,以文本形式来描述数字系统硬件的结构和行为的语言,用它可以表示逻辑电路图、逻辑表达式,还可以表示数字逻辑系统所完成的逻辑功能。

    与VHDL比较

    |verilog HDL|VHDL |
    |语言自由、易学易用|语法严谨、较难上手|
    | 适合算法级、门级设计 |适合系统级设计 |
    |代码简洁 | 代码冗长 |
    |发展较快 | 发展缓慢 |

    基础语言学习

    1】逻辑值
    0:逻辑低电平,条件为假
    1:逻辑高电平,条件为真
    z:高阻态,无驱动
    x:未知逻辑电平

    2】关键字
    module:模块开始
    endmodule:模块结束
    input:输入信号
    output:输出信号
    inpout:双向
    wire:线网型变量
    寄存器变量:reg

    //参数
    parameter:在顶层文件通过实例化来对子功能模块中的参数进行修改
    localparam:只能在模块内部使用,不能实例化

    //常量
    基数表示法
    格式:
    【换算后的二进制位宽的总长度】【'】【数值进制符号】【与数值进制符号对应的数值】
    8’d171:位宽为8bit,十进制的171
    h:十六进制
    o:八进制
    b:二进制
    8’hab:表示8bit的十六进制数ab
    8’o253:表示8bit的八进制数253
    8’1011—1011表示8bit的二进制数1011—1011,下划线增强可读性
    【换算后的二进制位宽的总长度】:可有可无,verilog会未常量自动匹配合适的位宽,当总位宽大于实际位宽,则自动在左边补0,总位宽小于实际位宽,则自动截取左边超出的位数。
    'd7与8’d7:表示相同数值,8’d7换算为二进制就是8’b0000_0111,前面5位补0
    2’d7换算成二进制就是2’b11,超过2位宽的部分被截取。
    如果直接写参数,例如100,表示位宽为32bit的十进制数100

    //阻塞赋值
    顺序执行,第一句执行完毕才会执行第二句
    a =1;
    b=2;
    c=3;
    begin
    a=b;
    c=a;
    end
    a=2;
    b=2;
    c=2;

    //非阻塞赋值
    a =1;
    b=2;
    c=3;
    begin
    a<=b;
    c<=a;
    end
    结果:
    a=2;
    b=2;
    c=1;

    //always语句
    一般always语句可以分为两类电路。一种是组合逻辑。一种是时序逻辑。

    第一类:组合逻辑

    //-----1.1 组合逻辑 --------

    Always @ (*)
    Begin
    If(a>b)
    Q = 1;
    Else
    Q = 0;
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    //------- end -------------//

    如1.1所示,就是一个简单的组合逻辑always块,它应该是被综合成一个一位的比较器。

    //---- 1.2 组合逻辑 缺少敏感信号 ------

    Always @ (a)
    Begin
    If(a>b)
    Q = 1;
    Else
    Q = 0;
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    //------- end -------------//

    代码 1-2 也是一个组合逻辑,与 1-1 不同的是,敏感信号列表中只有a没有 b。

    我们知道,在 Verilog 语法中, always 块的含义是一个重复执行的语句。

    那么 1-2 会综合成一个比较器:

    当 a 发生变化时,q 发生变化
    当 b 发生变化,由于 b 不再敏感信号列表中,所以 q 不变
    这是一个彻头彻尾的软件思维,世界上不存在这种电路,综合器多半会综合一个与代码 1-1 一样的电路,然后报一个警告。

    编写组合逻辑的 always 块,使用 * 代替敏感信号列表是一个简单方便而且不容易出错的好办法。
    第二类:时序逻辑
    //----- 2-1 时序逻辑 -------

    reg [1:0] q;
    always @ (posedge clk)
    begin
    q <= q + 1'b1;
    End
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:这里使用的是阻塞赋值,我们的 q 这个时候被综合成一个寄存器,而不是一个软件上的变量。

    代码 2-1 是一个时序逻辑单元,它应该被综合成一个计数器,每当时钟的上升沿,q 自增一

    // 2-2 时序逻辑 ,带异步复位

    reg [1:0] q;
    always @ (posedge clk or negedge rst_n)
    begin
    if(!rst_n)
    q <= 2'b00;
    else
    q <= q + 1'b1;
    End
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    always语句注意点:
    1、不要在不同的always块内为同一个变量赋值。即某个信号出现在<=或者=左边时,只能在一个always块内。
    2、不要在同一个always块内同时使用阻塞赋值(=)和非阻塞赋值(<=)。
    3、在使用always块描述组合逻辑时使用阻塞赋值(=);使用always块描述时序逻辑时使用非阻塞赋值(<=)。
    4、任何在always块内被赋值的变量都必须是寄存器型(reg)。
    5、always的敏感列表中可以同时包括多个电平敏感事件,也可以包括多个边沿敏感事件,但不能同时有电平和边沿敏感事件。另外,在敏感列表中,同时包括一个信号的上升沿敏感事件和下降沿敏感事件是不容许的,因为这两个事件可以合并为一个电平事件。

    //assign语句
    赋值语法以关键字assign开头,后面是信号名,可以是单个信号,也可以是不同信号网的连接。驱动强度和延迟是可选的,主要用于数据流建模,而不是综合到实际硬件中。右侧的表达式或信号被分配给左侧的网或网的表达式。
    语法结构如下:

    assign <net_expression> = [drive_strength] [delay] <expression of different signals or constant value>
    
    • 1

    延迟值对于指定门的延迟很有用,并用于模拟实际硬件中的时序行为,因为该值决定了何时应该用评估值分配网。

    使用 assign 语句时, 需要遵循一些规则:
    LHS(左值) 应该始终是wire类型的标量或向量网络, 或者标量或矢量网络的串联, 而绝对不能是reg类型的标量或矢量寄存器。
    RHS 可以包含标量或向量寄存器以及函数调用。
    只要 RHS 上的任何操作数的值发生变化, LHS 就会使用新值进行更新。
    assign 语句也称为连续赋值, 并且始终处于活动状态。

    2】算数运算符
    加减乘除求余

    3】规约运算符\按位运算符
    以“&”操作符为例,“&”操作符有两种途径,既可以作为一元运算符(仅有一个参与运算的量),也可以作为二元运算符(有两个参与运算的量)
    例如:
    &4’b1111 = 1&1&1&1=1’b1
    &4’b1101 = 1&1&0&1=1’b0
    &4’b1010&&4’b0101 =&4’b0000
    &4’b1101&&4’b1111 =&4’b1101
    当“&”作为二元运算符是表示按位与,m&n是将m的每个比特与n的相应比特相与,在运算的时候要保证m和n的比特数相等,最后的结果和m(n)的比特数相同
    &”、“^”、‘^’、“|”、“~|”同理

    4】逻辑运算符
    “&&”:逻辑与
    “||”:逻辑或
    “==”:逻辑相等
    “!|”:逻辑不等

    5】关系运算符

    a<b  a小于b
    a>b  a大于b
    a<=b  a小于等于b
    a>=b  a大于等于b
    
    • 1
    • 2
    • 3
    • 4

    注:关系运算符一般在条件判断时用到,例如if的判断语句,如果if后面接的判断语句

    6】移位运算符
    移位运算符是二元运算符,左移符号为“<<”,右移符号为“>>”,将运算符左边的操作数左移或右移指定的位数,用0来补充空闲位。
    b<= a<<1 //即让a的每一位都往左移动1位,结果赋值给b
    b<= a>>2 //让a的每一位都往右移动2位,结果赋值给b

    在应用移位运算符的时候,一定要注意它的这个特性,那就是空闲位用0来填充,也就是说,一个二进制不管原数值是多少,只要一直移位,最终都会变为0

    7】位拼接运算符
    位拼接运算符由一对花括号加逗号组成“{}”,拼接不同的数据之间用“,”隔开。
    例如
    将8bit的a,3bit的b,5bit的c按顺序拼接成一个16bit的d,表示方法为:d={a,b,c}

    8】条件运算符
    条件运算符,“?:”,是一个三元运算符,即有三个参与运算的量,条件表达式的一般形式为:表达式1?表达式2:表达式3
    执行过程:当表达式1位真,则表达式2作为条件表达式的值,否则以表达式3作为条件表达式的值
    要注意的是,使用条件表达式时,“?”和“:”是一对,不可以只用一个
    9】优先级
    总的优先级关系为:
    规约表达式>算数运算符>移位运算符关系运算符>“==”和“!=”>按位运算符>“&&”和“||”,总的来说,就是一元运算符>二元运算符>三元运算符

    10】if-else条件分支语句
    if-else条件分支语句的作用是根据指定的判断条件是否满足来确定下一步要执行的操作,它在使用时可以采用如下三种形式:
    (1)
    if(<条件表达式>)
    语句或语句块
    这种用法如果在always语句块表达组合逻辑时会产生latch,所以不推荐这种写法

    (2)
    if(<条件表达式>)
    语句或语句块1
    else if(<条件表达式>)
    语句或语句块2

    else
    (3)
    if(<条件表达式1>)
    if(<条件表达式2>)
    语句或语句块1
    else
    语句或语句块2
    else
    语句或语句块3
    verilog HDL允许if-else条件分支语句的嵌套使用,但是不要嵌套太多层,也不推荐这种嵌套的写法,因为嵌套会有优先级的问题,最后导致逻辑混乱,if和else的结合混乱,代码也不清晰,如果写代码时遇到这种情况往往可以将其合并,最终写成(2)的形式。

    11】case分支控制语句
    case分支语句通常用于对微处理器指令译码功能的描述以及对有限状态机的描述。case分支语句有“case”“casez”“casex”三种形式
    case(<控制表达式>)
    <分支语句1>:语句块1
    <分支语句2>:语句块2
    <分支语句3>:语句块3

    <分支语句n>:语句块n
    default :语句块n+1
    endcase

    #系统函数
    verilog语言中预先定义了一些任务和函数,用于完成一些特殊的功能,它们被称为系统任务和系统函数,这些函数大多数都是只能在testbench仿真中使用的,使我们更方面的进行验证。
    'timescale 1ns/1ns //时间尺度预编译指令 时间单位/时间精度
    仿真中使用“#数字”表示延时相应时间单位的时间
    时间精度:决定时间相关量的精度及仿真显示的最小刻度

    $disply //打印信息,自动换行
    使用格式:
    $display(“%b+%b=%d”,a,b,c)//格式控制,未指定时默认十进制
    %h 或% H //以十六进制的形式输出
    %d 或% D //以十进制形式输出
    %o 或% O //以八进制形式输出
    %b 或% B //二进制形式输出
    每次打印信息后自动换行

    $write //打印信息
    使用格式:
    $write(“%b+%b=%d”,a,b,c)//格式控制,未指定时默认十进制
    %h 或% H //以十六进制的形式输出
    %d 或% D //以十进制形式输出
    %o 或% O //以八进制形式输出
    %b 或% B //二进制形式输出
    /n 换行

    $strobe //打印信息,自动换行,最后执行

    $monitor //监测变量
    $monitor (“%b+%b=%d”,a,b,c)//格式控制,未指定时默认十进制
    %h 或% H //以十六进制的形式输出
    %d 或% D //以十进制形式输出
    %o 或% O //以八进制形式输出
    %b 或% B //二进制形式输出
    /n 换行
    //a、b、c输出列表,需要输出信息的变量
    //被测变量变化触发打印操作,自动换行

    $stop /暂停仿真
    $finish //结束仿真
    $time //时间函数
    $random //随机函数
    $readmemb //读文件函数

  • 相关阅读:
    生产环境部署Nginx服务器双机热备部署-keepalived(多种模式教程)
    gorm的简单操作
    数码好物推荐,双十一好物选购攻略
    无线通信与编码_MATLAB实现Turbo码的仿真_含仿真代码_Dr.WuYufei
    Informatica使用操作流程及Expression(表达式转换)案例2
    关于CSS 盒子模型的基础教程
    BLDC电机控制算法例程
    Vue--》过滤器介绍及其使用方法
    Leetcode39.组合总和
    Spring 中 Bean 对象的存储和取出
  • 原文地址:https://blog.csdn.net/liulangqingchun444/article/details/126697561