参考教程:
Verilog教程-夏宇闻
因为Verilog和C语言很像,所以这个入门只是记录一下Verilog的特殊点等,具体可以去看上面的参考教程
数据类型及常量、变量
- 数据类型
- 表述数字电路中数据存储和传送单元
- 共19种数据类型
- 4种最基本:
integer
,parameter
,reg
,wire
- 其他:
large
,medium
,scalared
,small
,time
,tri
,tri0
,tri1
,triand
,trior
,trireg
,vectored
,ward
,wor
- 4种最基本:
- 常量
- 整数型常量
- 有二进制、十进制、十六进制、八进制
<位宽>'<进制><数字>
- 缺省位宽,则位宽由机器系统决定;缺省进制,则为十进制
- x和z值
- x表示不定值,z表示高阻值
- 具有扩展性(
8'b1x=8'b0000_001x
) ?
是z的另一种表示符号,建议在case语句中使用?表示高阻态
- 负数
- parameter常量(符号常量)
- 用parameter来定义一个标识符,代表一个常量——称为符号常量
parameter 参数名1=表达式,参数名2=表达式,……
- 用来定义延迟时间和变量宽度
- 参数是本地的,其定义只在本模块内有效
- 在模块或实例引用时,可通过参数传递改变在被引用模块或实例中已定义的参数
defparam
:defparam 例化模块名.参数名1=常数表达式,例化模块名.参数名2=常数表达式,……;
#
:被引用模块名# (参数1,参数2……) 例化模块名 (端口列表);
- 整数型常量
- 变量
- 数据类型有19种,常用的有三种
- 网络型
nets
- 输出始终随输入变化而变化的变量
- 不能存储值
- 最常用:
wire
,常用来表示以assign语句赋值的组合逻辑信号
- 寄存器型
register
- 对应具有状态保持作用的电路元件(如触发器、寄存器等),常用来表示过程块语句(如initial,always,task,function)内的指定信号
- 需要明确赋值,并在被重新赋值前一直保持原值
- 必须通过过程赋值语句赋值,不能通过assign语句
reg
- 常代表触发器,但不一定就是触发器(也可以是组合逻辑信号)
reg[n-1:0] 数据名1,数据名2,……,数据名m;
或reg[n:1] 数据名1,数据名2,……,数据名m;
integer
:32位带符号整数型变量real
:64位带符号实数型变量time
:无符号时间变量
- 数组
memory
- 由若干个相同宽度的reg型向量构成的数组
- 可描述RAM、ROM和reg文件
运算符及表达式
- 算术运算符
- 逻辑运算符
- 关系运算符
- 等式运算符
- 缩减运算符
- 条件运算符
- 位运算符
- 移位运算符
- 位拼接运算符
- 运算符优先级
结构说明语句
- initial说明语句——只执行一次
- 在仿真的初始状态对各变量进行初始化
- 在测试文件中生成激励波形作为电路仿真信号
initial begin 语句1; 语句2; …… 语句n; end
- always说明语句——不断重复执行,直至仿真结束
- 被赋值的只能是
register
型变量 - 每个always块在仿真一开始便执行
always <时序控制><语句>
- 必须与一定的时序控制结合在一起在有用,否则,易形成仿真死锁
- 当always块有多个敏感信号时,一定要采用
if-else if
语句,而不能采用并列的if语句,否则,易造成一个寄存器有多个时钟驱动 - 通常采用异步清零
- 被赋值的只能是
- task说明语句——可在程序模块中一处或多处调用
- 用户定义任务
- 对一些信号进行一些运算并输出多个结果
- 定义和调用必须在一个
module
模块内 - 可以调用其他任务和函数
任务定义: task <任务名>; 端口及数据类型声明语句; 其他语句; endtask 任务调用: <任务名> (端口1,端口2,……);
- function说明语句——可在程序模块中一处或多处调用
- 用户定义函数
- 通过返回一个用于某表达式的值,来响应输入信号。适用于对不同变了采取同一运算操作
- 可以在其他模块调用
- 其定义不能包含任何时间控制语句
- 不能调用任务
- 定义时至少有一个输入参量,且不能有任何输出或输入/输出双向变量
- 函数定义中必须有一条赋值语句,给函数中一个内部寄存器赋以函数的结果值,该内部寄存器与函数同名
函数定义 function <返回值位宽或类型说明> 函数名; 端口声明; 局部变量定义; 其他语句; endfuction 函数调用 <函数名>(<表达式> <表达式>)
编译预处理语句
define
include
timescale
- 定义跟在该命令后模块时间单位和时间精度
timescale <时间单位>/<时间精度>
- 时间精度值不能大于时间单位值,且必须都是整数
基本结构
- Verilog程序由模块构成,模块可以进行层次嵌套
- 每个Verilog源文件只能有一个顶层模块,其他为子模块
- 逻辑功能定义
- 在Verilog中有三种方法可以描述电路的逻辑功能
- 1.用assign赋值语句
assign x=(b&~c);
- 常用于描述组合逻辑
- 2.用元件例化(instantiate)
and myand3(f,a,b,c);
- 元件例化即是调用Verilog提供那个的元件
- 包括门元件例化和模块元件例化
- 每个实例元件名字必须唯一
- 例化元件名也可以省略
- 3.always块语句
- 结构说明语句
- 常用于描述时序逻辑 ,也可以描述组合逻辑
always @(posedge clk)//每当时钟上升沿到来时执行一遍块内语句 begin if(load) out=data;//同步预置数据 else out=data+1+cin;//加1计数 end
- 其大概模板如下:
module <顶层模块名>(<输入输出端口列表>)
output 输出端口列表;
input 输入端口列表;
//(1)使用assign语句定义逻辑功能
wire 结果信号名;
assign <结果信号名>=表达式;
//(2)使用always块定义逻辑功能
always@(<敏感信号表达式>)
begin
//过程复制语句
//if语句
//case语句
//while,repeat,for循环语句
//task,function调用
end
//(3)元件例化
<module_name><instance_name>(<port_list>);//模块元件例化
<gate_type_keyword><instance_name>(<port_list>)//门元件例化
endmodule
关键字
Verilog的描述
- 系统级:用高级语言结构(如case语句)实现的设计模块外部性能的模型
- 算法级:用高级语言结构实现的设计算法模型(写出逻辑表达式)
- RTL级:描述数据在寄存器之间流动和如何处理这些数据
- 门级:描述逻辑门以及逻辑门之间连接的模型
- 开关级:描述器件中三极管和存储节点及其之间连接的模型
门级描述
- 结构描述,最直观
- 关键字有26个,常用的有:
not,and,nand,or,nor,xor,xnor,buf,(各种三态门)bufif1,bufif0,notif1,notif0
- 调用语法:
门类型关键字 <例化的门名称>(<端口列表>);
设计技巧
- 一个变量不能在多个
always
块中被赋值 - 在
always
块语句中,当敏感信号为两个以上的时钟边沿触发信号时,应注意不要使用多个if
语句,以免因逻辑关系不清晰而导致编译错误(if-else
) - 当输出信号为总线信号是,一定要在I/O说明中指出其位宽,否则在生成逻辑信号时,输出信号被误认为是单个信号
- 当要用到计数器时,一定要根据计数最大值事先计算好所需的位宽