明德扬吴老师 发表于 2020-3-2 12:13:33

【原创】你必须要掌握的 Verilog语法知识点 | Verilog语法笔记私人总结版

作者:轩工
本文为明德扬原创及录用文章,转载请注明出处!
1.1 概述
条目说明
分类1>>面向设计的语句;//可综合。2>>面向测试的语句; //testbench,不可综合。
特点设计语句assign, always,模块例化,都对应实际电路,并行执行。
构造

1.2 模块Module
条目说明
模块名(端口列表)整个电路的外特性,抽象为黑盒子;
端口方向input,output;inout;
端口类型wire,reg;端口类型是wire时可以省略。例:input a; //端口方向为输入,类型默认为wire;



1.3 数据类型1.3.1 wire/reg线网wire和reg都是线类型,工程上没区别;只是always/initial模块中输出定义需要为reg型;注意:不要将reg类型与D触发器混淆,reg理解为因为代码所产生的。例如:

wire a;//定义了8位的wire型数据wireb;   // 定义了1位的wire型数据
reg sum;//定义了一个4位的reg型数据

1.3.2 常量
类型格式说明
parameterparameter数据名= 表达式parameterMSB = 7;
//定义参数MSB为常量7;推荐大写;
常量<位宽><进制><数字>二进制:B或b;十进制:D或d;八进制:O或o;
十六进制:H或h;8’b1010_1100 (‘b表示二进制)
下画线“_”,提高阅读性。
<数字>默认十进制;
4值逻辑0:Logic Low低电平;
1:Logic High高电平;
x:Unknow;不确定;
z:High Impedance;高阻态; //三态门

1.4 运算符1.4.1 概述
运算符说明
算术运算符+(加),-(减),*(乘),/(除),%(取模);
每个运算符在电路中都是个模块,如加法器,减法器;!注意:除法,除2^n,是移位运算,浮点运算就复杂了,因此浮点运算要专用除法器;
关系运算符>, <, >=, <=,==(相等), !=(不相等);
逻辑运算符&&(逻辑与). ||(逻辑或), !(逻辑非);条件判断语句中,为避免歧义,逻辑运算符二边推荐为1bit;
位运算符&(与),|(或), ~(非), ^(异或); ~^(同或);
移位运算符<<(左移),>>(右移);
归约操作&,~&, |, ~|,^, ~^;//unary reduction;
条件运算符?:
拼接运算符{}//{3{a}}:代表3根同样的a线,{a,a,a}

1.5 设计语句1.5.1 assign(连续赋值)
实例说明
assigny   = ~ b;assign out = a==1 && c==1;assign f = sel?a:b;>>实现可以用布尔函数描述的组合逻辑电路;
>>“=”后面可以是任何布尔函数;>>并行执行;
典型错误1:assigna = b + a;避免出现反馈电路:变为了不可知时序逻辑电路;


1.5.2 always(过程块)赋值
赋值方式说明
=,阻塞赋值always @(a or b or C or …)begin语句块(=, if语句, case语句)end
实现:组合逻辑电路;(注意!禁止用于时序逻辑电路)always块内,阻塞赋值:是顺序执行(类似C);
敏感表:@(*) //“*”自动添加相关输入信号;
避免出现Latch(锁存器)分支语句(if语句,case语句)条件不满时,会在电路中自动生成锁存器来保存不满足条件的值,因此要补全if-else,和case的defalut语句;
<=,非阻塞赋值always @(posedge clk or negedge rst_n)begin语句块(<=, if语句, case语句)end
实现:时序逻辑电路;(注意!禁止用于组合逻辑电路)always块内,阻塞赋值:并行执行;

if语句
条目说明
格式1if(条件)begin      语句1;      语句2;endelse begin      语句1;      语句2;end
格式2if(条件)begin      语句1;      语句2;endelse if begin      语句1;      语句2;endelse begin      语句1;      语句2end
特点分支语句,各个分支条件不同;顺序执行判断;
注意if-else成对使用;

case语句
条目说明
格式case(表达式)常量表达式1:begin语句;      end常量表达式2:begin语句;      end常量表达式3:begin语句;      end       default:语句;endcase
特点分支语句,各个分支条件相同;并行执行判断;
注意default语句不可省略;


代码&硬件
条目说明
映射赋值语句 ->逻辑函数; //加法器,减法器等;
边沿型条件分支 -> D触发器;
条件分支 ->多路选择器;
示例

1.5.3 模块例化作用系统设计时,建议遵循以下设计原则:
常见的典型错误如下所示:

1.5.4 全加器
全加器顶层:w1,w2,w3:模块之间连线;
半加强:2种描述方法,如下:

描述方式
描述方式说明
位置关联AND u1(a, b, and_out);
名字关联AND u1(.a(a), .b(b), .o(and_out)); //推荐使用


1.6 测试语句1.6.1 结构
Testbench




