查看: 26|回复: 0

verilog 语法基础汇总

[复制链接]
  • TA的每日心情

    2024-11-15 16:19
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    292

    主题

    26

    回帖

    2978

    积分

    管理员

    积分
    2978
    发表于 2024-11-15 11:53:27 | 显示全部楼层 |阅读模式
    一.Verilog语法基础

    1. 逻辑值



            0:逻辑低电平,条件为假



            1:逻辑高电平,条件为真



            z:高阻态,无驱动

            x:未知逻辑电平



    2. 归约运算符,按位运算符

            以&为例,当&作为一元运算符时表示归约与,&m是将m中所有比特位相与,最后的结果为1bit



            例如:



                    &4'b1111=1&1&1&1=1'b1



                    &4b'1101=1&1&0&1=1'b0



            当&作为二元运算符时表示按位与,m&n是将m的每个比特位与n的相应比特位相与,在运算时要保证m和n的比特位数相等,最后的结果与m和n的比特位数相同



            例如:



                    4b'1010&4b'0101=4b'0000



                    4b'1101&4b'1111=4b'1101



            其它例如'~&' , '^' , '~^' , '|', '~|' 在分别作为一元和二元运算符时也有和'&'一样的性质



    3. 逻辑运算符和关系运算符

            具有'&&'形式的操作符表示逻辑与



            例如:



                    a=a'ha, b=4'd0, c=a&&b  运算结果是c=0



            关系运算符(逻辑运算符)的使用方法和C语言完全类似



    4. 移位运算符



            移位运算符时二元运算符,左移符号为'<<',右移符号为'>>',结果是将运算符左边的操作数左移或右移指定的位数,用0来填补空位。



            b <= a<<1;   #作用是将a的每一位都向左移动1位,结果赋值给b



            b <= a>>2;   #作用是将a的每一位都向右移动1位,结果赋值给b



    需要注意的是:



            1)移位运算造成的空位自动用0来填充,因此任意一个二进制数只要一直移位其值最终都会变成0。



            例如: a=4'b1000,  a>>3的结果为 4'b0001;a>>4的结果为4'b0000



            2)移位运算符在使用时可代替乘法和除法,左移一位看作是乘以2,右移移位可以看作是除以2,但是仍然要注意位宽的拓展。



    5.位拼接运算符



            位拼接运算符由一对花括号加逗号组成,形式为’{  , }', 拼接的不同数据之间用','隔开。



            例如:



                    将8bit的a、3bit的b、5bit的c按顺序拼接成一个16位的d,表示方法为:d={a,b,c};



    6. 条件运算符



            一般格式:(逻辑判断语句)? 语句1 : 语句2



            执行过程是:当[逻辑判断语句]为真,则[语句1]作为条件表达式的值,否则将[语句2]作为表达式的值。



            例如: a=6, b=7, c=(a>b)?a:b 语句执行后c=7



    7. 运算符优先级



            归约运算符 > 算术运算符 > 移位运算符 > 关系运算符 > ’==‘ 和'!='  >  按位运算符  >  '&&' 和 '||' > 条件运算符



            归纳起来就是一元运算符 > 二元运算符 > 三元运算符。



            运算符优先级往往不需要准确**,通过括号增加优先级是更为简单且准确的方法。

    8. case分支语句



            格式:



                    case(<控制表达式>)



                            <分支语句1> : 语句块1;



                            <分支语句2> : 语句块2;



                             ......



                            <分支语句n> : 语句块n;



                            default : 语句块n+1;



                    endcase                                #这行不要漏写



            注意:



                    1)在执行了某一分支项内的语句后,跳出case语句结构,终止case语句执行。



                    2)case语句中的各个<分支语句>中表达式取值必须是互不相同的。



    二. 系统函数

    定义:Verilog语言中预先定义了一些任务和函数,用于完成一些特殊的功能,它们被称为系统任务和系统函数。这些函数大多数都是只能在Testbench仿真中使用的,使得用户可以更方便地进行验证。



    1.timescale函数



            格式: 'timescale   1ns/1ns   #时间尺度预编辑指令  参数对应  时间单位/时间精度



            其中时间单位和时间精度由值为1、10、100以及单位s, ms, us, ns, ps, fs 组成。



            时间单位:定义仿真过程所有与时间相关量的单位。



            仿真中使用"#数字"格式表示延时相应时间单位的时间,例如在前面设定的时间单位和精度前提下"#10"表示延时10个时间单位,也就是10ns



            时间精度:决定时间相关量的精度以及仿真显示的最小刻度。



            例如:



                    `timescale 1ns/10ps   表示的精度为0.01ns, #10.11表示延迟10110ps



                    很重要的一点:timescale前面的符号是键盘左上角的,千万不要写成单引号!



            注意:在使用timescale函数时要保证时间单位大于时间精度



                    'timescale  100ps/1ns 这样的写法就是错误的



    2.display函数



            功能:用来输出、打印信息



            格式:$display("%b+%b=%d",a,b,c);        #"%b+%b=%d"用于输出格式控制,未指定时默认为十进制



            %h或%H    以十六进制格式输出



            %d或%D    以十进制格式输出



            %o或%O    以八进制格式输出



            %b或%B    以二进制格式输出



            注意:每次输出结束后自动换行



    3.write函数



            功能:用于输出、打印信息



            格式:$write("%b+%b=%d\n",a,b,c);        #其中控制参数的用法同display函数



            注意: $write函数每次输出结束后不会自动换行,换行需要搭配"\n"实现。



    4.strobe函数



            功能和用法与display和write相同,区别在于$strobe函数不论被置于程序中什么位置都是固定放在最后执行,其中变量参数也都是程序执行到最后的值。并且会自动换行。



    5.monitor函数



            功能和用法与display和write相同,区别在于每改变$monitor中参数的值时就会打印一次。自动换行。



    6.stop和finish函数



            $stop用于暂停仿真,$finish用于结束仿真



    7. time和random函数



            功能:$time为时间函数,返回64位当前仿真时间;$random用于产生随机函数,返回随机数



    8.readmemb/readmemh函数



            功能:$readmemb和$readmemh分别用于读取二进制和十六进制文件



            格式: $readmemb("<数据文件名>",<存储器名>);



                    例如:$readmemb("test.txt",a);



    三. 关键字

    1. module(模块开始)---endmodule(模块结束)



           格式: module exmaple



    2. input(输入)/input(输出)



            input   wire    sys_cik,               #这里注意每一个参数定义要加‘,’而定义语句结尾没有



            input   wire    sys_rst_n,



            inout   wire    sda,                     #inout定义的信号可同时用于输入或输出



            output  wire    po_flag



    3. 变量类型



            1)线网型变量: wire                #在系统中会被直接认为具有一条物理连线



            2)寄存器型变量: reg        #对某一时间点的状态进行保存,在系统中会被认为是寄存器



                  格式: reg [7:0] a [20:0];   #表示定义一个名为a,位宽为8bit,深度为21的寄存器变量



            两种变量类型的使用场景:



                    1. 当使用always语句给变量赋值时,要用reg型



                    2. 当使用assign语句给变量赋值时,用wire型。assign可以视为在电路中添加一条连线。



    4.参数



            1)parameter



                   格式: parameter   CNT_MAX = 100;



                    特性:实例化时参数可修改



            2)localparam



                    格式:localparam   CNT_MAX = 100;



                    特性:只能在模块内部使用,不能实例化



    5.常量(基数表示法)



            格式:[换算为二进制后位宽的总长度]['][数值进制符号][与数值进制符号相对应的应的数值]



            其中:[数值进制符号]:[h]表示十六进制,[o]表示八进制,表示二进制



            例如: 8'd171 : 位宽是8bit,十进制的171



                        8'hab : 8bit的十六进制数ab



                        8'o253 : 8bit的八进制数253



                        8‘b1010_1011 : 8bit的二进制数1010_1011   #二进制数可以用下划线分割增强可读性



            [换算为二进制后位宽的总长度]这一项可有可无,verilog会自动为常量匹配合适的位宽。 当总位宽大于实际位宽,则自动在左边补0,总位宽小于实际位宽则自动截断左边超出的位数



            例如:'d7与8'd7表示相同数值,8'd7换算为二进制是8'b0000_0111,前五位补0



                       2'd7换算为二进制是2'b11,超过2位宽的部分被截断   #这里的截断是从右往左进行的



            注意:如果直接写参数,例如100,表示位宽为32bit的十进制数100        



    6.赋值



            1)阻塞赋值(“=”)



                    内部语句同时并行执行



            2)非阻塞赋值(“<=")



                   程序从上到下顺序执行赋值语句



    注意一些问题:



            1.阻塞赋值电路结构与时钟触发沿没有关系,只与输入电平的变化有关。阻塞赋值语句是顺序执行的,先计算赋值符号右边的语句并更新赋值号左边的语句,此时不允许有来自其他任何语句的干扰,直到现行的赋值完成,才允许下一条赋值语句的执行。



            2.非阻塞赋值的电路结构与时钟触发沿有关系,只有触发沿时刻才进行相应的非阻塞赋值。非阻塞赋值语句是并行执行的,先计算所有非阻塞赋值号右边的语句再同时进行向左赋值,这期间允许其他语句进行操作。



            3.非阻塞赋值只能用于对寄存器变量进行赋值,因此只能能用于‘inital’和‘always’块中(敏感列表要采用电平触发方式/敏感列表.关于Modelsim仿真的一点提示:



            如果Modelsim报错error loading design 则最常用的解决办法是返回检查tb文件中的文件名是否与仿真项目名一致。就是always@(这里)的语句),不允许用于连续赋值‘assign’中。



            4.时序逻辑电路中推荐使用非阻塞赋值,方便实现时钟边沿触发。



            5.一个语句块中不要同时用阻塞和非阻塞赋值。同时推荐一个always语句块只对一个变量进行赋值。



            6.使用锁存器(latch)要采用非阻塞赋值。

    三、关于Modelsim仿真的一点提示:



        如果Modelsim报错error loading design 则最常用的解决办法是返回检查tb文件中的文件名是否与仿真项目名一致。

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    友情链接:

    返回顶部 返回列表