吴费维,王逵,方昊,许浒
北京大学微处理器研发中心
高速I/O交互的物理设计和时序分析给ASIC设计带来了很大的挑战。传统的物理设计方法已经不能满足DDR内存控制器的设计要求。在北大众志863项目中,我们采取了一种实用的层次化设计方法来进行DDR内存控制器的物理设计,这种设计方法满足了DDR内存控制器的复杂的时序要求。
本文主要介绍了采用Synopsys工具的具体的物理实现流程,包括使用JupiterXT的顶层布局规划,部分模块的硬核化方法,Physical Compiler的物理综合策略,层次化设计的时钟树综合,以及最后的静态时序分析和ECO方法。
北大众志PKUNITY863-2CPU系统芯片是基于北大众志 UniCore-Ⅱ微处理器体系结构,采用TSMC0.18微米工艺,约400万门,主频达到400MHz的一款面向高性能多媒体网络计算机、高性能网络安全设备、IPTV终端设备、家用多媒体设备和数字电视等应用领域的系统芯片。内部集成USB2.0 OTG控制器、IDE 控制器、10M/100M/1000M以太网MAC、DDR-I内存控制器 和AC’97控制器等功能部件,具备MPEG1/2/4和H.264编解码等多媒体加速能力。芯片结构图如图1所示:
相对于北大众志PKUNITY863-1CPU系统芯片,为了解决处理器和外部数据交互慢这个瓶颈,在北大众志PKUNITY863-2CPU系统芯片中,我们采用了DDR-I内存结构代替SDRAM内存结构来提高数据传输率。
DDR内存结构包括外部的内存和芯片内部的DDR内存控制器。相对SDRAM结构,DDR内存结构使得数据的传输发生在时钟的上升沿和下降沿。在同样的频率下,数据传输率得到了成倍的增长,在DDR频率为166MHz时,数据传输率可以达到333MB/s。
但同时DDR内存控制器的设计复杂度大为提高,设计中包含了异步路径,单周期路径等等情况,并且对信号之间的同步提出了要求。这些要求已经超出了传统的同步时钟电路设计方法的能力。比如,对于DDR内存控制器信号之间的同步性,难以简单的完成。这个时候我们需要改变传统的设计流程,采用层次化的设计方法,完成复杂数字电路的设计。
本节主要介绍一下DDR内存控制器的特点,包括结构特点、时钟结构、时序特点以及设计的难点。
DDR控制器是系统芯片上用来直接和外部DDR内存交互的控制模块(结构如下图2所示),一方面它从总线取得命令和交互数据,另一方面通过IO单元与外部的内存交互。
核心逻辑包括控制逻辑和延迟补偿电路(Delay Compensation Circuitry, DCC),控制逻辑用来同步内存时钟,DCC控制和内存条交互的读写时钟。IO模块用来控制IO 单元的控制逻辑。
在控制器内部有四个时钟域,如下:
1. clk
控制器的系统主时钟,这个时钟从系统引入DDR控制器内部,所有被它驱动的寄存器都是同步的。
2. clk_wr
在对内存条进行写操作时候的写数据时钟,是由clk经过delay line 延迟四分之三周期得到,和clk是同步关系。
3 clk_dqs_out
在对内存条进行写操作时候的strobe信号(写滤波信号),是由clk经过delay line 延迟一个周期得到,和clk是同步关系。
4. read_dqs clock
从内存读数据时的读时钟,来自DDR内存条,输入片内后经过delay line延迟用来采样读入数据。
这四个时钟的逻辑关系如图3所示:
在写数据时候,clk_wr用来触发数据发出,clk_dqs_out送出片内用来作为DQS信号输入内存,clk_dqs_out的边沿应该在数据的中间位置,所以理想条件下clk_dqs_out需要比clk_wr延迟1/4个周期。如图4所示:
在数据读入时,DQS信号由片外输入的read_dqs产生,同样也要经过delay line 延迟得到,使得边沿发生在数据的中间。
DDR内存控制器的具体工作原理,在这里我们没有作进一步具体的阐述,请参见2006年的SNUG paper 《Getting DDRs “write” the 1x output circuit revisited》一文。
1. 设计必须满足设计的时序要求,达到目的频率。
2. 确保各个时钟之间的相位问题。
3. 满足各个时钟内部的扭斜问题。
4. 确保地址和命令输出时候的建立和保持时间。
5. 确保写数据时候,数据相对于DQS的建立和保持时间。
6. 在读数据时候,确保输入数据和DQS之间的相位问题,使得数据能够正确采集。
7. 满足clk差分时钟的输出。
本节主要介绍在北大众志863项目中,针对DDR内存控制器我们采用的层次化的设计方法。
在DDR内存控制器中有一些模块,由于时序的需求,我们将其先硬核化,然后做成milkyway库,在DDR内存控制器直接引用,作为reference lib。需要硬核化模块主要包括以下模块:
1. IO模块
它们直接和IO 单元相连,为了保证它们都尽量接近IO单元,以及保持信号的延迟尽量相等,我们将这些IO模块都进行硬核化。包括以下模块:io_dqscell, io_dmcell, io_datacell, io_controlcell。它们都不大,例如io_dmcell,如图5所示:
2. delay line 延迟模块
用来对时钟进行可控的延迟。包括对clk_wr,clk_dqs_out以及8个输入读时钟read_dqs的延迟。每个delay line都包括诺干delay element,由于延迟需要精确控制delay line的延迟,尽量需要每个delay element的延迟一致,所以进行硬核化处理。
3. dqs_in模块
对输入时钟进行门控转化的模块,由于其中包括很多的非同步路径,需要设置大量的set_max_delay来完成,并且为了使得8个读入时钟进入片内后延迟一致,也进行硬核化处理。
4. read_datablk模块
对输入数据进行同步并且有clk来采数据。由于数据同步要求高,以及有跨时钟路径,硬核化使得时钟和数据的延迟得以很好的控制。
以上模块硬核化采用以下流程进行硬核化:
为了使得DDR顶层布局方便,电源连接容易,我们硬核化的模块都没有power ring,而是直接通过标准单元的power rail连接出去。
在Astro中,读入引脚约束文件(TDF file)后,就算设置core to boundary为0,在core和boundary之间也会由于pin的原因,产生一个pin的距离。由于我们将模块做成一个multi-row的标准单元,需要core和boundary重合,所以必须对流程稍作修改。
模块布局规划时候不使用tdf文件,这样在之间不会在core和boundary之间由于pin而产生一个pin的距离。对于pin的调整,运用Astro中dump floorplan的命令导出pin位置,运用脚本修改pin的位置,再次运用load命令导入调整后pin的位置,到达了pin在单元边际之内的效果,如图6所示:
针对DRR内存控制器中较小的需要硬核化的模块,比如所有的IO模块,在项目中采用传统流程。首先floorplan时候根据cell大小,限定2-3row高度。由于cell较小,一般不超过10个标准单元,floorplan之后采用手摆的方法进行place,摆放的位置可参考netlist,根据标准单元之间的逻辑关系进行摆放,注意采用move命令摆放时候,选上snap to tail,标准单元可以自动对准row,并且根据power rail的位置,自动进行翻转。
摆放完以后,可以删除pin,运用select命令,选上所有pin,进行删除。之后进行布线,由于模块小采用3层net布线,可以满足要求。由于pin已经删除,提取FRAM之前,需要在net或者标准单元的pin上添加text,按照text提取FRAM VIEW。
需要注意的是,为了在DDR控制器内部,这些模块的power rail能够辨认和连接,在power rail上我们也添加了text。完成后的模块版图如图7所示“
针对DDR内存控制器中较大的需要硬核化的模块,硬核化成一个20row以下的标准单元。和2-3个row的模块相比,流程有所改变。首先在物理综合时候,由于包含的标准单元较多,我们不再采用手摆的方式,而是采用运用physical compiler进行物理综合,根据时序要求可以进行时序约束,针对比较复杂的时序,采用set_max_delay来约束。
但是对于delay line由于其特殊性,绝大部分是delay element,而且逻辑关系规整,为了使得delay element之间的延迟尽量相等,采用脚本进行place,采用的方法是dump floorplan 导出delay element的位置,根据delay element之间的逻辑关系,运用脚本修改位置,然后load这个文件就可。
其次较大的模块我们不删除pin。在floorplan时候根据时序和逻辑特点我们优化pin的位置,一直保留pin到布线。布线之后采取在运用dump floorplan命令导出pin的位置,运用脚本提取其中的的位置信息,在相应的位置添加上text。FRAM VIEW也按照text提取。
这样的好处是,首先由于这些模块pin的数量较多,相比以前删掉pin,然后再去一个一个找到net打text的方法,节约了大量时间。其次之所以还是按照text来提取FRAM VIEW,可以给顶层布线打来更大的自由度,因为text提取出来的pin信息,是原来pin所连接所有net的信息,和顶层的连接只要和这些net中的任意一点连接就可以。
对于delay line中的delay element硬核化时,也采用这种方法,因为发现进行delay line布线时Astro会尽量先采用delay element中已经有的布线,所以这么做可以使得delay line中delay element之间的布线非常规整,这样有利于使得每个delay element的延迟尽量接近。
为了减少芯片内部的延迟,DDR内存控制器放置在靠近DDR IO单元的附近。在北大众志863项目中我们将模块放在芯片右面,以及上下边的一部分,做成一个U型。
我们采用层次化设计,利用JupiterXT在设计顶层对DDR内存控制器设置为plan group。所有硬核化IO好的模块被放置在相应的IO单元附近,相应的时钟处理模块也被放在相应的位置。顶层物理综合之后,将DDR内存控制器模块设置为soft macro,这样我们可以单独对DDR内存控制器进行物理综合优化以及时钟树综合以及布线等步骤,增加项目的并行性。做成soft macro的DDR控制器在顶层芯片的位置如图8所示:
由于大部分复杂的时序问题我们已经通过模块硬核化得以解决,在DDR控制器物理综合时,主要关注于和芯片内部的时序问题。针对和硬核化模块相关的路径,如果顶层分析时,时序不满足,我们对其设置set_max_delay来解决。
同时物理综合还要解决拥塞问题,由于DDR控制器是U型,很狭长,非常容易引起拥塞问题,特别是在两个转弯处,通过多次物理综合得到较理想的DDR内存控制器的形状,如图9所示:
在设计中,时钟需要连入各种IO模块,由于他们的输入load相差较大,所以在时钟树综合时候采用限制transition的方法,transition控制在时钟周期的5%以内。在本次设计中,限制transition为0.2ns以内。
同时时钟树之间需要有一定的延迟差,这个需要在时钟树综合时候对时钟树进行调整,以满足设计的需求。在设计中clk_wr要比clk延迟3/4周期,clk_dqs_out要比clk延迟一个周期,这个延迟都是运用delay_line来达到的,所以应该使得除去delay line的延迟,clk,clk_wr,clk_dqs_out的延迟尽量一致。
我们将clk_wr,clk_dqs_out的时钟设置在相应的delay line的出口,从此处开始进行对应时钟树的综合。在进行clk时钟树综合时,对clk_wr,clk_dqs_out相应的delay line入口设置相应的sync pin。8个读入DQS时钟,由于经过的路径都已经硬核化,不需要时钟树综合。
由于在IO模块是几个标准单元组合的逻辑模块,它的时钟端口并没有如标准单元一样的时钟端口定义,需要设置sync pin来达到平衡的目的。其他需要设置sync pin的地方还包括一些delay line的控制信号产生的寄存器,否则时钟树综合时就不会把它当作时钟叶节点,这不是设计所需要的。具体流程如图10所示。
在布线之后,进行静态时序分析以及必要ECO处理。我们在边界没有采用传统的timing budget的方法,而是采用了内部路径的方式,采用qtm(quick timing model)将外部的DDR内存条以及之间的连线模型化。
例如对于io_dmcell的边界时序,处理后如图11:
先利用PrimeTime的qtm模型建立外部的DDR内存条时序模型以及之间的连线的时序模型。
例如DDR内存条时序模型:
create_qtm_model ddr_sdram
create_qtm_port -type clock CK
create_qtm_port -type clock CK_n
create_qtm_port -type input CKE
set ctrl_signal {CS_n, RAS_n, CAS_n, WE_n}
set addr_signal {BA1 BA0}
for {set i 0} {$i<=13} {incr i} { lappend addr_signal A$i }
foreach s [concat $addr_signal $ctrl_signal] {
create_qtm_port -type input $s
create_qtm_constraint_arc -edge rise -setup -value $tIS -from CK -to $s
create_qtm_constraint_arc -edge rise -hold -value $tIH -from CK -to $s
}
set data_signal {}
for {set i 0} {$i<64} {incr i} { lappend data_signal DQ$i }
for {set i 0} {$i<8} {incr i} { lappend data_signal DM$i }
foreach s $data_signal {
create_qtm_port -type input $s
create_qtm_constraint_arc -edge rise -setup -value $tDS -from CK -to $s
create_qtm_constraint_arc -edge rise -hold -value $tDH -from CK -to $s
create_qtm_constraint_arc -edge rise -setup -value $tDS -from CK_n -to $s
create_qtm_constraint_arc -edge rise -hold -value $tDH -from CK_n -to $s
}
for {set i 0} {$i<8} {incr i} {
create_qtm_port -type inout DQS$i; set s DQS$i
create_qtm_constraint_arc -edge rise -setup -value [expr $tCK-$tDQSSmax] -from CK -to $s
create_qtm_constraint_arc -edge rise -hold -value $tDQSSmin -from CK -to $s
}
for {set i 0} {$i<8} {incr i} {
create_qtm_port -type clock DQSrd$i; set s DQSrd$i
create_qtm_delay_arc -edge rise -from CK -to $s -value 0; #DQSCK
create_qtm_delay_arc -edge rise -from CK_n -to $s -value 0;
}
save_qtm_model -format db -output ddrsdram –lib
在设置了DDR内存条时序模型以及之间的连线的时序模型以及它们相应的延迟后,本来的边界路径变为内部路径,使得静态时序分析简单易懂。
在静态时序分析的基础上,针对出现的时序问题,进行必要的ECO,方法如下。
1. setup time violation
由于信号完整性等问题的存在,布线之后会出现一定的时序问题,有些在DDR控制器顶层,有些在硬核化的模块中。采取以下方法修复:
一是size cell。这是最主要的一种方法,对于delta比较大的net,寻找驱动它的cell,将cell sizing为驱动能力较强的cell。如果这个cell已经是型号很大了,没有sizing的余地,可以继续往上寻觅,找到引起transition突然变大的、驱动能力不强的cell进行sizing。
二是net double spacing。对于delta较大的net,可以到版图里面看一下,如果这条net附近有较长的、近距离并行的、同层金属的net,那么可以设置double spacing,减小串扰得影响。
三是shielding。这是很少使用的方法。Shielding Net可以在连线旁边添加Ground Net环,将SI基本减到很小。
四是调整时钟树。如果源端和末端的clock network delay相差较大引起setup violation,可以通过在末端寄存器的时钟路径上插buffer调整。
五是手修连线。手动使用get_attr [get_net {netname}] effective_aggressors报出与特定连线耦合相关的nets,并用不同的颜色标示出这些连线,通过改变这些连线与目标连线之间的相对位置,来进一步减小信号之间的串绕。手修是在前面的方法均已试完的情况下采取的最后方式。
修hold的方法之一是插buffer。插buffer的时候首先要确认setup time的margin有多大,找到一个不会引起setup time violation的地方插入buffer。
3. 修transition 和电容的violation
对于有transition和电容violation的地方,大都是由于连线过长、驱动不足造成的。可以在不影响时序的情况下采用插入buffer增加驱动、插入buffer使连线变短、挪动cell位置使连线变短的办法。
本文介绍一种比较实用的DDR内存控制器的物理设计方法,包括从顶层划分到最后ECO。事实证明这套方法是切实可行的,给我们的工作带来了很大的便利。Synopsys的工具给我们提供了很多的方便,特别是模块的硬核化以及qtm的模型化时序分析,我们同时希望Synopsys今后能够不断革新,给我们用户带来更多的方便。
文章评论(0条评论)
登录后参与讨论