· RTL(Register Transfer Level)寄存器传输级别的电路描述语言。
因为逻辑综合工具的发展,数字电路的设计中不再需要直接描述逻辑门及其连接关系。
而是通过RTL对电路功能做行为级描述,通过综合工具自动的从RTL抽取出逻辑门级别的描述。
· IEEE是Verilog的语言标准,1995年批准第一版,2001版有所改进
Comment:
由于RTL语言具有一定软件特性,在初学RTL时,经常不考虑RTL对应的电路,直接按照功能处理输入信号,
使输出能够满足期待动作。这样写出来的代码常常是不可综合的。
常规设计流程中,Coding之前必须按照功能,做出设计资料(时序,数据处理流程,整理各信号间关系等)
实际上,在此阶段设计就算是完成了,剩下的是把设计资料翻译成verilog代码。详细设计资料能够有效缩短后期验证所需时间
在Test Bench中对激励的描述,这部分内容是不需要综合成电路的,所以语法更加灵活。可使用System Verilog来产生激励。
验证目标模块时,有两种调用方式。
① 直接在Test Bench中调用设计
module teset_bench;
reg clk;
reg rst;
wire out;
parameter clk_period = 10; //通过参数设定始终周期
dut dut(clk , rst , q); // 调用设计模块
initial begin // 产生时钟周期为10的clk
clk = 1'b0;
forever #(clk_period/2) clk = ~clk;
end
inital begin
rst = 1‘b0;
#50 rst = 1'b1; //设定rst在仿真开始为低,经过50个仿真时间单位后拉高
#200 $finish; //在第200个仿真时间单位时,终止仿真
end
enmodule
②建立一个没有In/out的虚拟顶层top,在top中调用设计和Test Bench,使两者在同一层次
module top;
wire clk;
wire rst;
wire q; //定义输出q,才能在波形中查看
dut dut(clk , rst , q); // 调用设计模块
test test(clk , rst ); // 调用激励产生模块
enmodule
– > 我更倾向于第二种方法,层次清晰,灵活性好。
抽取部分认为有价值/易错的记录下来。
4'b0011 //指定位数,4位二进制数
'b0011 //不指定位数,32位的二进制数
1 //不指定位数,32位的十进制数
为了尽可能少的占用资源,设计都要定义数字的bit宽度。
特别是在使用例化模块时通过parameter传入参数时,容易漏掉bit宽度的定义。
Comment:不定义bit宽度不会导致设计出错,但是在使用Lint工具检查设计语法时,会检测到算式左右bit位宽不对称的Warning。
②负数
-4'd3 //4位的十进制负数3,内部通过二进制补码存储
-4'sd3 //4位的用于有符号计算的十进制负数3
Comment:通过在指定位宽的值前面加上一个负号来表示负数,在进制符号前加s(sign)表示有符号数。使用场景未遇到过
module test(
input clk,
input a,
output add
);
parameter P_width = 4'd8; //定义参数,可以通过外部例化修改参数值
localparam LP_width = 4'd6; //定义局部参数,参数值不能被修改
reg tmp1[P_width-1 : 0]; // 在定义reg变量时,可以使用参数设定位宽
reg tmp2[PL_width-1 : 0];
····
endmodule
test test_int //模块例化,需要在模块外层
#( //通过#例化参数,下面端口例化不需要#符号
.P_width ( 4'd4 )
)(
.clk ( clk_int ),
.rst ( rst_int ),
.add ( add_int )
);
reg [4:0] tmp1;
$display (" at time %d the address is %h",$time,tmp1);
· $monitor :对信号值进行动态监视
$monitor(p1,p2,p3····,pn);
p1··,pn可以是变量,信号名,双引号括起来的字符串。
对参数列表中的参数不间断的监视,其中任何一个发生变化时,显示所有参数值。
任意仿真时刻,只有一个monitor有效,前面的monitor会被后面调用的覆盖。
inital begin
$monitor("at time %d",$time,"test1's value=%d test2's value=%d",tmp1,tmp2);
end
用来描述组合逻辑,连续赋值是数据流建模的主要语法结构。只能对wire赋值,输出状态完全由当前状态决定。
其他的就是一些语法的应用。
算术运算符(+ - * / % **) : 一般只使用+ - ,其他的要么不可综合,要么综合出来的面积很大,非优化设计。
逻辑运算符(&&,||,!):非0即为1,非假即真。输出是1位0/1。
关系运算符(> , >= , < , <= ):输出是逻辑0或1
等价运算符(== , != ):两个操作数逐位比较,返回逻辑0/1。
按位操作符(~,|,&,^(异或)) : 两个操作数逐位处理,若两个操作数位宽不等,位宽小的向高位补0,输出与位宽大的操作数等位宽)
缩减操作符(&,|,^,缩减异或,缩减同或等):操作符在操作数前面,只有一个操作数,操作数按位处理。
非阻塞赋值的理解: 并行执行的语句块。当always的敏感列表中条件达成时,先计算表达式右侧信号值,并临时存储到仿真器中,等到赋值语句的延时条件达成后,把保存的值传到表达式左侧的寄存器中。
因为是在相同的时刻调度表达式右侧的值,所以即使各个表达式的延迟设定不同,还是能够传相同时刻的值到不同表达式,这就是非阻塞概念。