当前位置:   article > 正文

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

简单的rtl设计


请阅读【芯片设计 RTL 数字逻辑设计扫盲 】


1.1 RTL 开发流程

1.1.1 组合逻辑

always @(*)begin
	if(sel==0)
		c = a + b;
	else
		c = a + d;
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这种条件信号变化结果立即变化的 always 语句被称为“组合逻辑” 。

1.1.2 时序逻辑

always @(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
		c <= 0;
	end
	else if(sel==0)
		c <= a + b;
	else
		c <= a + d;
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上述代码的敏感列表是“posedge clk or negedge rst_n” , 也就是说, 当 clk 由 0 变成 1 的瞬间, 或者 rst_n 由 1 变化 0 的瞬间, 执行一次程序代码, 即第 2 至 8 行, 其他时刻 c 的值保持不变。这种信号边沿触发, 即信号上升沿或者下降沿才变化的 always, 被称为“时序逻辑” , 此时信号 clk 是时钟。 注意: 识别信号是不是时钟不是看名称, 而是看这个信号放在哪里, 只有放在敏感列
表并且是边沿触发的才是时钟。

注意以下几点
1、 组合逻辑的 always 语句中敏感变量必须写全, 或者用“*” 代替。
2、 组合逻辑器件的赋值采用阻塞赋值 “=”, 时序逻辑器件的赋值语句采用非阻塞赋值“<=” ,

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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 方式1: 使用门级网表的方式来描述:在这里插入图片描述

  • 方式2:使用 RTL 设计, assign 表示用金属线连接,主要用于组合电路;其中的花括号可以认为是拼接符号,将高位放在前面,将低位放在后面;一位的全加器会形成两位的输出,所以花括号里是两位的。可以看到使用 “+” 来描述比门级网表的方式要清晰。

assign 语句的功能属于组合逻辑的范畴, 应用范围可以概括为一下几点:

  • 持续赋值;
  • 连线;
  • 对 wire 型变量赋值, wire 是线网, 相当于实际的连接线, 如果要用 assign 直接连接, 就用 wire 型变量, wire 型变量的值随时发生变化。

需要说明的是, 多条 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, count;

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 (count)     //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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

首先了解下上面 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"
  • 1

三、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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/807914
推荐阅读
相关标签
  

闽ICP备14008679号