文章目录
- 1.1
- 1.1.1 DUT Code
- 1.1.2 Testbench
- 1.1.3 自动化编译:Makefile
- 1.1.4 Debug 方法
- 1.2 逻辑综合工具 - Design Compile
- 1.2.1 逻辑综合流程
- 1.2.2 逻辑综合方法
1.1
1.1.1 DUT Code
以实现一个全加器为例子,
-
功能
- 真值表
- 真值表
-
验证
- 功能完整性
- 穷举法
- 代码覆盖率
-
lab01
- 编译
- 仿真
- 产看波形
//-------------------------------------------------------------
// FileName: full_adder.v
// Creator: demo
// E-mail: demo@demo.com
// Function: one bit full adder
// Update:
// Copyright: www.demo.demo.com
//--------------------------------------------------------------
module full_adder (
// module head: verillog-2001 format
input wire a_in,
input wire b_in,
input wire c_in, //carry in
output wire sum_out,
output wire c_out //carry out,
);
// mehtod 1 Gate Level describe
assign sum_out = a_in ^ b_in ^ c_in;
assign c_out = (a_in & b_in) | (b_in & c_in) | (a_in & c_in);
// method 2 RTL design for Adder with the keyword "assign"
// behaviro of the adder can be synthesizable
// "assign" means connectivity, which is used to describe a combinational circuit
// assign {c_out, sum_out} = a_in + b_in + c_in;
// method 3 RTL design for Adder wiht the keyword "always"
//reg c_o, sum_o;
//always @ (a_in, b_in, c_in) begin
// {c_o, sum_o} = a_in + b_in + c_in; // the reg type variable is required in the always blocks
//end
// assign {c_out, sum_out} = {c_O, sum_o};
endmoudle
- 方式1: 使用门级网表的方式来描述;
- 方式2:使用 RTL 设计, assign 表示用金属线连接,主要用于组合电路;其中的花括号可以认为是拼接符号,将高位放在前面,将低位放在后面;一位的全加器会形成两位的输出,所以花括号里是两位的。可以看到使用 “+” 来描述比门级网表的方式要清晰。
- 方式3:使用RTL 设计,使用“always”语句来定义输出,注意always 语句左侧必须是 reg 类型,
1.1.2 Testbench
如何验证一个全加器呢?
//-------------------------------------------------------------
// File header
//-------------------------------------------------------------
module full_adder_tb;
// driver the input port with the reg type
reg ain, bin, cin; //给 DUT 输出驱动,驱动的类型要是 reg 类型;
// sample the output port with the wire type
wire sumout, cout;
full_adder u_full_addr( // instance, 实列化,真正的物理电路是实例化以后,课可以例化很多加法器。
// task 1. how to create an instance
// moudle head: verillog-2001 format
/* input wire */ .a_in (ain), //testbench 的信号和 DUT的信号通过显示方式进行连接
/* input wire */ .a_in (bin),
/* input wire */ .a_in (cin),
/* output wire */ .sumout (sumout), //carry in
/* output wire */ .c_out (cout) //carry out
);
// behavior of the adder can ben synthesizeable
// "assign" means connectivity
// assign {c_out, sum_out} = a_in + b_in + c_in;
// task 2. clock and reset generator
parameter CLK_PERIOD = 20;
reg clk, reset_n; // reset_n: active low
initial begin
clk = 0;
forever begin
#(CLK_PERIOD/2) clk = ~clk;
end
end
initial begin
reset_n = 0;
#100
reset_n = 1;
end
// task 3. driver the stimulus and caputre the response
// here is a testcase
initial begin
#110 ain = 0; bin = 0 ; cin = 0; //00
#20 ain = 0; bin = 1 ; cin = 0; //01
#20 ain = 1; bin = 0 ; cin = 0; //01
#20 ain = 1; bin = 1 ; cin = 0; //10
#20 ain = 0; bin = 0 ; cin = 1; //01
#20 ain = 0; bin = 1 ; cin = 1; //10
#20 ain = 1; bin = 0 ; cin = 1; //10
//#20 ain = 1; bin = 1 ; cin = 1; //11
#20 ain = 1; bin = 1 ; cin = 0; //10
#50 $finish; // here is a system task which can stop the simulation
end
// task 4. check the result
always @ {possedge clk} begin
if (!reset_n) begin
$dispaly("%t: %m: resetting..., $time")// counter5 clock
end
else begin
$dispaly("%t: %m: resetting finish!, $time")// the 6th clock
end
end
initial begin
#115 if({count, sumout}!=2'b00) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b01) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b01) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b10) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b01) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b10) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b10) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b11) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
#20 if({count, sumout}!=2'b11) $display("Error:{count, sumout}=%b,ain=%b,bin=%b,cin=%b",{count,sumout},ain,bin,cin);
end
// task 5. dump waveform with the compile opton -debug_all
inital begin
$vcdplusson;
end
endmoudle
initial begin 表示初始化,也即只执行一次:
- clk 逻辑: 设置时钟周期
CLK_PERIOD =20 ns
, 也即时钟为50M
, 开始时刻 clk 为0, 然后 进行 延时10ns(CLK_PERIOD/2)后再将 clk 信号取反,这样时钟就会反复循环10ns
高 和10ns
低的效果。 - reset 逻辑:
reset_n
先拉低,然后延时100ns
后再拉高
1.1.3 自动化编译:Makefile
# Makefile for simulate the full_adder.v with the simulator VCS
#-----------------------------------------------------------------
# Macro variables
RTL := ./full_addder.v
TB += ./full_adder_tb.v
SEED ?= $(shell data +%s)
# Target: Dependency
all: compile simulate
compile:
vcs -sverilog -debug_all timescale.v $(RTL) $(TB) -l com.log #编译文件
simulate:
./simv +ntb_random_seed=$(SEED) -l sim.log # 执行仿真
run_dev:
dev -vpd vcdplus.vpd # 查看仿真波形
clean: rm -rf *.log csrc simv* *.key *.vpd DVEfiles coverage *.vdb
首先了解下上面 Makefile 中的 三种赋值方式:
- := 属于强制赋值;
- += 属于追加赋值,如果TB已经有值,会在其后追加当前的值;
- ?= 属于判断赋值方式,如果SEED已经有值,这个赋值就不会执行;
其次了解下编译参数:
-sverilog
用于识别 SystemVerlog 语法;-debug_all
可以将 debug 的信息全部保存下来,比如波形文件;-l com.log
将百衲衣过程生成的日志全部写入 com.log 文件。
vcs 编译完成后会生成一个simv的可执行文件。
在 terminal 中输入 make 命令:
make
; 回到当前目录找Makefile 文件,并all 开始执行;make all
make compile
;make simulate
相当于执行了 make allmake run_dev
make clean
;make all
用户可以指定要 make
的 target, 即要做哪件事情,如:make clean
,那么就会执行 Makefile 文件中的 删除文件操作。
1.1.4 Debug 方法
1.2 逻辑综合工具 - Design Compile
逻辑综合(Synthesis)工具主要用于检查 RTL 代码是否可以综合成电路(与门、非门、或门、FF),具体来说的化就是在 RTL Code freeze 之后将前端设计工程师写的RTL code,映射到特定工艺库上(TSMC/UMC/SMIC),通过添加约束信息,对RTL 代码进行逻辑优化,形成门级网表。
其中约束信息包含(PPA):
- 时序,比如设计100M;
- 功耗;
- 面积;
PPA 信息添加完成后 工具就会进行优化,优化完成后会形成门级网表。
主要包括下面三部:
Trannslation + mapping + optimized
逻辑综合只做了解
1.2.1 逻辑综合流程
- Load library and design
- Apply timing constraints and design rules constraints
- Synthesis the design
- Analyze the results
- Write out the design data(netlist)
逻辑综合完成后需要将 netlist + SDC 给到 backend,做物理版图(layout)
1.2.2 逻辑综合方法
一、启动 DC 工具
- 方式1:使用GUI方式;
- 方式2:involve DC,
dc_shell
- 方式3:工程上常用 dc_shell 吃入一个 *.tcl(tool command language) 脚本,很多工具都支持 tcl 语言,
dc_shell -f syn.tcl | tee -i syn.log
二、设置搜索路径(search_patch)
set_app_var search_patch "$search_patch" ./rtl ./scripts ./libs"
三、libray setup(mapping)
- target libray
- link libray
四、read_verilog
read_verilog "TOP.v A.v B.v"
五、current_design
current_design TOP
//设置顶层文件
六、timing constrain
-
clock period;
-
clock skew 时钟上升或者下降的坡度;
-
clock transition 时钟从0->1 或者从 1->0 需要的时间;
-
clock latency 时钟从源发出到接收点的时间;
-
Input delay
set_input_delay
-
output delay
set_out_delay -max 0.8 -clock Clk [get_ports B]
七、environment constraint
set_input_transition
set_load
八、compile/compile_ultra
compile
compile_ultra
九、report qor
- Timing
- Cell count
- Area:组合电路的面积,非组合电路的面积,线网的面积
十、report_timing
report_timing
静态时序分析
十一、output
推荐阅读:
https://www.bilibili.com/video/BV1WY411D7So?p=9&spm_id_from=pageDriver&vd_source=a354e64412a97e828c2f4b7ebe7c3606