verilog笔记
逻辑值
1、0、z(高阻态,无驱动)、x(未知逻辑电平,实际不存在)
实际电路中,只存在:1、0、z,还有亚稳态不稳定状态
参数定义
parameter 可以在顶层文件中对模块中参数进行修改
localparam 只能模块内部使用,
换算二进制后位宽的总长度可有可无,verilog会为常量自动匹配合适的位宽
当总位宽大于实际位宽,则自动在左边补0,总位宽小于实际位宽,则自动截断左边超出的位数
如果直接写参数,100,则表示32位的十进制数100
阻塞赋值
顺序赋值
非阻塞赋值
同时赋值
乘和除一般不适用,消耗资源大,有乘法器,使用乘法器,除法通过别的方法技计算
求余一般用在测试文件中
归约运算符 按位运算符
& 可以作为一元运算符(仅有一个参与运算的量);也可以作为二元运算符(有两个参与运算的量)
一元运算是
表示归约与,&m将m中所有bit相与,最后结果为1bit
二元运算符
按位与,m&n m中每一位与n中每一位相与,在运算时候要保证m和n的比特数相等,最后的结果和m(n)的比特数相同。
~& ^ ~^ | ~| 与上面同理
逻辑运算符
&& 与c语言相同 逻辑与运算符结果只有真或假,
||(逻辑或) ==(逻辑相等) !=(逻辑不等)
#关系运算符
< > <= >=
移位运算符
<< >> 左移运算符 右移运算符
位拼接符号
拼接是一堆花括号加逗号组成{,}不同数据之间用”,”隔开
8bit的a 3bit的b 5bit的c 顺序拼接成16位的d
d = {a,b,c}
条件运算符
?:;和C语言中三目运算符相同
优先级
归约运算符 > 算数运算符 > 移位运算符 > 关系运算符 > “==”和“!=” > 按位运算符 > “&&”和”||” > 条件运算符
总体 一元运算符 > 二元运算符 > 三元运算符
使用括号添加优先级
if - else 语句
分支语句
case casex casez
case 分支
系统函数
有一些任务和函数,完成一些特殊的功能,系统任务和系统函数,这些函数大多数只能在Testbench仿真中使用,timescale 1ns/1ns //时间尺度预编译指令时间单位/时间精度 时间单位和时间精度由值1、10、和100 以及单位s、ms、us、ns、ps 和fs 组成。 时间单位:定义仿真过程所有与时间相关量的单位。 仿真中使用“#数字”表示延时相应时间单位的时间,例#10表示延时 10个单位的时间,即 10ns。 时间精度:决定时间相关量的精度及仿真显示的最小刻度, timescale 1ns/10ps 精度0.01,#10.11 表示延时 10110ps。
下面这种写法就是错误的,因为时间单位不能比时间精度小。
`timescale 100ps/1ns //错误
生要的函数有如下这些,在支持 Verilog 语法的编辑器中都会显示为高亮关键字
1 | $display //打印信息,自动换行 |
$display() //自动换行
$display(“%b+%b=%d”,a,b,c);//格式“%b+%b=%d”格式控制,未指定时默认十进制
%h 或%H //以十六进制的形式输出
%a 或%D //以十进制的形式输出
%o或%O //以八进制的形式输出
%b 或%B //以二进制的形式输出
initial 只执行一次
$readmemb
$readmemb:用于读二进制文件函数。
$readmemh:用于读十六进制文件函数。
1 | $readmemb("<数据文件名>",<存贮器名>); |
1 |
|
reg [7:0] a [20:0];
1 | reg [7:0] a [20:0]; |
reg [7:0]表示定义8位宽的寄存器类型数据,每位索引范围为7(最高位)到0(最低位)a [20:0]表示定义深度为21的数组,索引范围为20到0整体含义:定义了一个包含21个存储单元的存储器,每个单元为8位寄存器,总存储容量为21×8位
实际应用:
该定义合法且常见于硬件描述中,可用于建模RAM、ROM等存储结
示例初始化方式:
1 | reg [7:0] a [20:0] = '{21{8'h00}}; // 全部初始化为0 |
注意事项:
- 存储器索引通常按降序定义(如[20:0]而非[0:20]),符合Verilog规范
- 每个存储单元需通过完整下标访问(如a[15]表示第16个单元的8位数据)
该定义可直接用于实际设计文件(如.v文件),综合工具会将其映射为实际硬件存储单元
1 | case (sel) |
双向IO使用
1 | inout io; |
右移循环
1 | reg [7:0]shift_a; |
左移循环
1 | reg [7:0]shift_a; |
位拼接
1 | wire [3:0]x; |
除法器
时序逻辑
连续赋值
1 | input a; |
只要是使用always中输出的结果,都需要定义reg类型。
1 | module add2(a,b,c); |
所有敏感信号 always@(*)
1 | module |
前级仿真
功能仿真
设置仿真工具
在Quartus中,通过 Assignments > Settings > Simulation 选择仿真工具(如ModelSim),并确保 不勾选 Run gate-level simulation(否则会触发后仿真流程)。
配置测试文件
在 Native Link 选项卡中添加测试文件(如 testbench.v),并指定顶层模块名称需与RTL代码中的模块名一致
执行仿真
通过 Tools > Run RTL Simulation 或 Tools > Run Functional Simulation 启动前仿真,此时仅验证逻辑功能,无时序延迟
前仿真:基于RTL代码,速度快,用于功能验证
后级仿真
生成网表文件
完成布局布线后,Quartus会自动生成网表文件(.vo)和时序文件(.sdo),这些文件将用于后仿真
启用时序仿真
在 Settings > Simulation 中勾选 Run gate-level simulation,并确保已加载正确的器件库(如 altera_ver)
配置延时文件
在ModelSim中,需将生成的.sdo时序文件与网表文件一同加载,以反映实际布线延迟
后仿真:基于网表文件,包含布线延迟,用于时序验证
生成网表文件(.vo)和时序文件(.sdo)
参数 parameter
模块
1 | module led(clk,rst,out); |
例化
1 | module led_top(); |
可以通过parameter 设置实例模块产生不同频率的输出,一个模块多场景应用,也可以使用端口出来设置值
parameter具体可以查看Verilog HDL 入门 (4) ;用于模块内部的参数定义,可通过模块例化时的#()语法修改值
defparam具体可以查看Verilog HDL 入门 (4) ;用于在例化后通过层次化路径强制修改已定义的parameter值
冲突与优先级
若同一参数被#()和defparam同时修改,defparam的赋值会最终生效(因其在编译后执行)。
但此用法易导致代码可读性差,且部分综合工具可能不支持defparam。
设计建议
优先使用#()语法在例化时传递参数,避免混用defparam
defparam通常仅用于仿真调试或遗留代码维护
注意
1. 设计一个功能,分成控制模块与数据处理模块编写,然后通过顶层模块联合在一起
串口
收数据通过采样,在一定时间内通过采样次数去比较是高或低电平,最低采样次数大于16次,找中间点数据分析,