【芯片设计- RTL 数字逻辑设计入门 5 -- RTL 全加器实现及验证】

文章目录

    • 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

以实现一个全加器为例子,

  • 功能

    • 真值表
      【芯片设计- RTL 数字逻辑设计入门 5 -- RTL 全加器实现及验证】_第1张图片
  • 验证

    • 功能完整性
    • 穷举法
    • 代码覆盖率
  • lab01

    • 编译
    • 仿真
    • 产看波形
//-------------------------------------------------------------
// FileName: full_adder.v
// Creator: demo
// E-mail: [email protected]
// 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 命令:

  1. make; 回到当前目录找Makefile 文件,并all 开始执行;
  2. make all
  3. make compile; make simulate 相当于执行了 make all
  4. make run_dev
  5. 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

你可能感兴趣的:(芯片设计,RTL,数字逻辑设计扫盲,fpga开发,RTL,语法,RTL,全加器)