Loading

对IC Flow的再反思

最近测试有些进展,但也碰到了许多令人尴尬的问题。

但问题不大,吸取经验教训才能进步。

说回到这次碰到的问题。片上做的i2c接口实测时发现读取出现问题,体验了一波从实测追溯到仿真的过程。具体来说:

  1. 如果有一套fpga代码有一套asic代码,版本管理做好,确保一致性

  2. fpga验证pass不能代表asic代码就没问题,该仿真的地方得仿真覆盖,不能跳过

  3. 具体来说的流程:设计文档编写->RTL编写->RTL仿真验证->spyglass检查->FPGA验证->dc综合->dc网表fm检查->dc网表仿真验证->后端pnr->后端网表fm检查->后端网表验证仿真->LVS检查,如果出了问题就是倒过来查验一遍

  4. 涉及数模接口的部分必须混仿覆盖到

之前一直偷懒,跳过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编辑器使用。

设计文档格式可参考《设计文档模板》,内容需要包括:

  1. 模块/芯片功能描述(描述模块/芯片整体功能)
  2. 模块/芯片架构描述(包含框图以及子模块功能基本描述)
  3. 模块/芯片端口(使用表格进行描述,表格中需要包含以下内容:Port 端口名;Width 端口位宽;Direction 端口方向; Function 功能描述)

如果存在模块/芯片存储器和存储器也需要进行描述:

  1. 模块/芯片寄存器(使用表格进行描述,表格中需要包含以下内容:Address 地址;Name:寄存器名;Type:功能(读写/只读/只写); Function 功能描述;Reset Value 复位值)
  2. 模块/芯片存储器(使用表格进行描述,表格中需要包含以下内容:Start Address 起始地址; End Address 终止地址;Size 存储器尺寸;Name 存储器名;Function 功能描述)

验证文档格式可参考《验证文档模板》,内容需要包括:

  1. 验证说明描述(描述要验证的模块,验证的方案,验证的工具,待验证的功能目标)
  2. 验证平台架构(包含框图以及子模块基本功能描述)
  3. 验证模块/芯片端口(使用表格进行描述,表格中需要包含以下内容:Port 端口名;Width 端口位宽;Direction 端口方向; Function 功能描述)
  4. 验证计划(使用表格进行描述,表格中需要包含以下内容:Test Name 测试名;Test Method 测试方法;Test Target 测试目标)
  5. 验证用例(使用表格进行描述,表格中需要包含以下内容:Case Name 用例名;Description 用例描述; Implementation 用例的验证激励和验证响应)

测试文档格式可参考《测试文档模板》,内容需要包括:

  1. 测试说明描述(描述要测试的模块,测试的方案,测试的工具,待测试的功能目标)
  2. 测试平台架构(包含框图以及子模块基本功能描述)
  3. 测试模块/芯片端口(使用表格进行描述,表格中需要包含以下内容:Port 端口名;Width 端口位宽;Direction 端口方向; Function 功能描述)
  4. 测试计划(使用表格进行描述,表格中需要包含以下内容:Test Name 测试名;Test Method 测试方法;Test Target 测试目标)
  5. 测试用例(使用表格进行描述,表格中需要包含以下内容:Case Name 用例名;Description 用例描述; Implementation 用例的测试激励,预期响应和实际响应)

此外文档需要注明以下信息:

  1. 文档作者
  2. 作者联系方式
  3. 文档版本
  4. 文档编写日期

若文档存在历史版本,需要说明各版本修改信息。

4. 数字编码规范

主要参考华为内部编码标准。以下规范均只涉及可综合设计部分,对于testbench以及第三方ip不应用以下规范。

4.1 设计风格

  1. 低电平有效的信号,信号名后缀"_n"
  2. 模块名统一使用小写+下划线方式风格,例如"test_module"
  3. 模块例化使用u_xx表示,需要多次例化的模块使用序号表示(0、1、2),例如"u_test_0"
  4. 使用降序定义向量位宽,最低位为0,例如"wire [3:0] vector"
  5. 采用小写字母定义wire,reg和input/output
  6. 采用大写字母定义参数,参数名小于20个字母,例如"parameter PARAM = 2'b00"
  7. 时钟信号应前缀"clk",复位信号应前缀"rst"
  8. 对于一个时钟上产生分频时钟应后缀分频比例,例如"clk_128",表示clk信号分频128倍后产生的时钟
  9. 代码中不能使用VHDL,Verilog或SystemVerilog的保留字
  10. 在进行模块声明时,按照如下顺序定义端口信号:输入、输出,例如:
