Verilog HDL设计与综合 (学习笔记)

Verilog HDL设计与综合 (学习笔记)


**·**在刚学习verilog时,草草的看过这本书,主要关注点都在语法上,现在有了一点设计经验。重新学习此书,希望能够学到更多东西。

概述


设计

· RTL(Register Transfer Level)寄存器传输级别的电路描述语言。

因为逻辑综合工具的发展,数字电路的设计中不再需要直接描述逻辑门及其连接关系。
而是通过RTL对电路功能做行为级描述,通过综合工具自动的从RTL抽取出逻辑门级别的描述。

· IEEE是Verilog的语言标准,1995年批准第一版,2001版有所改进

Comment:
由于RTL语言具有一定软件特性,在初学RTL时,经常不考虑RTL对应的电路,直接按照功能处理输入信号,
使输出能够满足期待动作。这样写出来的代码常常是不可综合的。
常规设计流程中,Coding之前必须按照功能,做出设计资料(时序,数据处理流程,整理各信号间关系等)
实际上,在此阶段设计就算是完成了,剩下的是把设计资料翻译成verilog代码。详细设计资料能够有效缩短后期验证所需时间

验证

  • 设计完成后搭建Test Bench(测试平台),验证设计正确性。
  1. 对设计模块施加激励,通过波形查看结果是否正确。(直接验证方式)。
  2. 通过Assertion断言检查,随机验证+期待值比较等。(随机验证)。

在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)表示有符号数。使用场景未遇到过

  • ③parameter
    通过参数定义一个常数,在模块内定义的parameter可以调用模块时,在instance(例化)处传入新参数,覆盖模块内的参数值。
    在模块复用时,用此方式,调整参数。
    localparam 是局部参数定义,作用与parameter相同,区别是不能被修改。
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 )
);
  • ④系统任务
    ·$display
    类似C语言的printf,会自动在行尾插入换行符。
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的敏感列表中条件达成时,先计算表达式右侧信号值,并临时存储到仿真器中,等到赋值语句的延时条件达成后,把保存的值传到表达式左侧的寄存器中。
因为是在相同的时刻调度表达式右侧的值,所以即使各个表达式的延迟设定不同,还是能够传相同时刻的值到不同表达式,这就是非阻塞概念。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值