ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Memory Compiler参数配置与SRAM生成优化实战:从原理到PPA调优

Memory Compiler参数配置与SRAM生成优化实战:从原理到PPA调优 一开始接触Memory Compiler的时候我其实挺不以为然的。那时候总觉得不就是跑个脚本生成一个SRAM嘛参数填一填仿真没问题Lib一给后端该怎么做就怎么做。直到后来项目里芯片面积爆炸、时序收敛困难被追着查了一个多月才发现问题全出在memory配置上——bank切分不合理、列复用选错、甚至写穿write-through模式导致的动态功耗超标。从那以后我才真正明白Memory Compiler参数配置不是填表那么简单它直接决定了一颗芯片的PPAPower、Performance、Area能不能达到设计预期。这篇文章不聊那些EDA工具的UI操作教程而是把我在数字芯片后端设计中做Memory Compiler参数配置与SRAM生成优化时踩过的坑、总结的经验、梳理过的原理系统性地捋一遍。适合刚接触后端流程的工程师也适合那些已经会跑流程但对“为什么这么配”还不太清楚的同行。1. 为什么SoC里到处是生成出来的SRAM1.1 从寄存器堆到SRAM的必然选择做数字芯片的都清楚芯片里除了标准单元逻辑剩下的大头几乎全是存储器。小的寄存器堆Register File可以用标准单元搭但一旦容量到了几十KB甚至几MB级别再用标准单元去搭面积和功耗是完全不可接受的。原因也很直接标准单元存储位比如D触发器至少需要二十多个晶体管而一个SRAM的6T存储单元只有6个晶体管实际工艺中往往还有额外的读写辅助管密度差距在4到10倍以上。所以大容量存储业界基本都用SRAM而这个SRAM绝大多数情况下是由Memory Compiler自动生成的。你可能会问能不能自己画一个SRAM可以但那是全定制设计Custom Design团队的活周期长、验证复杂、成本极高。对于数字芯片后端设计师来说更务实的做法就是用Memory Compiler在给定的工艺PDK下通过配置参数快速生成一套完整的SRAM硬核hard macro里面既有物理版图也有时序模型、功耗模型和仿真模型。这也是业界标准做法。1.2 Memory Compiler到底帮你做了什么事说直白一点Memory Compiler就是一个“SRAM建筑队”。你告诉它要盖多大的楼存储容量、开几扇门数据位宽、用什么样的结构单端口、双端口、寄存器输出它负责把楼盖好竣工后交付全套图纸。具体到后端设计里一套成熟的Memory Compiler产出物至少包含物理版图GDSII最终要放进芯片版图里的东西。抽象视图LEF/Astron给布局布线工具用的包含引脚位置、障碍区域。时序库.lib / .db综合时序分析与收敛用的。功能模型.v / .vhd仿真验证用。功耗模型.pw / .saif / .lib中的功耗信息做功耗分析时用。版图验证文件.lvs / .drc规则适配确保最终物理验证不出问题。这里面的每一步其实都受你配置的参数影响。很多同事只盯着容量和位宽填忽略了诸如列复用Column Mux、Bank切分、功耗模式、延迟模式这些细节结果生成的memory尺寸、速度和功耗性能很差。后面我会重点展开。1.3 从项目全局看SRAM的重要性一颗典型的SoC里SRAM面积往往能占到30%到50%甚至在高性能AI芯片里占比更高。这就意味着如果memory面积多出来哪怕10%整颗die可能就要加大一个等级成本直接飙升。时序方面SRAM的访问延迟通常是关键路径的主要组成部分频率上不去很多时候就是memory的CLK-to-Q太慢。功耗层面SRAM的漏电在先进工艺下占了相当比例如果没选好retention模式待机功耗可能超标。所以SRAM生成优化从来不是“跑个脚本”这样简单的事。它是数字芯片后端设计里需要非常认真对待的一个环节。下面我把原理和参数配置拆开来讲。2. SRAM工作原理与关键参数背后的门道2.1 SRAM存储单元与读写过程SRAM的全称是Static Random-Access Memory静态随机存取存储器。所谓“静态”是指只要不掉电存储的数据就不会丢失不需要像DRAM那样周期性刷新。这背后的核心就是6T存储单元两个交叉耦合的反相器4个晶体管构成一个双稳态触发器负责锁定0或1。两个访问管2个晶体管由字线Word Line, WL控制负责连接存储节点和位线Bit Line, BL/BLB。读操作时先把位线预充到高电平然后拉起字线。假如存储节点存的是0那么对应的位线就会被下拉位线之间产生一个微小电压差由灵敏放大器Sense Amplifier放大成完整的逻辑电平输出。写操作则相反先把要写的数据强驱动到位线上再拉起字线直接“压过”存储单元的内部状态完成写入。这个读写的物理过程决定了SRAM的速度和功耗。敏感放大器、预充电路、写驱动器的能力都是Memory Compiler在后台根据你选的工艺和参数自动优化的。2.2 为什么大容量SRAM内部需要复杂的寻址电路既然每bit都靠6个晶体管存储那如何从成千上万个存储单元中找到你要访问的那一个答案就是行译码和列选择。一个深度为Depth、位宽为Width的SRAM内部物理上会组织成行Row和列Column。行译码器Row Decoder负责把地址的一部分翻译成具体某一行拉高该行的字线列选择逻辑Column Mux则负责从多列中选出对应的那几列连接到IO。大容量SRAM里整个存储阵列还要被切分成多个Bank阵列块一是为了降低字线长度减少RC延迟二是为了降低位线长度减少寄生电容和功耗。这也就是你看到的memory总面积里除了6T存储核心还有一大部分是外围电路的原因。在实际项目中当你拿到Memory Compiler生成的RAM面积报告时可以明显看到array面积和overhead面积的比例。如果overhead占比过高通常是因为bank切分过多或列复用过大这个后面在优化部分细说。2.3 从DRAM对比看懂SRAM的架构优势很多人在学习时会拿SRAM和DRAM做对比。DRAM是动态随机存取存储器存储单元由一个晶体管加一个电容组成靠电容上的电荷保持数据所以需要定期刷新否则电荷漏完数据就丢了。因为单元结构更简单DRAM密度比SRAM高很多价格也低所以内存条这类大容量存储都用DRAM。而SRAM不需要刷新访问速度更快和逻辑工艺兼容性好6T结构可以直接用标准逻辑工艺制造所以在芯片内部缓存、寄存器堆、缓冲队列这些场景下占据绝对优势。代价就是单元面积大成本高。在SoC中你会看到工程师精心规划到底哪部分用SRAM、哪部分用DRAM Controller去接外部DRAM本质就是在性能和成本之间做取舍。这些原理听起来像是大学教材内容但我建议后端工程师还是要把它们记牢因为当你配置Memory Compiler时几乎所有选项都在直接操作这些物理结构。你选了多大的Column Mux直接决定了列选择电路的复杂度你切不切bank直接影响字线和位线的负载。3. Memory Compiler参数配置实操解析3.1 最常见也最容易被忽视的核心参数从工程角度配置Memory Compiler最核心的参数有这么几组容量类参数存储深度Depth、数据位宽Width这俩一乘就是容量。结构类参数端口类型单端口、伪双端口、真双端口、Bank数量、Column Mux列复用比、输出寄存器Pipeline/Registered Output、Byte Write功能、ECC支持等。功耗类参数工作电压VDD、保持电压Retention Voltage、漏电优化等级、功耗模式引脚Sleep、Shutdown等。时序类参数建立时间、保持时间、CLK-to-Q的目标值有的Compiler允许你选择normal还是high speed的bitcell。很多新人容易犯的错是只把深度和位宽填好其他一律默认。默认参数不是不能用但往往不是最优解。比如同样一个4KB的memoryColumn Mux从2改成4面积可能小一些但访问时间会变慢反过来如果选Column Mux1速度最快但面积最大。没有“绝对正确”的参数只有“适合当前设计”的参数。3.2 参数配置的链路逻辑与推荐顺序在实际项目里我习惯按照下面这个逻辑顺序去配置参数先确认容量需求这通常来自架构师或系统规格。深度、位宽、是否需要byte write字节写入使能必须一开始就定死。再选端口类型单端口1RW、伪双端口1R1W、真双端口1R1R或1R1W独立时钟这个取决于数据通路的读写并发需求。伪双端口面积比真双端口小很多如果读写时钟同频且不需要同时随机访问优先用伪双端口。然后定物理结构Bank数和Column Mux一起看。Clock频率高就要控制每一位线对应的存储单元数可以通过增加Column Mux来减少列数但这会影响单次访问的数据位。接着选功耗特性是否需要Sleep模式、Retention模式如果芯片有低功耗需求这个必须提前打开。注意retention模式下数据能否保持取决于Compiler使用的bitcell类型。最后是输出时序选项是否打一拍寄存器输出Registered Output这对后端时序收敛非常关键。打一拍后CLK-to-Q变快实际上是输出被寄存器重新定时但多了一个cycle的读延迟面积和功耗也会增加。这套顺序的本质是先满足功能再优化功耗面积最后处理时序。顺序反了很容易反复迭代。3.3 特殊引脚解析EMA、Sleep、RetentionMemory Compiler生成的SRAM除了基本接口CLK、CEN、WEN、A、D、Q之外还经常会看到一些特殊控制引脚比如EMA、SL、DS、SD等。这些引脚很多人遇到时一头雾水我这里挑几个重要的讲一下。EMA引脚在部分Compiler生成的SRAM中EMAExternal Memory Access用于测试或调试模式下的外部访问控制。当你把EMA置为有效时可以从外部直接控制内部存储阵列的访问路径方便做一些DFT可测性设计或bring-up阶段的检查。如果设计中没有这种需求可以在配置时关掉这个引脚以节省一点面积。注意EMA相关逻辑本身会带来面积和时序开销不用就不要开。Sleep引脚SL用于把SRAM切换到低功耗睡眠模式。睡眠模式下存储数据会丢失具体看Compiler类型有些是用Power Gating直接关掉阵列电源。适合那些可以随时重新加载数据的缓存场景。Retention引脚SD/DS用于把SRAM切换到数据保持模式阵列电源电压降到保持电压不读写数据但存储内容不会丢。这个非常适合需要待机且掉电不能丢数据的场景比如物联网芯片里的配置寄存器备份区。这些引脚的激活和退出时序都需要和芯片的电源管理单元PMU协同设计。我在实际项目中见过不止一次因为Retention控制信号时序没算好导致芯片在唤醒瞬间读到了乱码。一定要让前端设计工程师在RTL阶段就把这些信号的行为描述清楚后端才能把时序约束做对。3.4 一个典型配置实例与面积/时序影响估算假设我们要生成一个容量为256KB、位宽256bit、深度8192的SRAM给AI加速器做line buffer。芯片目标频率1GHz。这里的关键矛盾是位宽很宽256bit如果直接全部并行输出数据总线会很宽但这恰恰是加速器需要的。那么后端要怎么权衡面积和时序我用常见28nm工艺做个粗略估算bitcell面积大约0.13平方微米256KB 256×8 2048Kbit。bitcell总面积为2048K乘以0.13平方微米约等于266240平方微米也就是0.27平方毫米左右。加上外围电路通常占到30%到50%总面积大约0.35到0.40平方毫米。如果我把Column Mux设为4意味着每一行对应的数据位会被分成4组通过4选1的列选择电路接到IO。好处是位线负载变小访问速度更快坏处是列选择电路和IO数量的安排会更复杂。实际跑下来在64nm以下工艺节点Column Mux4通常是时序和面积之间比较均衡的选择。在Memory Compiler里你还会看到bank切分选项。比如8192深度的RAM如果你切成2个bank每个bank深度4096那么字线负载就减半时序更好但总的外围电路开销更大。到底值不值建议拿Compiler实际生成几组配置跑一轮lib对比用数据说话不要拍脑袋。4. SRAM生成全流程与落地细节4.1 生成前的环境准备与工艺选择这一步相比很多人的理解要更琐碎。首先确认工艺库版本不同工艺节点比如28nm、22nm、16nm、7nm的Memory Compiler版本不同对应PDK里的bitcell模型也不同。打开Compiler之后第一件事就是选对工艺角SS、FF、TT等和电压条件。这里的电压条件是关键因为SRAM在低压下性能下降非常明显选错工作电压会导致lib时序完全不可用。其次留意工具版本和license模块。Memory Compiler一般按容量或生成次数收费license不够的时候会干脆不让你跑。另外新版本工具生成的GDS可能和老版本有兼容问题如果一个项目组多人协作最好统一工具版本。最后最好准备一个专门的工作目录按memory类型子目录隔离比如linebuf、fifo、regfile。每个memory生成时把生成的报告、lib、v、GDS归档清楚。不要小看这一步我在项目中见过有人把几十个memory全混在一个目录里后期找东西全靠猜非常痛苦。4.2 参数配置脚本示例现在主流Memory Compiler都支持脚本化或Tcl命令行配置。下面是一个简化版的配置示例帮助你理解整个流程的逻辑# 创建工程 create_project -name sram_256x128 -technology tech28hpc # 配置基本参数 set_memory_type -type single_port set_memory_size -depth 256 -width 128 set_column_mux -value 4 set_bank_count -value 1 # 功耗相关 set_power_mode -sleep_enable true set_retention_enable true set_retention_voltage 0.7 # 输出选项 set_output_registered true set_scan_ff true # 生成 generate_memory注意不同工具命令词会有差异但概念一致。配置完成后工具会在目录下生成全套文件清单。我建议把脚本和关键参数写进一个README方便项目交接和回溯。所谓“生成优化”很大一部分就是在这类小事情上做规范。4.3 生成产物解读如何快速判断生成的SRAM质量每次生成完先别看波形直接看报告。Memory Compiler一般会给出面积、功耗、时序报告这些是项目评估的第一手数据。我通常会重点看这几个指标总周长和总面积和预估相比差多少面积有没有异常。时序路径报告尤其是地址到数据输出的delay对比.lib里的CLK-to-Q是否合理。功耗拆分动态功耗、内部功耗、漏电功耗各占多少sleep模式下的保持功耗是不是可以接受。物理约束文件里的端口位置端口是否均匀分布在边界上会不会给后端的布局布线造成瓶颈。如果生成的memory面积比预期大很多先怀疑是不是深度位宽算错了位bit和byte换算错是极常见的再看是不是特殊功能开多了比如打开了ECC、DFT、冗余修复这些都会明显增大面积。4.4 将SRAM集成到后端流程中的关键步骤拿到memory硬核后后端流程中要做的核心步骤有Floorplan阶段根据SRAM的尺寸和端口位置把它们放到合理的物理位置。多bank大容量的SRAM一般占用大片面积摆放时要考虑数据通路的方向避免后续布线绕远。尤其要关注memory的端口密度如果端口全挤在一边那后端的拥堵就不可避免。布局布线阶段SRAM硬核内部已经固定不能改所以它周围的标准单元布局要和SRAM的引脚位置协调。memory附近尽量不要放太多高驱动单元一方面电源/地绕线会困难另一方面噪声也可能影响SRAM稳定性。时序收敛阶段SRAM的时序模型是.lib文件提供的综合工具和布局布线工具都会用它。这里特别提醒SRAM的hold time通常比较敏感尤其是write操作。如果hold违例重灾区往往在memory的数据输入引脚。经验做法是在group path时对memory相关路径做特殊处理或者为寄存器输出模式留出余量。功耗分析阶段用.lib里的功耗数据 网表翻转率VCD/SAIF算功耗。SRAM在低功耗模式下有专门的功耗行为一定要把sleep/retention的控制波形仿真进来否则漏电功耗严重被低估。4.5 生成优化与迭代策略生成优化不是一次跑完就完事往往是多轮迭代。我常用的方法是做一组“配置矩阵”比如保持容量不变跑Column Mux2、4、8输出寄存器开与关bank 1与2然后把每种配置的面积、时序、功耗汇总成表格交给前端和架构一起决策。这里给一个简化的对比示例配置方案Column MuxBank数面积相对值读延迟相对值动态功耗相对值A211.121.001.08B411.001.061.00C421.080.951.03D810.941.150.96从表格可以看出面积和时序永远是矛盾的。如果系统频谱吃紧方案C很可能是更好的选择如果面积是第一位方案D可以做备选。我的建议是永远不要只用默认配置至少跑3组以上配置对比再把数据拿到项目评审会上讨论这样才能做理性决策。5. 常见问题与排查技巧实录5.1 生成的lib文件读不进STA工具这个问题出现频率相当高经常是综合和后端工具报“invalid timing library”或“cannot find cell”。最常见的原因有几个版本不匹配。Memory Compiler生成.lib时用的是当前工具库版本但后端STA工具版本较老读不了。解决办法是让工具重导出兼容版本。工艺库名称不一致。lib顶层的library_name必须和后续流程引用的名称匹配有的工程师喜欢手动改名结果改漏了工具就找不到。多电压域识别失败。如果SRAM工作电压和lib声明的nominal voltage不一致在multi-voltage flow里也会报错。排查时先用文本编辑器打开.lib确认头几行的library name和voltage再决定是重新生成还是修改环境。注意修改lib里的电压值不是好习惯最好还是用Compiler按正确条件重新生成。5.2 面积异常比预期大很多我之前遇到过生成一个4KB的memory面积却比预期大了将近40%。查到最后发现是配置时Byte Write功能被打开了每个字节都额外增加了一套写控制电路。对于256bit宽的数据总线Byte Write的overhead会非常可观。所以如果你的设计根本不需要对每个字节单独写使能比如FIFO、Line Buffer千万别多开这个功能。另外一个隐形的面积杀手是DFT或BIST逻辑。部分Memory Compiler允许插入内建自测逻辑但这会占据不少面积。除非芯片有很严格的测试要求否则量产前后端里不要每颗memory都开BIST只对关键存储器开。5.3 时序违例频发怎么定位是memory配置的问题后端布局布线后时序违例如果集中出现在memory周围的路径问题大概率出在memory的物理位置或配置上。常见的情况Memory端口分布不合理导致data bus绕线过长信号延迟剧增。地址建立时间要求太紧本身配置时选得过高速度目标编译器用激进电路换来速度但抗干扰能力差实际物理实现反而更容易违例。时钟偏斜SRAM的时钟输入端太多导致CTS插入延迟与memory内部时钟不匹配。我的排查习惯是先看违例路径是read还是write方向。read方向违例多和CLK-to-Q或数据输出路径相关可以考虑开registered outputwrite方向违例多和地址建立时间或数据输入setup相关需要检查CTS和memory的input delay约束。5.4 功耗超标sleep模式开了却不起作用这个案例我记得很清楚。某个低功耗项目里芯片待机功耗怎么也压不下去查了半天发现Memory Compiler配置时把Sleep引脚使能打开了但RTL里根本没有把sleep信号接上一直悬空floating。工具在默认情况下会把悬空引脚处理为无效状态memory始终处于正常工作状态漏电功耗自然下不来。所以配置了功耗模式引脚后一定要去核对生成的.v网表确认这些引脚在RTL仿真里是有实际驱动的。另外sleep/retention的切换时序也要做专门的UPFUnified Power Format约束否则PR工具根本不知道这些信号是电源管理信号不会做隔离和电平转换。5.5 版本混乱换工艺节点后直接套老配置在项目从28nm迁移到22nm甚至更先进节点时Memory Compiler的配置是不能直接平移的。不同工艺下最优的Column Mux、bank数量都不一样。因为先进工艺下晶体管的驱动能力更强但线电阻更大时序瓶颈会从晶体管本身转向互连线RC。这也解释了为什么很多公司换节点时会重新整理一套memory配置标准而不是沿用上一颗芯片的脚本。关键参数比如bitcell类型、外围电路结构每个工艺节点都不同贸然平移轻则面积大幅增加重则时序收敛不了。你可能还会遇到一些奇怪的现象比如同样配置下不同批次生成出来的memory的面积有微小差异。这通常是因为工具版本或PDK版本微调一般不影响使用但如果差异超过了5%要立刻排查是不是库里默认参数变了。6. 工具选型与团队协作建议6.1 主流Memory Compiler工具与选用场景业界主要用的Memory Compiler大部分来自IP厂商自己的流程比如基于Arm Artisan物理IP平台配合Synopsys、Cadence的后端流程。选型时主要看三点工艺覆盖是否支持当前项目的工艺节点和电压域比如是否支持近阈值电压。模型完整性是否能同时提供标准延迟格式.sdf、功耗模型、UPF视图缺任意一个后端流程都会有断点。集成效率是否能够稳定地在主流流程Innovus、ICC2中导入无需大量手工二次处理。有些公司还会用开源或自研的memory generator但成熟度通常不如商业方案。做产品的话我不建议在这上面节省因为一颗芯片流片成本极高memory一旦出问题代价巨大。6.2 团队协作时如何管理memory配置版本项目里动辄几十颗SRAM如果没有版本管理后期绝对是一场灾难。我的建议是在项目里建立一个memory配置总表包含每个实例名、功能、深度位宽、端口类型、Column Mux、bank数、功耗模式、生成工具版本、lib版本等。所有生成文件统一归档到服务器目录禁止个人电脑里散放。这样做的直接好处是后端在做ECOEngineering Change Order时可以快速定位到哪颗memory需要重生成。而且一旦时序或功耗出了问题可以回溯到具体配置不用全项目“翻土”。7. 最后的实战小技巧说两个我用了很久的小技巧希望对你有用。第一生成memory之后花五分钟人工看一遍生成的.v网表和lib。重点确认输入输出引脚有没有多余的比如你明明没开sleep结果lib里却出现了SL引脚这就代表配置出错。这类问题如果拖到后端流程后期才发现返工成本极高。即时检查五分钟能省下后面几天的功夫。第二凡是牵扯到memory功耗模式的信号一定让前端在RTL里用明确的名字命名比如lm_bank0_sleep_b并在UPF里把对应电源状态定义清楚。别嫌麻烦实际调试的时候你会感激当初定的这些命名规范。Memory Compiler参数配置这门手艺说难不难但真要深入下去涉及的知识面很宽工艺、电路原理、物理设计、时序、功耗、测试全都要懂一些。这篇实战分享算是我自己这几年项目经验的浓缩希望能帮你少走一些弯路。后续如果大家对具体某个环节感兴趣比如怎么用UPF配合memory做低功耗设计或者怎么评估DFT插入策略我可以在下一篇再展开聊。
返回列表