module test(
	input  a,
    input  b,
    output c
);
  1. 不要书写空的模块,每个模块至少有一个输入和一个输出
  2. 时钟事件必须要以边沿触发的形式书写,即"posedge <clk_name>"或"negedge <clk_name>"
  3. 异步复位,高电平有效使用"if(<asynch_reset>)",低电平有效用"if(!<asynch_reset>)"
  4. 代码中给出必要的注释
  5. 每个文件应包含一个文件头,包含作者,日期等基本信息,即
//--------------------------------------------------------------------
//  ___  _____ ______   _______       ________  ___  _________   
// |\  \|\   _ \  _   \|\  ___ \     |\   __  \|\  \|\___   ___\ 
// \ \  \ \  \\\__\ \  \ \   __/|    \ \  \|\ /\ \  \|___ \  \_| 
//  \ \  \ \  \\|__| \  \ \  \_|/__   \ \   __  \ \  \   \ \  \  
//   \ \  \ \  \    \ \  \ \  \_|\ \ __\ \  \|\  \ \  \   \ \  \ 
//    \ \__\ \__\    \ \__\ \_______\\__\ \_______\ \__\   \ \__\
//     \|__|\|__|     \|__|\|_______\|__|\|_______|\|__|    \|__|                         
//
// COPYRIGHT 2023, ALL RIGHTS RESERVED
// Institute of Microelectronics, Chinese Academy of Sciences
// Beijing Institude of Technology
//
// Filename:    
// Author:      
// Date:        
// 
// Project:     
// Description: 
//--------------------------------------------------------------------
  1. 每个文件只包含一个模块
  2. 模块名与模块名保持一致,例如模块命名为"module test",则文件名必须为"test.v"
  3. 模块名或变量要使用缩写时请参考缩写规范:(382条消息) 【精】Verilog语言缩写规范_verilog 常用缩写_heartdreamplus的博客-CSDN博客

4.2 设计可靠性

  1. 同步时序逻辑的always block中有且只有一个时钟信号,并且所有在同一个边沿动作(如上升沿)
  2. 采用同步设计,避免使用异步逻辑(全局异步复位除外)
  3. 避免将时钟信号作为数据信号输入
  4. 不要在时钟路径上添加任何buffer(即让原始的时钟信号穿过任何逻辑再输出到其他模块作为时钟)
  5. 不要在复位路径上添加任何buffer(即让原始的复位信号穿过任何逻辑再输出到其他模块作为复位)
  6. 在顶层模块中,时钟信号必须可见
  7. 不要采用向量的方式定义一组时钟
  8. 建议使用单一的全局同步复位电路或者单一的全局异步复位电路
  9. 不使用不可综合的语法
  10. 不使用不可综合的运算符
  11. 避免使用inout端口
  12. 避免在多个逻辑块中驱动同一个信号
  13. 时序always块禁止使用电平驱动
  14. 数据位宽要匹配
  15. 时序逻辑块统一使用非阻塞赋值(<=)
  16. 组合逻辑块统一使用阻塞赋值(=)
  17. 避免产生latch
  18. 避免产生异步数据环路

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

以下常用模块参照模板格式进行编码:

  1. 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
  1. 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
  1. 译码逻辑

针对简单的译码逻辑可以使用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
  1. 分频逻辑

采用参数化设计

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注意事项

Verilog中可综合与不可综合的语句 - 知乎 (zhihu.com)

综合工具-DesignCompiler学习教程 - 知乎 (zhihu.com)

使用 Design Compiler 评估 RTL 设计 - 知乎 (zhihu.com)

DC report_timing 报告分析(STA)_北方爷们的博客-CSDN博客

xxx芯片详细设计模板.doc (book118.com)

验证:

Coverage 用法总结 - Alvin’s Stage (alvinrolling.github.io)

基于SV简单的数字IC验证框架搭建_sv验证平台-CSDN博客

UVM项目之二:验证计划的编写_uvm验证方案怎么写-CSDN博客

验证计划文档模板_ic验证计划模板-CSDN博客

测试:

芯片测试报告模板 - 百度文库 (baidu.com)

设计文档模板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. 功能1
  2. 功能2
  3. 功能3
  4. ......

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. 功能1
  2. 功能2
  3. 功能3
  4. ......

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. 功能1
  2. 功能2
  3. 功能3
  4. ......

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接口观察到内部寄存器均被正确复位为初始值
......
posted @ 2024-07-26 12:56  sasasatori  阅读(260)  评论(0编辑  收藏  举报