Verilog基础语法
- 1. 常用关键字/保留字
- 模块 module endmodule
- 输入输出信号 input output inout
- 变量 wire reg
- 参数 parameter localparam
- 常数
- 赋值
- always
- assign
- 运算符
- 归约运算符、按位运算符
- 逻辑运算符
- 关系运算符
- 移位运算符
- 位拼接运算符
- 条件运算符
- 优先级
- 分支控制语句
- if-else
- case
- 系统函数
1. 常用关键字/保留字
.main文件速览
module example //模块开始 模块名
{input wire sys_clk , //输入信号input wire sys_rst_n , //输入信号inout wire sda , //输入输出信号output wire po_flag //输出信号
};//线网型变量
wire [0:0] flag ;//寄存器型变量
reg [7:0] cnt;//参数
parameter CNT_MAX = 100;
localparam CNT_MAX = 100;//模块实例化
example
#(.CNT_MAX (8'd100) //实例化时参数可修改
)//always
always (posedge sys_clk or negedge sys_rst_n)if(sys_res_n == 1'b0)cnt <= 8'd0;else if (cnt == CNT_MAX)cnt <= CNT_MAX;else cnt <= cnt + 8'd1;//assign
assign po_flag = (cnt == CNT_MAX) ? 1'b1 : 1'b0;endmodule
模块 module endmodule
- 用
module
表示模块的开始,模块有开始就有结束。 - 用
endmodule
表示模块的结束。 - 模块开始后需要写入模块名,模块名一般与.main文件一致
输入输出信号 input output inout
- 输入信号:
input
- 输出信号:
output
- 既可以做输入信号也可以做输出信号:
inout
变量 wire reg
输入信号需要不能直接变成输出数据,需要经过变量之间的操作修改。
- 线网型变量
- 用
wire
申明 - 可以看成实际的连接,在物理实验中会看成一条真实的连线
- 用
- 寄存器型变量
- 用
reg
申明 - 具有对某一数据保留的功能
- 会被映射成为一个真实的物理寄存器
- 用
参数 parameter localparam
有两个关键字可以用来定义参数。
parameter
可以在顶层文件通过实例化对此功能模块中的参数进行修改localparam
只能在模块内部使用,不能实例化。
常数
- 使用基数表示法
- 格式 :[换算为二进制后位宽的总长度]['][数值进制符号][与数值进制符号对应的数值]
eg. 8'd171 //位宽为8bit,十进制的171
- [数值进制符号] :[h]十六进制、[o]八进制、[b]二进制
8'hab //8bit的十六进制数ab 8'o253 //8bit的八进制数253 8'b1010_1011 //8bit的二进制数1010_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、c被赋值是同时执行的,最终得到的结果为
a = 2;
b = 2;
c = 1;
always
always (posedge sys_clk or negedge sys_rst_n)if(sys_res_n == 1'b0) //当复位信号有效时cnt <= 8'd0; //cnt初值设置为0else if (cnt == CNT_MAX) //如果计数到最大值cnt <= CNT_MAX; //cnt保持在最大值else cnt <= cnt + 8'd1;//否则每一个时钟周期cnt++
assign
assign po_flag = (cnt == CNT_MAX) ? 1'b1 : 1'b0;
//如果满足括号内条件,则将1'b1赋值给po_flag,反之将1'b0赋值给po_flag;
运算符
归约运算符、按位运算符
以’'&"为例:
- 作为一元运算符
表示归约&m
表示将m中所有比特相与,最终的结果为1bit。&4'b1111 = 1&1&1&1 = 1'b1 &4'b1101 = 1&1&0&1 = 1'b0
- 作为二元运算符
表示按位与,m&n
将m的每个比特与n的相应比特相与,运算的时候需要保证m和n的比特数相等,最后的结果和m(n)的比特数相同。4'b1010 & 4'b0101 = 4'b0000 4'b1101 & 4'b1111 = 4'b1101
逻辑运算符
"&&“逻辑与、”||“逻辑或、”==“逻辑相等、”!="逻辑不等
关系运算符
<、>、<=、>=,一般用于条件判断语句
移位运算符
- 左移"<<",将运算符左边的操作数左移指定的位数,用0补充空闲位。
b <= a<<1
a左移1位,结果赋值给b - 右移">>",将运算符右边的操作数右移指定的位数,用0补充空闲位。
b <= a>>2
a右移2位,结果赋值给b - 注意:因为会用0填充,一个二进制数一直移位最终全部会变成0
- 可以代替乘除法使用,<<1看成*2,>>1 看成/2,但需要注意位宽的扩展
位拼接运算符
格式:{ ,}
拼接不同的数据之间用","
隔开。bit
eg.将8bit的a、3bit的b、5bit的c 按顺序拼接成一个16bit的d d = { a, b, c} ;
条件运算符
? :
是一个三元运算符,格式:表达式1 ? 表达式2 : 表达式3
- 执行过程:if(表达式1) 表达式2作为条件表达式的值,else 表达式3作为条件表达式的值。
eg.a = 6, b = 7, c = ( a > b ) ? a : b
最终得到c=7
优先级
归约运算符 > 算术运算符 > 移位运算符 > 关系运算符 > “==” “!=” > 按位运算符 > “&&” “||” > 条件运算符
一元运算符 > 二元运算符 > 三元运算符
分支控制语句
if-else
与C++相同
case
case分支语句有"case"、“casez”、"casex"三种
case (<控制表达式>)<分支语句1> : 语句块1 ;……<分支语句n> : 语句块n ;default : 语句块 n+1 ;
endcase
注意与c语言不同的是,最后要有endcase
系统函数
Verilog中预先定义的任务和函数大多数只能在仿真中使用,方便进行验证
常用系统函数
$display //打印信息,自动换行
$write //打印信息
$strobe //打印信息,自动换行,最后执行
$monitor //监测变量
$stop //暂停仿真
$finish //结束仿真
$time //时间函数
$random //随机函数
$readmemb //读文件函数
- 时间参数
timescale 1ns/1ns //时间尺度预编译指令 时间单位/时间精度
- 时间单位和时间精度由值1、10、100和单位s、ms、us、ns、ps和fs组成。
- 时间单位:定义仿真过程中所有与时间相关量的单位
仿真过程中使用"#数字" 表示延时相应时间单位的时间,例 #10 表示延时10个单位的时间,即10ns。 - 时间精度:决定时间相关量的精度及仿真显示的最小刻度
timescale 1ns/10ps
精度0.01
,#10.11
表示延时’10110ps’ - 错误写法
timesace 100ps/1ns
单位时间不能比时间精度小