1.6.2 特殊符号
语句说明
`<标识符>表示:编译引导语,用于指导仿真编译器在编译时采取一些特殊处理;编译引导语句一直保持有效,直到被取消或重写;
`timescale`timescale <时间单位>/<时间精度>例1:`timescale 1ns/1ns//时间单位1ns;时间精度1ns;#2    //延时2 ×1=2ns;#2.1//延时2.1 × 1 = 2.1ns,精确到1ns,为2ns;例2:`timescale 1ns/100ps//时间单位1ns;时间精度100ps;#2    //延时2 ×1= 2ns;#2.1//延时2.1 × 1 = 2.1ns,精确到100s,为2.1ns;
`define

`include`include “global.v”包含另一个文件,完整拷贝过来;
`restall把所有设置的编译引导恢复到缺省状态;


#<num>;#10; //延迟10个时间单位

1.6.3 语句
语句说明
initial块语句:只执行一次,always循环执行;不可综合;
作用:产生激励信号;检查输出波形;赋初值;
forever//产生周期信号:intial beginclk = 0;forever #10 clk = ~clk;//时钟信号end

1.6.4 系统任务和函数
条目说明
$<标识符>表示Verilg的系统任务和函数
$time当前的仿真时间
$display显示信号值变化:只执行一次,打印当前时刻;$display($time, “b% %b %b”, rst,clk,dout);
$monitor监视信号值变化:所有过程时刻;$monitor($time, “b% %b %b”, rst,clk,dout);
$stop暂停仿真
$finish结束仿真,释放电脑资源;

1.7 代码模板1.7.1 组合逻辑电路
条目说明
assignassign add_cnt = flag==1; //用于简单的组合逻辑电路;
alwaysalways@(*)begin//统一采用“*”为敏感列表;(=,if,case)语句;//只能使用“=”赋值end
1.7.2 时序逻辑电路计数器模板1
3段式模板模板1
1计数段always @( posedge cllk or negedge rst_n) beginif (!rst_n)   cnt <= 0;         //初值规定为0else if (add_cnt)begin//【位置1】if(end_cnt)            cnt <= 0;else               cnt <= cnt + 1; endend
2加1条件assingadd_cnt = d==1;   //d==1: 什么时候开始数脉冲
3结束条件assing end_cnt = add_cnt&& cnt == X-1; // X:数多少个脉冲
计数器模板2
3段式模板模板1
1计数段always @( posedge cllk or negedge rst_n) beginif (!rst_n)   cnt <= 0;         //初值规定为0else if (add_cnt)begin//【位置1】if(end_cnt)            cnt <= 0;else               cnt <= cnt + 1; endelse cnt <= 0;    //不连续,需要清0时,使用模板2;end
2加1条件assingadd_cnt = d==1;   //d==1: 什么时候开始数脉冲
3结束条件assing end_cnt = add_cnt&& cnt == X-1; // X:数多少个脉冲

模板4段式状态机
段号代码
1// 初始化,次态赋值给现态,明确当前状态;always @(posedge clk or negedge rst_n) begin    if(!rst_n)      state_c <= S00;//初始状态    else       state_c <= state_n;end
2always @( * ) begin//组合逻辑,描述状态转换目标    case(state_c)S00: begin            if(s00_s20_start)// 条件名 S00->S20                state_n = S20;            else                state_n = state_c; // 方便拷贝      endS20: begin            if(s20_s21_start)                state_n = S21;            else                state_n = state_c;      endS21: begin            if(s21_s00_start)                state_n = S00;            else                state_n = state_c;      enddefault: begin            state_n = S00;      end    endcaseend
3//具体的转换条件内容assign s00_s20_start = state_c==S00&& (条件);assign s20_s21_start = state_c==S20&& (条件);assign s21_s20_start = state_c==S21&& (条件);
4根据转态设计输出:1个 always 设计1个输出信号;



1.7.3 Testbench框架
条目内容
模块名`timescale 1 ns/1 nsmodule testbench_name();
信号定义reg clk;//时钟reg rst_n;//复位regdin0; //uut的输入信号 ,定义为reg型,在initial中reg       din1;wire      dout0;//uut的输出信号, 定义为wire型wire dout1;parameter CYCLE    = 20; //参数定义,方便修改;parameter RST_TIME = 3 ;
待测模块例化module_name uut(   //统一采用名字关联       .clk          (clk   ),        .rst_n      (rst_n   ),       .din0         (din0    ),       .din1         (din1    ),       .dout0      (dout0   ),       .dout1      (dout1   ));
激励产生//复位,时钟 ,等
显示输出结果$display   //类似printf;


复位
复位
initial begin       rst_n = 1;       #2;       rst_n = 0;       #(CYCLE*RST_TIME);       rst_n = 1; end

仿真时钟
仿真时钟
initial begin    clk = 0;   forever   #(CYCLE/2)   clk=~clk; end


激励信号
激励信号
initial begin      #1;//方便观测      din1 = 0; //赋初值      #(10*CYCLE);//开始赋值 end

以上就是本人总结的Verilog语法相关知识点,当然明德扬还有很多比较简便的模板给我们使用,感兴趣的朋友可以进入明德扬论坛(http://www.fpgabbs.cn/)进行更多FPGA 或者语法相关讨论!

lililala6868 发表于 2021-1-21 19:11:52

对学习有帮助 非常不错,谢谢
页: [1]
查看完整版本: 【原创】你必须要掌握的 Verilog语法知识点 | Verilog语法笔记私人总结版