|

楼主 |
发表于 2020-4-13 09:15:48
|
显示全部楼层
在之前一篇文章中已经为大家介绍了使用ocean脚本实现corner仿真的方法,并且在文章末尾附上了完整、实用的ocean脚本,不过对于ocean脚本的稍高级用法以及语法内容并没有做详细的介绍,在这里特别做一些补充,帮助同学们完成一些符合自己实际情况的ocean脚本。
用好软件工具
刚开始接触ocean语言的同学可能会感觉到毫无方向,只是别人脚本里写了什么,自己也在脚本里写进去,偶尔遇到需要实现的一些功能又不知从何写起,只能在各大论坛、技术交流群里大海捞针,试图发现一丝对自己有用的内容。
筛选信息的方法虽然有用但是效率太低,而且不能保证每次都能找出有用信息,对于这一点小目同学深有感触,因为这是很多初学者都会走的路,不过今天小目同学想分享一些经验,希望有心学习IC设计的初学者可以少走一些弯路,早日圆了“芯片梦”。
Cadence SKILL API Finder: 这个是Cadence提供的工具,可以用来查找skill语言和ocean语言相关的函数功能以及用法,对于不熟悉的函数,用这个工具可以快速找到解决方法。
启动方法是:在Virtuoso软件CIW界面:Tools->SKILL API Finder, 启动之后可以在搜索框输入需要查找的函数名,如果正确就会看到函数的使用方法和函数功能简介。
Cadence Help: 小目同学个人认为这个是在使用Cadence系列软件的时候最有利的帮手,如果使用得当基本可以解决平时使用中遇到的所有问题,而且使用起来也很方便。
在Virtuoso软件界面:Help->Virtuoso Documentation Library, 之后按下快捷键:F2, 可以看到如图所示的搜索框,像所有的搜索工具一样,只需要输入自己想要查找的内容就可以看到相关的信息以及对应的文档。
正确使用Cadence Help功能可以为我们解决很多工具上的使用问题,再也不必为简单的软件问题头疼,当然ocean语言的学习也离不开Cadence Help的帮助。
SKILL IDE: 目前市面上有很多针对其他语言比如:python, C等开发的各种各样的IDE, 不仅界面友好,而且辅助功能应有尽有。然而,由于ocean或者skill语言的应用相对较少,小目同学暂时没有发现可以独立使用的skill语言IDE, 但是Cadence 公司在工具里集成了一个类似的工具,帮助用户调试脚本。
打开方式是:在Virtuoso软件CIW界面:Tools->SKILL IDE, 对于复杂的程序在这里调试会事半功倍,不过如果程序相对简单,可以直接在CIW界面进行调试,倒是没有使用IDE的必要。
除了Cadence软件自带的SKILL IDE外,小目同学要给大家推荐一下VS Code, 因为这里有各位大神贡献的插件,其中就有一个针对skill语法的高亮插件,可以让脚本看起来更加清晰,不妨一试,两个工具的显示效果如下面图片所示。
VS Code插件显示ocean语言
Cadence Online Support: 网址:https://support.cadence.com, 这相当于一个封闭的Cadence社区,里面包含各种各样的知识库、课程以及专业的技术支持,解决各种各样的疑难杂症。不过由于限制,只有那些大的公司工作人员才有可能获得权限,小目同学也无法看到里面的精彩内容,希望有账号的同学跟我们分享一些“内部消息”,在此谢过!
以上的“利器”是在学习Cadence软件平台使用方法的时候不可或缺的资源,好好利用必然可以节省很多时间,大大获益。
ocean语言的内容补充
以前面文章中给的ocean脚本作为示例,更详细地介绍ocean初学者可能不理解的地方,同时也巩固一些基础内容,希望各位同学能够熟练掌握、达到举一反三的学习目标,能在工作中灵活使用ocean语言。
- filename = "ICSkillSharing.ocn" ;file name
- design_dir = "/home/IC/Documents/analog_ic/simulation/inv/spectre/schematic/netlist/netlist" ;dir of netlist file
- modelfile_dir = "/home/IC/Documents/pdks/smic18mmrf/models/spectre/ms018_v1p9_spe.lib" ;dir of process models
- for(corner_sim 1 3 ;;loop for corner, corner_mos、corner_bjt、corner_res、corner_cap are different corners
- if(corner_sim == 1 then corner_dir = "tt" corner_mos = list(modelfile_dir "tt") corner_res = list(modelfile_dir "res_tt") corner_cap = list(modelfile_dir "mim_tt") corner_bjt = list(modelfile_dir "bjt_tt"))
- if(corner_sim == 2 then corner_dir = "ss" corner_mos = list(modelfile_dir "ss") corner_res = list(modelfile_dir "res_tt") corner_cap = list(modelfile_dir "mim_tt") corner_bjt = list(modelfile_dir "bjt_tt"))
- if(corner_sim == 3 then corner_dir = "ff" corner_mos = list(modelfile_dir "ff") corner_res = list(modelfile_dir "res_tt") corner_cap = list(modelfile_dir "mim_tt") corner_bjt = list(modelfile_dir "bjt_tt"))
- ;if(corner_sim == 4 then corner_dir = "sf" corner_mos = list(modelfile_dir "sf") corner_res = list(modelfile_dir "res_tt") corner_cap = list(modelfile_dir "mim_tt") corner_bjt = list(modelfile_dir "bjt_tt"))
- ;if(corner_sim == 5 then corner_dir = "fs" corner_mos = list(modelfile_dir "fs") corner_res = list(modelfile_dir "res_tt") corner_cap = list(modelfile_dir "mim_tt") corner_bjt = list(modelfile_dir "bjt_tt"))
- for(vdd_sim 1 3 ;;loop for power supply
- if(vdd_sim == 1 then vdd = 3.0 vdd_dir = "3p0")
- if(vdd_sim == 2 then vdd = 3.3 vdd_dir = "3p3")
- if(vdd_sim == 3 then vdd = 2.7 vdd_dir = "2p7")
- for(temp_sim 1 3 ;;loop for temp
- if(temp_sim == 1 then temp = 27 temp_dir = "27")
- if(temp_sim == 2 then temp = -40 temp_dir = "m40")
- if(temp_sim == 3 then temp = 125 temp_dir = "125")
- results_dir = strcat(substring(design_dir 1 62) substring(filename 1 14) "/" corner_dir "_v" vdd_dir "_t" temp_dir) ;save results dir
- simulator( 'spectre ) ;setup siulator
- design( design_dir ) ;netlist file
- resultsDir( results_dir ) ;save results dir
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;; add simulation script blow ;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- modelFile( corner_mos corner_bjt corner_res corner_cap ) ;setup process models
- analysis('dc ?saveOppoint t ?param "va" ?start "0"
- ?stop "3" ) ;add dc simulation
- ;analysis('ac ?start "1" ?stop "1G" ) ;add ac simulation
- ;analysis('stb ?start "1" ?stop "10G" ?probe "/IPRB0" ) ;add stb simulation
- analysis('tran ?stop "10u" ?errpreset "conservative" ) ;add tran simulation
- desVar( "avdd" vdd ) ;setup avdd
- desVar( "va" 1.5 ) ;setup va
- envOption(
- 'analysisOrder list("dc" "tran")
- ) ;setup simulation order
- option( ?categ 'turboOpts
- 'apsplus t
- 'errorLevel "Moderate"
- 'uniMode "APS"
- ) ;use aps
- saveOption( 'subcktprobelvl "5" ) ;save results option, for 5th subckt blow
- saveOption( 'currents "all" ) ;save all current
- temp( temp ) ;setup temp
- run() ;start the simulation
- selectResult( 'tran ) ;select result for tran simulation
- VTEST = average(VT("/Y"))
- plot(getData("/A") getData("/Y") ?expr list(strcat("A_" corner_dir "_v" vdd_dir "_t" temp_dir) strcat("Y_" corner_dir "_v" vdd_dir "_t" temp_dir)) ) ;plot A & Y
- selectResult( 'dc ) ;select result for dc simulation
- plot(getData("/A") getData("/Y") ?expr list(strcat("A:" corner_dir "_v" vdd_dir "_t" temp_dir) strcat("Y:" corner_dir "_v" vdd_dir "_t" temp_dir)) ) ;plot A & Y
- ;selectResult( 'ac ) ;select result for ac simulation
- ;plot(getData("/A") getData("/Y") ?expr list(strcat("A:" corner_dir "_v" vdd_dir "_t" temp_dir) strcat("Y:" corner_dir "_v" vdd_dir "_t" temp_dir)) ) ;plot A & Y
- ;YN = clip((- VT("/Y")) 1e-06 9e-06) ;use calculator
- ;plot( YN ?expr list( strcat("YN:" corner_dir "_v" vdd_dir "_t" temp_dir) ) ) ;plot result
- ;results_outfile = outfile(strcat(substring(design_dir 1 62) substring(filename 1 14) ".txt") "a") ;save VTEST to a file
- ;fprintf(results_outfile "The PVT are:\t\t %s_v%s_t%s\n" corner_dir vdd_dir temp_dir) ;save PVT info
- ;fprintf(results_outfile "The results are:\t VTEST = %f\n" VTEST) ;save result to file
- ;close(results_outfile) ;close file opened before
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;; add simulation script above ;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ) ;;end loop for temp
- ) ;;end loop for power supply
- ) ;;end loop for corner
复制代码
以上脚本的功能大家都已经熟悉,但是可能对更细节的语法内容有所疑惑,这里就挑一些会令初学者犯难的地方加以说明。
列表结构:首先解释一下ocean语言中频繁出现的半个单引号:「'」, 比如:以上脚本中第22行:simulator( 'spectre ), 第51行:selectResult( 'tran )等,其中的单引号作用是:单引号后面的内容数据类型为列表,也可以用函数:list()来实现,可以看到脚本中也有很多用list()实现的列表。
ocean语言和skill语言中有很多以列表传递参数的形式,因为skill语言是从Lisp(List Processing)语言发展而来的,顾名思义这是一种对list结构操作的语言,所以skill语言中有很多对list处理的语句。
选择设计:脚本中第23行:design( design_dir ), 作用是设置仿真电路的网表文件,这个文件是在图形化界面生成的,初学者不太注意的话很容易产生疑惑。
有时候用户希望和图形化界面操作一样,选择具体的设计文件,对于这种情况,design()函数也可以像后面这样传递参数:design( "libName" "cellName" "viewName" "mode"), 各个参数分别代表:设计所在的库名称、设计的名称、打开的视图和打开方式,对于小目同学的演示设计,第23行可以这样写:
design( "ICSkillSharing" "inv" "shematic" "r")
波形打印:之前的脚本打印波形用plot()函数,传递需要打印的波形信息即可。认真实验的同学可能发现,直接由ADE L保存的ocean脚本运行之后打印的波形名称和直接在ADE L仿真界面打印的波形名称不一致,至于原因小目同学也搞不清楚,只能采用其它方法实现波形名称修改。
在使用ocean脚本时打印波形可以使用这样的方法:plot(waveform ?expr 'waveName), 指定波形名称,不至于在同时打印多个波形时混淆。
坐标轴变换:plot()函数只能实现波形打印,坐标轴变换也是一个常用功能,比如在gm/Id设计方法中需要画出gm/Id与gm*ro的关系曲线,但是gm/Id本身就是一个因变量,所以需要先画出gm/Id和gm*ro与vgs的关系曲线,然后通过坐标变换输出gm/Id与gm*ro的关系曲线。
函数ocnYvsYplot(?wavex wavex ?wavey wavey ?exprx exprx ?expry expry)实现坐标变换,参数的传递与plot()函数很一致,可以类比设置。
保存文件:ocean脚本不仅可以实现仿真功能,还可以根据需要将结果保存至文件以供后续处理。
实现4bit选择开关的遍历仿真
ocean脚本很适合做一些重复性的仿真操作,实现corner仿真只是这类仿真中的一种,还有很多其它类似仿真比如:trimming电路的仿真,虽然很多时候trimming电路只需要通过手算就可以确定结果,但是有时候也可能需要遍历所有可能,这时候使用ocean脚本的优势就会体现出来。
- avdd = 3 ;logic 1
- for(bit3_sim 0 1 ;loop for bit 3
- for(bit2_sim 0 1 ;loop for bit 2
- for(bit1_sim 0 1 ;loop for bit 1
- for(bit0_sim 0 1 ;loop for bit 0
-
- bit3 = avdd*bit3_sim ;value for control vsource
- bit2 = avdd*bit2_sim ;value for control vsource
- bit1 = avdd*bit1_sim ;value for control vsource
- bit0 = avdd*bit0_sim ;value for control vsource
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;; add simulation script blow ;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;desVar( "bit3" bit3 ) ;assign value
- ;desVar( "bit2" bit2 ) ;assign value
- ;desVar( "bit1" bit1 ) ;assign value
- ;desVar( "bit0" bit0 ) ;assign value
- ;add self ocean here
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;; add simulation script abovew ;;;;;;;;;;;;;;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- printf("The trimming code is:%d %d %d %d. \n" bit3 bit2 bit1 bit0);display results
- ) ;end loop for bit 0
- ) ;end loop for bit 1
- ) ;end loop for bit 2
- ) ;end loop for bit 3
复制代码
以上的例子希望能起到抛砖引玉的作用,脚本学习重在实践,在工作和学习中活学活用才能体现脚本的魅力,希望使用脚本能给各位同学带来一定的便利。 |
|