學習Murmann《Systematic Design of Analog CMOS Circuits》過程中,需要首先仿真得到關於Gmid參數的數據庫。該數據庫在Matlab環境下生成。
我的仿真環境為:CentOS7、Matlab2018a、CadenceIC617。
該數據庫是四維的數據庫,四個維度分別為\(V_{DS}\)、\(V_{SB}\)、\(V_{GS}\)、\(L\)。
包含的參數有:
類別 | 詳細內容 |
---|---|
電容信息C | CGG,CGS,CSG,CGD,CDG,CGB,CDD,CSS |
電流信息I | ID,IGD,IGS |
跨導信息GM | GM,GMB |
閾值電壓VT | VT |
噪聲信息S | STH,SFL |
利用書中提供的工具箱,利用該數據庫即可完成相應設計。
下載/安裝Matlab相應工具包
我將相應工具包上傳到了這里,請點擊下載。該工具箱包括《Systematic Design of Analog CMOS Circuits》書配套工具箱和Spectre數據讀取工具箱。
- 下載Matlab相應工具包;
- 將工具包載入Matlab工作目錄即可;
配置仿真.m腳本
仿真使用的腳本有兩個,一個用來配置仿真參數,名字為cortemsweep_config.m;另一個用來執行仿真,名字為cortemsweep_spectre_run.m。
腳本中有一些路徑需要修改成為自己電腦中的相應路徑。
需要修改的地方我會寫做“< XXX… > “,修改時請去掉左右尖括號< >。
例如:'< 修改為你模型所在的路徑,例如:/home/allmodel.scs >' 修改為‘/home/allmodel.scs’。
cortemsweep_config.m腳本整體如下:
% Harroy 2020.09.02
% 該.m文件用來配置數據庫仿真時的一些參數,注意輸入參數需要輸入相應工藝角和溫度(攝氏度)
function c = cortemsweep_config(corner, temp)
% 仿真模型路徑
c.modelfile = '< 修改為你模型所在的路徑,例如:/home/allmodel.scs >';
c.modelinfo = '< 此處填寫數據庫信息,方便查閱,不對數據庫數據產生影響,例如:180nm CMOS>';
c.corner = corner;
c.temp = temp;
% 模型名字,對應Spectre相應仿真中器件的模型名。
c.modeln = 'nch';
c.modelp = 'pch';
% 數據庫存儲名字和位置
c.savefilen = sprintf("< NMOS數據庫存儲名字和位置,例如:/home/180_nch_%d_%s >",c.temp, c.corner);
c.savefilep = sprintf("< PMOS數據庫存儲名字和位置,例如:/home/180_pch_%d_%s >",c.temp, c.corner);
% 該仿真是通過在matlab中調用spectre的方式實現的,下面是關於調用的命令,配合system函數使用。
c.simcmd = '< Spectre軟件所在路徑,若環境變量已配置好,直接輸入Spectre即可 > -64 < 本.m文件自動生成仿真網表文件的路徑,在本.m文件最后位置更改或查看 > +log < 填寫log文件存在位置,可以查看仿真中遇到的問題,例如:/home/techsweep.out >';
c.outfile = '< 仿真網表文件存放路徑,后面會讀取該文件,建議和數據庫放一起。例如:/home/techsweep.raw >';
c.sweep = 'sweepvds_sweepvgs-sweep';
c.sweep_noise = 'sweepvds_noise_sweepvgs_noise-sweep';
% 掃描仿真的信息,可以自行修改自己為所需數據
c.VGS_step = 100e-3;
c.VDS_step = 100e-3;
c.VSB_step = 0.1;
c.VGS_max = 1.8;
c.VDS_max = 1.8;
c.VSB_max = 1.0;
c.VGS = 0:c.VGS_step:c.VGS_max;
c.VDS = 0:c.VDS_step:c.VDS_max;
c.VSB = 0:c.VSB_step:c.VSB_max;
c.LENGTH = [(0.18:0.02:0.5) (0.6:0.1:2.0)];
c.WIDTH = 4;
c.NFING = 4;
% 變量排布,以便后面讀取數據,不熟悉請不要修改
c.outvars = {'ID','VT','IGD','IGS','GM','GMB','GDS','CGG','CGS','CSG','CGD','CDG','CGB','CDD','CSS'};
c.n{1}= {'mn:ids','A', [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ]};
c.n{2}= {'mn:vth','V', [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 ]};
c.n{3}= {'mn:igd','A', [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ]};
c.n{4}= {'mn:igs','A', [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 ]};
c.n{5}= {'mn:gm','S', [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 ]};
c.n{6}= {'mn:gmbs','S', [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 ]};
c.n{7}= {'mn:gds','S', [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 ]};
c.n{8}= {'mn:cgg','F', [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ]};
c.n{9}= {'mn:cgs','F', [0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 ]};
c.n{10}={'mn:cgd','F', [0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 ]};
c.n{11}={'mn:cgb','F', [0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 ]};
c.n{12}={'mn:cdd','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 ]};
c.n{13}={'mn:cdg','F', [0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 ]};
c.n{14}={'mn:css','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]};
c.n{15}={'mn:csg','F', [0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 ]};
c.n{16}={'mn:cjd','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 ]};
c.n{17}={'mn:cjs','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]};
%
% {'ID','VT','IGD','IGS','GM','GMB','GDS','CGG','CGS','CSG','CGD','CDG','CGB','CDD','CSS'};
c.p{1}= {'mp:ids','A', [-1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ]};
c.p{2}= {'mp:vth','V', [0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 ]};
c.p{3}= {'mp:igd','A', [0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 ]};
c.p{4}= {'mp:igs','A', [0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 ]};
c.p{5}= {'mp:gm','S', [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 ]};
c.p{6}= {'mp:gmbs','S', [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 ]};
c.p{7}= {'mp:gds','S', [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 ]};
c.p{8}= {'mp:cgg','F', [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ]};
c.p{9}= {'mp:cgs','F', [0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 ]};
c.p{10}={'mp:cgd','F', [0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 ]};
c.p{11}={'mp:cgb','F', [0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 ]};
c.p{12}={'mp:cdd','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 ]};
c.p{13}={'mp:cdg','F', [0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 ]};
c.p{14}={'mp:css','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]};
c.p{15}={'mp:csg','F', [0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 ]};
c.p{16}={'mp:cjd','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 ]};
c.p{17}={'mp:cjs','F', [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ]};
%
c.outvars_noise = {'STH','SFL'};
c.n_noise{1}= {'mn:id', ''};
c.n_noise{2}= {'mn:fn', ''};
%
c.p_noise{1}= {'mp:id', ''};
c.p_noise{2}= {'mp:fn', ''};
% 自動生成Spectre仿真網表,不熟悉請不要修改,注意其中有個路徑需要修改
netlist = sprintf([...
'//techsweep.scs \n'...
'include "%s" section=%s\n'...
'include "< 仿真執行時的掃描網表位置,注意和另一腳本對應路徑應該相同,例如:/home/techsweep_params.scs >\n'...
'save mn \n'...
'save mp \n'...
'parameters gs=0 ds=0 \n'...
'vnoi (vx 0) vsource dc=0 \n'...
'vdsn (vdn vx) vsource dc=ds \n'...
'vgsn (vgn 0) vsource dc=gs \n'...
'vbsn (vbn 0) vsource dc=-sb \n'...
'vdsp (vdp vx) vsource dc=-ds \n'...
'vgsp (vgp 0) vsource dc=-gs \n'...
'vbsp (vbp 0) vsource dc=sb \n'...
'\n'...
'//NOTE: YOUR MODELS SHOULD BE SET UP SUCH THAT THE STRESS PARAMS (SA, SB, etc.) ARE AUTOMATICALLY COMPUTED\n'...
'mn (vdn vgn 0 vbn) %s l=length*1e-6 w=%de-6 nf=%d \n'...
'mp (vdp vgp 0 vbp) %s l=length*1e-6 w=%de-6 nf=%d \n'...
'\n'...
'simOptions options gmin=1e-13 reltol=1e-4 vabstol=1e-6 iabstol=1e-10 temp=%d tnom=27 rawfmt=psfbin rawfile="%s" \n'...
'sweepvds sweep param=ds start=0 stop=%d step=%d { \n'...
' sweepvgs dc param=gs start=0 stop=%d step=%d \n'...
'}\n'...
'sweepvds_noise sweep param=ds start=0 stop=%d step=%d { \n'...
' sweepvgs_noise noise freq=1 oprobe=vnoi param=gs start=0 stop=%d step=%d \n'...
'}\n'...
], c.modelfile, c.corner, ...
c.modeln, c.WIDTH, c.NFING, ...
c.modelp, c.WIDTH, c.NFING, ...
c.temp, c.outfile,...
c.VDS_max, c.VDS_step, ...
c.VGS_max, c.VGS_step, ...
c.VDS_max, c.VDS_step, ...
c.VGS_max, c.VGS_step);
% 將網表寫入文件保存
fid = fopen('<仿真網表文件存放路徑,例如:/home/techsweep.scs' >, 'w');
fprintf(fid, netlist);
fclose(fid);
return
仿真執行腳本cortemsweep_spectre_run.m中也有一個路徑需要修改:
% Harroy @ 2020.09.02
clearvars;
close all;
% corner表示當前仿真工藝角,temp表示攝氏溫度,自行修改
corner = 'tt';
temp = 27;
% 載入配置腳本
c = cortemsweep_config(corner, temp);
% 載入掃描信息,無需修改
nch.INFO = c.modelinfo;
nch.CORNER = c.corner;
nch.TEMP = c.temp;
nch.NFING = c.NFING;
nch.L = c.LENGTH';
nch.W = c.WIDTH;
nch.VGS = c.VGS';
nch.VDS = c.VDS';
nch.VSB = c.VSB';
%
pch.INFO = c.modelinfo;
pch.CORNER = c.corner;
pch.TEMP = c.temp;
pch.NFING = c.NFING;
pch.L = c.LENGTH';
pch.W = c.WIDTH;
pch.VGS = c.VGS';
pch.VDS = c.VDS';
pch.VSB = c.VSB';
% 開始仿真
for i = 1:length(c.LENGTH)
str=sprintf('L = %2.3f', c.LENGTH(i));
disp(str);
tic
for j = 1:length(c.VSB)
% 寫入掃描參數
fid=fopen('< 仿真執行時的掃描網表位置,注意和另一腳本對應路徑應該相同,例如:/home/techsweep_params.scs >', 'w');
fprintf(fid,'parameters length = %d\n', c.LENGTH(i));
fprintf(fid,'parameters sb = %d\n', c.VSB(j));
fclose(fid);
pause(5)
% 調用Spectre
[status,result] = system(c.simcmd);
if(status)
disp('Simulation did not run properly. Check techsweep.out.')
return;
end
% 初始化數據庫
for m = 1:length(c.outvars)
nch.(c.outvars{m})(i,:,:,j) = zeros(length(c.VGS), length(c.VDS));
pch.(c.outvars{m})(i,:,:,j) = zeros(length(c.VGS), length(c.VDS));
end
% 讀取並存儲常規數據
for k = 1:length(c.n)
params_n = c.n{k};
struct_n = cds_srr(c.outfile, c.sweep, params_n{1});
values_n = struct_n.(params_n{2});
params_p = c.p{k};
struct_p = cds_srr(c.outfile, c.sweep, params_p{1});
values_p = struct_p.(params_p{2});
for m = 1:length(c.outvars)
nch.(c.outvars{m})(i,:,:,j) = squeeze(nch.(c.outvars{m})(i,:,:,j)) + values_n*params_n{3}(m);
pch.(c.outvars{m})(i,:,:,j) = squeeze(pch.(c.outvars{m})(i,:,:,j)) + values_p*params_p{3}(m);
end
end
% 讀取並存儲噪聲數據
for k = 1:length(c.n_noise)
params_n = c.n_noise{k};
% note: using cds_innersrr, since cds_srr is buggy for noise
struct_n = cds_innersrr(c.outfile, c.sweep_noise, params_n{1},0);
field_names = fieldnames(struct_n);
values_n = struct_n.(field_names{4});
params_p = c.p_noise{k};
% note: using cds_innersrr, since cds_srr is buggy for noise
struct_p = cds_innersrr(c.outfile, c.sweep_noise, params_p{1},0);
field_names = fieldnames(struct_p);
values_p = struct_p.(field_names{4});
nch.(c.outvars_noise{k})(i,:,:,j) = squeeze(values_n);
pch.(c.outvars_noise{k})(i,:,:,j) = squeeze(values_p);
end
end
toc
end
save(c.savefilen, 'nch');
save(c.savefilep, 'pch');
腳本修改完成后,即可執行cortemsweep_spectre_run.m腳本開始仿真。
仿真可能遇到的問題
Matlab輸出
“Simulation did not run properly. Check techsweep.out.“
查看Spectre生成的Log文件發現如下提示
“lmStatus: ERROR (LMC-01902): License call failed. The license server search path is defined as
. Can't find license file.“
- 此處提示沒有正確載入Spectre的Licenses,一般是由於沒有正確載入環境變量導致,從桌面快捷方式打開的Matlab仿真時會出現這種位問題。建議在終端Terminal中輸入matlab執行仿真。
運行時提示缺少“libsrr.so“
-
由於我的Cadence軟件是直接拷貝過來的,而不是正常的安裝,因此會導致關於Cadence 的動態連接庫無法找到。此時需要將Cadence/Spectre中的動態鏈接庫放入自己系統的環境中。
# 1. 首先找到libsrr.so所在的位置 locate libsrr.so # 2. 在結果中復制該文件所在文件夾的位置,例如復制/opt/cadence/installs/SPECTRE181/tools.lnx86/lib # 3. 進入系統動態連接庫所在位置 cd /etc/ld.so.conf.d/ # 4. 新建配置文件或復制配置文件 sudo cp libiscsi-x86_64.conf spectre.conf # 5. 將之前復制的位置/opt/cadence/installs/SPECTRE181/tools.lnx86/lib替換進去 # 6. 重新配置動態連接庫 sudo ldconfig
此時動態連接庫配置完成,重啟Matlab仿真即可。