对IC Flow的再反思
最近测试有些进展,但也碰到了许多令人尴尬的问题。
但问题不大,吸取经验教训才能进步。
说回到这次碰到的问题。片上做的i2c接口实测时发现读取出现问题,体验了一波从实测追溯到仿真的过程。具体来说:
-
如果有一套fpga代码有一套asic代码,版本管理做好,确保一致性
-
fpga验证pass不能代表asic代码就没问题,该仿真的地方得仿真覆盖,不能跳过
-
具体来说的流程:设计文档编写->RTL编写->RTL仿真验证->spyglass检查->FPGA验证->dc综合->dc网表fm检查->dc网表仿真验证->后端pnr->后端网表fm检查->后端网表验证仿真->LVS检查,如果出了问题就是倒过来查验一遍
-
涉及数模接口的部分必须混仿覆盖到
之前一直偷懒,跳过spyglass,fm和dc网表仿真的环节,当然这次是RTL上就出了问题但是没有验证覆盖到。
总体而言,小心驶得万年船。贴个更新后的组内规范上来:
数字前端规范 v1.4
编写人:袁易扬
联系方式:2861704773@qq.com
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | 2023.05.19 | 初次发布 |
v1.1 | 2023.05.20 | 勘误分频器模板说明 |
v1.2 | 2023.05.26 | 勘误工具版本 |
v1.3 | 2024.07.24 | 细化各条目说明,设计模板文档独立 |
v1.4 | 2024.07.26 | 更新各文档模板内容描述,更新参考资料 |
1. 工具链
数字前端工具链:
编译工具:
Synopsys VCS
仿真工具:
Synopsys Verdi
综合工具:
Synopsys Design Compiler
代码检查工具:
Synopsys Spyglass
一致性校验工具:
Synopsys Fomality 2018
2. 前端基本流程
设计文档编写->RTL编写->RTL仿真验证->spyglass检查->FPGA验证->dc综合->dc网表fm检查->dc网表仿真验证->后端pnr
3. 文档规范
原始文档建议使用markdown进行编辑,markdown编写软件推荐使用Typora(可以下载免费版,也可以购买付费版),也可以使用vscode安装markdown插件后作为markdown编辑器使用。
设计文档格式可参考《设计文档模板》,内容需要包括:
- 模块/芯片功能描述(描述模块/芯片整体功能)
- 模块/芯片架构描述(包含框图以及子模块功能基本描述)
- 模块/芯片端口(使用表格进行描述,表格中需要包含以下内容:Port 端口名;Width 端口位宽;Direction 端口方向; Function 功能描述)
如果存在模块/芯片存储器和存储器也需要进行描述:
- 模块/芯片寄存器(使用表格进行描述,表格中需要包含以下内容:Address 地址;Name:寄存器名;Type:功能(读写/只读/只写); Function 功能描述;Reset Value 复位值)
- 模块/芯片存储器(使用表格进行描述,表格中需要包含以下内容:Start Address 起始地址; End Address 终止地址;Size 存储器尺寸;Name 存储器名;Function 功能描述)
验证文档格式可参考《验证文档模板》,内容需要包括:
- 验证说明描述(描述要验证的模块,验证的方案,验证的工具,待验证的功能目标)
- 验证平台架构(包含框图以及子模块基本功能描述)
- 验证模块/芯片端口(使用表格进行描述,表格中需要包含以下内容:Port 端口名;Width 端口位宽;Direction 端口方向; Function 功能描述)
- 验证计划(使用表格进行描述,表格中需要包含以下内容:Test Name 测试名;Test Method 测试方法;Test Target 测试目标)
- 验证用例(使用表格进行描述,表格中需要包含以下内容:Case Name 用例名;Description 用例描述; Implementation 用例的验证激励和验证响应)
测试文档格式可参考《测试文档模板》,内容需要包括:
- 测试说明描述(描述要测试的模块,测试的方案,测试的工具,待测试的功能目标)
- 测试平台架构(包含框图以及子模块基本功能描述)
- 测试模块/芯片端口(使用表格进行描述,表格中需要包含以下内容:Port 端口名;Width 端口位宽;Direction 端口方向; Function 功能描述)
- 测试计划(使用表格进行描述,表格中需要包含以下内容:Test Name 测试名;Test Method 测试方法;Test Target 测试目标)
- 测试用例(使用表格进行描述,表格中需要包含以下内容:Case Name 用例名;Description 用例描述; Implementation 用例的测试激励,预期响应和实际响应)
此外文档需要注明以下信息:
- 文档作者
- 作者联系方式
- 文档版本
- 文档编写日期
若文档存在历史版本,需要说明各版本修改信息。
4. 数字编码规范
主要参考华为内部编码标准。以下规范均只涉及可综合设计部分,对于testbench以及第三方ip不应用以下规范。
4.1 设计风格
- 低电平有效的信号,信号名后缀"_n"
- 模块名统一使用小写+下划线方式风格,例如"test_module"
- 模块例化使用u_xx表示,需要多次例化的模块使用序号表示(0、1、2),例如"u_test_0"
- 使用降序定义向量位宽,最低位为0,例如"wire [3:0] vector"
- 采用小写字母定义wire,reg和input/output
- 采用大写字母定义参数,参数名小于20个字母,例如"parameter PARAM = 2'b00"
- 时钟信号应前缀"clk",复位信号应前缀"rst"
- 对于一个时钟上产生分频时钟应后缀分频比例,例如"clk_128",表示clk信号分频128倍后产生的时钟
- 代码中不能使用VHDL,Verilog或SystemVerilog的保留字
- 在进行模块声明时,按照如下顺序定义端口信号:输入、输出,例如:
module test(
input a,
input b,
output c
);
- 不要书写空的模块,每个模块至少有一个输入和一个输出
- 时钟事件必须要以边沿触发的形式书写,即"posedge <clk_name>"或"negedge <clk_name>"
- 异步复位,高电平有效使用"if(<asynch_reset>)",低电平有效用"if(!<asynch_reset>)"
- 代码中给出必要的注释
- 每个文件应包含一个文件头,包含作者,日期等基本信息,即
//--------------------------------------------------------------------
// ___ _____ ______ _______ ________ ___ _________
// |\ \|\ _ \ _ \|\ ___ \ |\ __ \|\ \|\___ ___\
// \ \ \ \ \\\__\ \ \ \ __/| \ \ \|\ /\ \ \|___ \ \_|
// \ \ \ \ \\|__| \ \ \ \_|/__ \ \ __ \ \ \ \ \ \
// \ \ \ \ \ \ \ \ \ \_|\ \ __\ \ \|\ \ \ \ \ \ \
// \ \__\ \__\ \ \__\ \_______\\__\ \_______\ \__\ \ \__\
// \|__|\|__| \|__|\|_______\|__|\|_______|\|__| \|__|
//
// COPYRIGHT 2023, ALL RIGHTS RESERVED
// Institute of Microelectronics, Chinese Academy of Sciences
// Beijing Institude of Technology
//
// Filename:
// Author:
// Date:
//
// Project:
// Description:
//--------------------------------------------------------------------
- 每个文件只包含一个模块
- 模块名与模块名保持一致,例如模块命名为"module test",则文件名必须为"test.v"
- 模块名或变量要使用缩写时请参考缩写规范:(382条消息) 【精】Verilog语言缩写规范_verilog 常用缩写_heartdreamplus的博客-CSDN博客
4.2 设计可靠性
- 同步时序逻辑的always block中有且只有一个时钟信号,并且所有在同一个边沿动作(如上升沿)
- 采用同步设计,避免使用异步逻辑(全局异步复位除外)
- 避免将时钟信号作为数据信号输入
- 不要在时钟路径上添加任何buffer(即让原始的时钟信号穿过任何逻辑再输出到其他模块作为时钟)
- 不要在复位路径上添加任何buffer(即让原始的复位信号穿过任何逻辑再输出到其他模块作为复位)
- 在顶层模块中,时钟信号必须可见
- 不要采用向量的方式定义一组时钟
- 建议使用单一的全局同步复位电路或者单一的全局异步复位电路
- 不使用不可综合的语法
- 不使用不可综合的运算符
- 避免使用inout端口
- 避免在多个逻辑块中驱动同一个信号
- 时序always块禁止使用电平驱动
- 数据位宽要匹配
- 时序逻辑块统一使用非阻塞赋值(<=)
- 组合逻辑块统一使用阻塞赋值(=)
- 避免产生latch
- 避免产生异步数据环路
4.3 其他规则
基本模板:
强调:所有文件使用UTF-8格式进行编码!
为了便于markdown表格与verilog的自动转换,模块端口声明请采用方向声明与类型声明分离的写法,为了简洁,input端口不声明端口类型,缺省为wire。output端口单独进行reg类型的声明。
优化数字前端工作流的小脚本 - sasasatori - 博客园 (cnblogs.com)
积极使用参数化设计以提高模块的重用性。
在模块内部进行声明时按照模块端口->参数->内部信号的顺序进行声明。
例子:
module my_module # //例化参数
(
DATA_WIDTH = 32,
ADDR_WIDTH = 5
)
( //模块端口
input clk, // 时钟
input rst_n, // 复位
input [ADDR_WIDTH-1:0] inst_addr, // 指令地址
output [DATA_WIDTH-1:0] inst_dout // 指令数据
);
// 端口reg
reg [DATA_WIDTH-1:0] inst_dout;
// 参数
parameter DEPTH = 32;
// 内部信号
reg [DATA_WIDTH-1:0] sram [DEPTH-1:0];
// 逻辑块
always @ (posedge clk or negedge rst_n) begin
...
end
// assign语句
assign ...
endmodule
以下常用模块参照模板格式进行编码:
- FSM模板
使用三段式状态机,输出逻辑使用时序逻辑
module fsm(
input clk,
input rst_n,
input [1:0] in,
output [1:0] out
);
reg [1:0] out;
parameter IDLE = 2'b00;
parameter STATE1 = 2'b01;
parameter STATE2 = 2'b10;
reg [1:0] current_state, next_state;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
current_state <= IDLE;
end else begin
current_state <= next_state;
end
end
always @ (*) begin
case(current_state)
IDLE: begin
if(in == 2'b01) begin
next_state = STATE1;
end else begin
next_state = IDLE;
end
end
STATE1: begin
if(in == 2'b10) begin
next_state = STATE2;
end else begin
next_state = STATE1;
end
end
STATE2: begin
if(in == 2'b01) begin
next_state = IDLE;
end else begin
next_state = STATE2;
end
end
default: next_state = IDLE;
endcase
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
out <= 2'b00;
end else begin
case(current_state)
IDLE: out <= 2'b00;
STATE1: out <= 2'b01;
STATE2: out <= 2'b10;
default: out <= 2'b00;
endcase
end
end
endmodule
- regfile
写端口使用时序逻辑,读端口使用组合逻辑,采用参数化设计以便控制位宽
module regfile #(
parameter ADDR_WIDTH = 5,
parameter DATA_WIDTH = 32,
parameter DEPTH = 32
) (
input clk,
input rst_n,
input wren,
input [ADDR_WIDTH-1:0] raddr1,
input [ADDR_WIDTH-1:0] raddr2,
input [ADDR_WIDTH-1:0] waddr,
input [DATA_WIDTH-1:0] wdata,
output [DATA_WIDTH-1:0] rdata1,
output [DATA_WIDTH-1:0] rdata2
);
output reg [DATA_WIDTH-1:0] rdata1;
output reg [DATA_WIDTH-1:0] rdata2;
reg [DATA_WIDTH-1:0] regs [DEPTH-1:0];
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
for(int i=0; i<DEPTH; i=i+1) begin
regs[i] <= 0;
end
end else if(wren) begin
regs[waddr] <= wdata;
end
end
assign rdata1 = regs[raddr1];
assign rdata2 = regs[raddr2];
endmodule
- 译码逻辑
针对简单的译码逻辑可以使用case语句进行生成
module decoder(
input [1:0] in,
output [3:0] out
);
reg [3:0] out;
always @ (*) begin
case(in)
2'b00: out = 4'b0001;
2'b01: out = 4'b0010;
2'b10: out = 4'b0100;
2'b11: out = 4'b1000;
endcase
end
endmodule
针对复杂译码逻辑(如cpu的指令译码)为了避免综合时产生latch,强烈建议使用wire和assign的纯组合语法,例如:
module decoder(
input [1:0] in,
output[3:0] out
);
assign out[0] = (in == 2'b00) ? 1'b1 : 1'b0;
assign out[1] = (in == 2'b01) ? 1'b1 : 1'b0;
assign out[2] = (in == 2'b10) ? 1'b1 : 1'b0;
assign out[3] = (in == 2'b11) ? 1'b1 : 1'b0;
endmodule
- 分频逻辑
采用参数化设计
module clk_divider
#(
parameter DIV = 10
)
(
input clk,
input rst_n,
output out
);
reg out;
reg [7:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
out <= 0;
end else if (cnt == DIV - 1) begin
cnt <= 0;
out <= ~out;
end else begin
cnt <= cnt + 1;
end
end
endmodule
5. 基本工程结构
所有路径描述务必均使用相对路径,避免出现任何工程文件夹外的路径。
数字前端示例工程结构:
.
|-- doc
| `-- xxx.pdf
|-- lib
| `-- xxx
|-- output
| |-- netlist
| `-- gds
|-- prj
| `|-- makefile
| -- filelist.f
|-- src
| |-- rtl
| `-- sdc
|-- tb
| |-- data
| `-- tb_xxx.v
`-- work
|-- dc
|-- fm
|-- spyglass
|-- vcs
`-- verdi
6. 参考资料
设计:
Verilog中可综合与不可综合的语句 - 知乎 (zhihu.com)
综合工具-DesignCompiler学习教程 - 知乎 (zhihu.com)
使用 Design Compiler 评估 RTL 设计 - 知乎 (zhihu.com)
DC report_timing 报告分析(STA)_北方爷们的博客-CSDN博客
验证:
Coverage 用法总结 - Alvin’s Stage (alvinrolling.github.io)
基于SV简单的数字IC验证框架搭建_sv验证平台-CSDN博客
UVM项目之二:验证计划的编写_uvm验证方案怎么写-CSDN博客
测试:
设计文档模板v1.0
编写人:袁易扬
联系方式:2861704773@qq.com
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | 2024.7.26 | 初次发布 |
文档标题(请使用二级标题)
编写人:xxx
联系方式:xxx(建议填写常用邮箱)
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | YYYY.MM.DD | xxxx |
v1.1 | YYYY.MM.DD | xxxx |
...... |
1. 模块/芯片功能(请使用三级标题)
针对XXX目标于XXX工艺上设计模块/芯片,模块/芯片功能目标包括:
- 功能1
- 功能2
- 功能3
- ......
2. 模块/芯片架构
[芯片架构图,最好使用Visio或PPT绘制]
顶层模块/芯片XXX共包含以下一级子模块:子模块1,子模块2......所有一级子模块提供详细描述
2.1 一级子模块1
一级模块XXX,功能描述
[一级子模块1架构图]
共分为X个二级子模块,功能分别为.......(非重要的二级子模块只提供文字描述即可,不需要再单独列条目,更深层级子模块同理)
2.2 一级子模块2
一级模块XXX,功能描述
[一级子模块2架构图]
共分为X个二级子模块,功能分别为.......(非重要的二级子模块只提供文字描述即可,不需要再单独列条目,更深层级子模块同理)
2.3 ....
3. 模块/芯片端口
3.1 顶层模块/芯片端口
Port | Width | Direction | Function |
---|---|---|---|
clk | 1 | input | 时钟信号 |
rst_n | 1 | input | 低有效复位信号 |
addr | 11 | input | 地址信号 |
...... |
3.2 子模块1端口
Port | Width | Direction | Function |
---|---|---|---|
clk | 1 | input | 时钟信号 |
rst_n | 1 | input | 低有效复位信号 |
...... |
3.3 ...
4. 模块/芯片寄存器
Address | Name | Type | Function | Reset Value |
---|---|---|---|---|
0x00 | uid_reg | Read Only | A constant id register | 0x99 |
...... |
5. 模块/芯片存储器
Start Address | End Address | Size | Name | Function |
---|---|---|---|---|
0x0000_0000 | 0x0000_FFFF | 64KB | Instruction Memory | Store the instructions |
...... |
验证文档模板v1.0
编写人:袁易扬
联系方式:2861704773@qq.com
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | 2024.7.26 | 初次发布 |
文档标题(请使用二级标题)
编写人:xxx
联系方式:xxx(建议填写常用邮箱)
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | YYYY.MM.DD | xxxx |
v1.1 | YYYY.MM.DD | xxxx |
...... |
1. 验证说明(请使用三级标题)
针对XXX芯片/模块进行验证,验证方案为XXX,基于XXX工具进行验证,待验证芯片/模块设计功能目标包括:
- 功能1
- 功能2
- 功能3
- ......
2. 验证平台架构
[验证平台架构图,最好使用Visio或PPT绘制]
验证平台XXX共包含以下子模块:子模块1,子模块2......所有子模块提供详细描述
2.1 子模块1
子模块XXX,功能描述
[一级子模块1架构图]
共分为X个二级子模块,功能分别为.......(非重要的二级子模块只提供文字描述即可,不需要再单独列条目,更深层级子模块同理)
2.2 子模块2
子模块XXX,功能描述
[一级子模块2架构图]
共分为X个二级子模块,功能分别为.......(非重要的二级子模块只提供文字描述即可,不需要再单独列条目,更深层级子模块同理)
2.3 ....
3. 验证模块/芯片端口
Port | Width | Direction | Function |
---|---|---|---|
clk | 1 | input | 时钟信号 |
rst_n | 1 | input | 低有效复位信号 |
addr | 11 | input | 地址信号 |
...... |
4. 验证计划
Test Name | Test Method | Test Target |
---|---|---|
XXX功能测试 | 黑盒测试/白盒测试/灰盒测试 | 功能点符合设计目标/代码覆盖率100%/功能覆盖率100% |
...... |
5. 验证用例
Case Name | Description | Implementation |
---|---|---|
rst_testcase | 复位功能测试 | 1. 验证激励:rst_n=1; #10; rst_n=0; 2. 预期响应:内部寄存器全被复位为初始值 |
...... |
测试文档模板v1.0
编写人:袁易扬
联系方式:2861704773@qq.com
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | 2024.7.26 | 初次发布 |
文档标题(请使用二级标题)
编写人:xxx
联系方式:xxx(建议填写常用邮箱)
文档版本 | 编写日期 | 说明 |
---|---|---|
v1.0 | YYYY.MM.DD | xxxx |
v1.1 | YYYY.MM.DD | xxxx |
...... |
1. 测试说明(请使用三级标题)
针对XXX芯片/模块进行测试,测试方案为XXX,基于XXX工具进行测试,待测试芯片/模块功能目标包括:
- 功能1
- 功能2
- 功能3
- ......
2. 测试平台架构
[测试平台架构图,最好使用Visio或PPT绘制]
测试平台XXX共包含以下一级子模块:子模块1,子模块2......所有子模块提供详细描述
2.1 子模块1
一级模块XXX,功能描述
[一级子模块1架构图]
共分为X个二级子模块,功能分别为.......(非重要的二级子模块只提供文字描述即可,不需要再单独列条目,更深层级子模块同理)
2.2 子模块2
模块XXX,功能描述
[一级子模块2架构图]
共分为X个二级子模块,功能分别为.......(非重要的二级子模块只提供文字描述即可,不需要再单独列条目,更深层级子模块同理)
2.3 ....
3. 测试模块/芯片端口
Port | Width | Direction | Function |
---|---|---|---|
clk | 1 | input | 时钟信号 |
rst_n | 1 | input | 低有效复位信号 |
addr | 11 | input | 地址信号 |
...... |
4. 测试计划
Test Name | Test Method | Test Target |
---|---|---|
GPIO输出功能测试 | 使用JTAG接口为芯片烧录GPIO输出翻转程序,并使用示波器观察GPIO输出翻转情况 | GPIO产生翻转波形,波形完整且翻转时间符合设计预期 |
...... |
5. 测试用例
Case Name | Description | Implementation |
---|---|---|
rst_testcase | 复位功能测试 | 1. 测试激励:rst_n=1; #10; rst_n=0; 2. 预期响应:内部寄存器全被复位为初始值 3. 实际响应:通过JTAG接口观察到内部寄存器均被正确复位为初始值 |
...... |