18

棋子 · 2023年09月18日

IC设计思维01_复用思维:增加复用性的6种方法

很多芯片在设计之初,就已经考虑如何增加代码的复用性,尽量减少工作量,降低错误概率。

增加复用性的几个场景:

  • 不同项目之间的代码复用性
  • 不同工艺之间的代码复用性
  • 同一个模块例化多份,分别工作在不同模式下
  • 同一个项目不同环境(RTL验证,FPGA demo 验证)之间的代码复用性                

本章节将简单谈谈几种增加代码复用性的方法。

1、基础模块IP化

在各家ASIC/FPGA项目的代码目录中,我们经常能看到各类小的基础模块,例如各类跨时钟模块、各类调度仲裁模块、各类RAM读写模块、各类总线接口模块等等。它们可能命名为share_ip_ 或 base_ip_ 或 cmn_ip_ ,又或者其他名称,几乎每个设计者都需要用到这些基础模块。

我们在需要实现其相关功能时,只需要例化模块即可,简单高效,有降低了bug概率。

2、模块参数化

在进行模块设计时,我们需要尽量保证模块参数化,尽量避免使用立即数(例如10’d0)。

被参数化的信号可能是数据位宽,用户数量或者其他类型的信号。

module  ip_bus_sync #( // 
    parameter   DATA_WDTH                       =       16                                      ,   //
    parameter   INI_VALUE                       =       {DATA_WDTH{1'b0}}                           //
)(
    input                                               i_src_clk                               ,   //
    input                                               i_src_rst_n                             ,   //
    input               [DATA_WDTH-1:0]                 i_src_din                               ,   //
    input                                               i_dst_clk                               ,   //
    input                                               i_dst_rst_n                             ,   //
    output  reg         [DATA_WDTH-1:0]                 o_dst_dout                                  // 

);


//逻辑代码

endmodule

3、宏定义区分代码分支

ASIC项目的代码一般至少有两个版本:ASIC版本和验证版本(FPGA/加速器)。部分公司还会同时出两个系列的芯片,ASIC系列和FPGA系列。因此我们通常需要通过宏定义区分不同的代码分支和参数

`ifdef FOR_ASIC_DESIGN
  //ASIC  logic
  //参数定义
`else
  //其他分支逻辑
  //参数定义
`endif
`ifdef FOR_ASIC_DESIGN


generate
genvar  i;

for ( i=0; i<DATA_WDTH; i=i+1 )
begin : SDFFY2D_INST

SDFFY_*CELL_TYPE*  SDFFY2D   //此处CELL_TYPE指的是具体的器件型号
(    
.CK   (i_dst_clk),
.D    (i_src_din[i] ),
.Q    (o_dst_dout[i]),
.SI   (1'b0     ),   //DFT 输入信号,由DFT工程师在网表中完成连线
.SE   (1'b0     )    //DFT 使能信号,由DFT工程师在网表中完成连线
);

end
endgenerate

`else

reg  [(DATA_WDTH-1):0]   din_d0;       //
reg  [(DATA_WDTH-1):0]   din_d1;       //

assign o_dst_dout = din_d1;

always @( posedge i_dst_clk ) 
begin
din_d0  <= i_src_din;
din_d1  <= din_d0;
end

`endif

     

4、使用参数选择代码分支

在同一个宏定义分支下(例如同在ASIC或者FPGA项目),我们可能需要奖模块例化多份,以支持如下场景:

Case1:同一个模块,工作在同的模式下,为了节约资源,只需要保留对应模式的代码逻辑。

Case2:同一个模块,其支持的功能数量不同,所需要的RAM等资源也不相同,需要例化不同规格的RAM。

module xxxxx
#(
    parameter   FUNCTION_MODE   =       `MULTI_FUNCTION             
)
(
   //各类IO信号
) ;


generate

if (FUNCTION_MODE==`MULTI_FUNCTION) begin:MULTI_FUNCTION_CODE

     //多function 逻辑  

end

else begin:SINGLE_FUNCTION_CODE

    // 单function 逻辑

    end      

end
endgenerate

5、IP接口隔离

不同Vendor的IP的用户侧接口大概率是不一样的,为了避免因为IP替换导致的大量代码修改,可以在设计之处就考虑将IP接口隔离。例如通过2类接口转换模块(控制类和数据类),将所需要的控制信号和数据流信号转换成通用的内部信号,这样无论怎么替换IP,都只需要修改少量代码。

image.png

6、std cell 隔离

我们通常会将std cell外包一层或者多层代码,这样就能将工艺与设计代码尽量分离。

常见的有bit同步器,ram,clk-gating,clk mux等模块。如下是单bit同步器的案例。

module  ip_bit_sync #( parameter      DATA_WDTH = 1    // bit width)(input  wire                     i_dst_clk,   // destination clockinput  wire [(DATA_WDTH-1):0]   i_src_din,   // data inputoutput wire [(DATA_WDTH-1):0]   o_dst_dout   // data output);`ifdef FOR_ASIC_DESIGNgenerategenvar  i;for ( i=0; i<DATA_WDTH; i=i+1 )begin : SDFFY2D_INSTSDFFY_*CELL_TYPE*  SDFFY2D   //此处CELL_TYPE指的是具体的器件型号(    .CK   (i_dst_clk),.D    (i_src_din[i] ),.Q    (o_dst_dout[i]),.SI   (1'b0     ),   //DFT 输入信号,由DFT工程师在网表中完成连线.SE   (1'b0     )    //DFT 使能信号,由DFT工程师在网表中完成连线);endendgenerate`elsereg  [(DATA_WDTH-1):0]   din_d0;       //reg  [(DATA_WDTH-1):0]   din_d1;       //assign o_dst_dout = din_d1;always @( posedge i_dst_clk ) begindin_d0  <= i_src_din;din_d1  <= din_d0;end`endifendmodule
作者:IC小鸽
文章来源:IC的世界

推荐阅读

更多IC设计干货请关注IC设计专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
11668
内容数
1232
主要交流IC以及SoC设计流程相关的技术和知识
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息