* You can save a .grf file in Viva, and then load it with : awvLoadWindow(awvCreatePlotWindow() "junk1.grf") * .cdsenv ui enableMenuShortcuts boolean nil ui showOptionForms boolean nil layout modalCommands boolean nil schematic modalCommands boolean nil viva.application vivaWindowMode string "window" schematic schDynamicHilightOn boolean t schematic schGridSpacing float 1.0 schematic schDynamicNetHilightOn boolean nil schematic statusBanner boolean t schematic statusBannerXY boolean t schematic comanageConstraintView boolean nil * verilogA nice reference at : https://help.simetrix.co.uk/8.0/simetrix/mergedProjects/verilog_a_reference/topics/veriloga_writingverilog_acode_asimpledevicemodel.htm https://designers-guide.org/verilog-ams/index.html * Create a symbol in cadence * Add labels (@instanceName, @cellName, @libName) * Very Important - Add all the pins you ever plan to add now. Do not change the pins later. If you need to change the pins then create a new cell from scratch and start over. * Very Important - Save the cell when the editor pops up. Do not add any code at this state. The special "save" button will try and update the CDF, and this will cause a bunch of problems if you have any code in it. Just save it blank, and then add code later with vim. You will will see the file path in the CIW when you close the cell. * Using vim in linux, insert your code in the skeleton provided. Once you've done this, you can edit the code directly in Linux Example Code : * **************************************************************************************** // VerilogA for junkLib, gblock, veriloga `include "constants.vams" `include "disciplines.vams" module gblock(Y, A, B, PCC, PSS); output Y; electrical Y; input A; electrical A; input B; electrical B; input PCC; electrical PCC; input PSS; electrical PSS; parameter real gain_val = 0.5; analog begin @(initial_step) begin $strobe(""); $strobe("*********************************"); $strobe("Hello World!"); $strobe("*********************************"); $strobe(""); end V(Y) <+ V(A) + V(B); end endmodule * **************************************************************************************** * ~/.cdsplotinit # Adobe PostScript Level 2 Plotter # AAAGregC|Generic 300 dpi Adobe PostScript Level 2 Plotter: \ :manufacturer=Adobe: \ :type=postscript2: \ :spool=lpr: \ :queue=lpq: \ :maximumPages#30: \ :resolution#300: \ :paperSize="A" 2400 3150 75 75: # # Adobe PostScript Level 1 Plotters # AAAGregE|Epsi Plotter: \ :manufacturer=Adobe: \ :type=epsf: \ :maximumPages#1: \ :resolution#300: \ :residentFonts: \ :paperSize="5x5 inches" 1500 1500: \ :paperSize="8x8 inches" 2400 2400: \ :paperSize="PPL" 300000 300000: \ :paperSize="Unlimited" 72000 72000: * **************************************************************************************** ; * ************************************************************************************************* procedure( ppe( @optional ( lwid 4 ) ( bname "junk" ) (idx nil) ) prog( (cv bBox jstr lname cname vname fnameo_pdf fnameo_ps idx_str) if( idx then idx_str = sprintf(nil "_%02d" idx) else idx_str = "" ) fnameo_pdf = sprintf(nil "%s%s.pdf" bname idx_str) fnameo_ps = sprintf(nil "%s%s.ps" bname idx_str) cv = getCurrentWindow() bBox = hiGetViewBBox(cv) xsize = 1.0 * (nth(0 nth(1 bBox)) - nth(0 nth(0 bBox))) ysize = 1.0 * (nth(1 nth(1 bBox)) - nth(1 nth(0 bBox))) lname = cv~>cellView~>libName cname = cv~>cellView~>cellName vname = cv~>cellView~>cellViewType gregOpen("gregPlot.plt") fprintf(gregOPort "schPlotOptions = '( nil\n") fprintf(gregOPort " hierarchy nil\n") fprintf(gregOPort " hierleveldown 0\n") fprintf(gregOPort " multisheet nil\n") fprintf(gregOPort " view \"%s\"\n" vname) fprintf(gregOPort " cell \"%s\"\n" cname) fprintf(gregOPort " library \"%s\"\n" lname) fprintf(gregOPort " plot \"cellview\"\n") fprintf(gregOPort " bBox %L\n" bBox) fprintf(gregOPort " fullarea nil\n") fprintf(gregOPort " noteText \"\"\n") fprintf(gregOPort " grid nil\n") fprintf(gregOPort " indexsheet t\n") fprintf(gregOPort " notes nil\n") fprintf(gregOPort " header nil\n") fprintf(gregOPort " plotToFile t\n") fprintf(gregOPort " vsheets 1\n") fprintf(gregOPort " hsheets 1\n") fprintf(gregOPort " pagecount 1\n") fprintf(gregOPort " nullpage nil\n") fprintf(gregOPort " paperdim (1.0 1.0)\n") fprintf(gregOPort " papersize \"PPL\"\n") fprintf(gregOPort " resolution 300\n") fprintf(gregOPort " plottertype \"epsf\"\n") fprintf(gregOPort " plotter \"AAAGregE\"\n") fprintf(gregOPort " fit nil\n") fprintf(gregOPort " outputfile \"junktmp.ps\"\n") fprintf(gregOPort " time \"now\"\n") fprintf(gregOPort " tmpdir \"/tmp\"\n") fprintf(gregOPort " copy 1\n") fprintf(gregOPort " unit \"inches\"\n") fprintf(gregOPort " scale 1.0\n") fprintf(gregOPort " center nil\n") fprintf(gregOPort " mail nil\n") fprintf(gregOPort " orientation \"portrait\"\n") fprintf(gregOPort " offset (0.0 0.0)\n") fprintf(gregOPort " plotsize (%0.5f %0.5f)\n" xsize ysize) fprintf(gregOPort ")\n") fprintf(gregOPort "\n") gregClose() schPlot("gregPlot.plt" cv) sprintf(jstr "cat junktmp.ps | sed -e 's/1 setlinewidth/%d setlinewidth/' > junktmp1.ps" lwid) system(jstr) sprintf(jstr "ps2pdf -dEPSCrop -dAutoRotatePages=/None junktmp1.ps") system(jstr) sprintf(jstr "mv junktmp1.ps %s" fnameo_ps) system(jstr) sprintf(jstr "mv junktmp1.pdf %s" fnameo_pdf) system(jstr) sprintf(jstr "cp %s ~/junk_last.pdf" fnameo_pdf) system(jstr) system("rm junktmp.ps") printf("\n") printf("cat f1.ps f2.ps f3.ps f4.ps > junk.ps; ps2pdf -dEPSCrop -dAutoRotatePages=/None junk.ps\n") printf("\n") printf("Created %s (%d)\n" fnameo_pdf lwid) printf("scp $SS:junk_last.pdf .\n") ) ) procedure( ggplot_xval(xmin xmax n) prog( ( ggwin ggdel ) ggwin = awvGetCurrentWindow() awvSetXLimit(ggwin list(xmin xmax)) ggdel = ( xmax - xmin ) / ( 1.0 * n ) awvSetXAxisStepValue(ggwin ggdel) ) ) procedure( ggplot_yval(ymin ymax n) prog( ( ggwin ggdel ) ggwin = awvGetCurrentWindow() awvSetYLimit(ggwin 1 list(ymin ymax)) ggdel = ( ymax - ymin ) / ( 1.0 * n ) awvSetYAxisStepValue(ggwin 1 ggdel) ) ) procedure( ggplot_savewin() prog( () gregPlotWindow = getCurrentWindow() gregBBox = hiGetAbsWindowScreenBBox(getCurrentWindow() t) printf("\n") printf("gregBBox = list( list( %d %d ) list( %d %d ) )\n" nth(0 nth(0 gregBBox)) nth(1 nth(0 gregBBox)) nth(0 nth(1 gregBBox)) nth(1 nth(1 gregBBox))) printf("\n") ) ) procedure( ggplot_loadwin( @optional ( bbox nil ) "l") prog( () if( bbox then gregBBox = bbox ) hiResizeWindow(gregPlotWindow gregBBox) ) ) procedure( ggplot( @optional ( fname "~/junk.png" ) "t" ) prog( () saveGraphImage( ?window currentWindow() ?fileName fname ?exactCopy t ) printf("\n") printf("scp $SS:junk.png .\n") printf("\n") ) ) procedure( gterm() prog( (cv pv) dir = "../.." system(strcat("cd " dir "; gnome-terminal &")) ) ) ; * ************************************************************************************************* *************************************************** ; Set up standard skill functions ; *************************************************** GREGPI = 3.14159265358979323846 procedure( safelog(vv) prog( ( vv_mag vv_log10 ) vv_mag = mag(vv) if( (vv_mag < 1.0e-15) then vv_mag = 1.0e-15 ) vv_log10 = log10(vv_mag) return(vv_log10) ) ) ; This procedure returns (DC, AMP, DLY, SNR2, SNR3, SNR) ; It assumes exactly one period of pure sinewave with an odd number of points procedure( gregfft(pnts, fx) prog( (num coeff xx yy sum DC AMP DLY SNR2 SNR3 SNR) num = length(pnts) coeff = adtFFT(pnts) DC = mag(nth(0, coeff))/num AMP = mag(nth(1, coeff)/num)*2.0 yy = imag(nth(1, coeff)) xx = real(nth(1, coeff)) DLY = -(1/fx) * (atan2(yy xx) + GREGPI/2)/(2*GREGPI) SNR2 = 20 * safelog( mag(nth(1, coeff)) / mag(nth(2, coeff)) ) SNR3 = 20 * safelog( mag(nth(1, coeff)) / mag(nth(3, coeff)) ) sum = 0.0 for( k 2 int(num/2) sum = sum + mag(nth(k, coeff))**2 ) SNR = 10 * safelog( mag(nth(1, coeff))**2 / sum ) return( list(DC, AMP, DLY, SNR2, SNR3, SNR) ) ) ) procedure( gtest( ccnd ) prog( (odx) if( ccnd then odx = 1 else odx = 0 ) return(odx) ) ) procedure( gregOpen( fname @optional ( fmode "w" ) "tt" ) prog( ( fnameFull ) sprintf(fnameFull "%s/%s" getShellEnvVar("PWD") fname ) gregOPort = outfile( fnameFull fmode ) ) ) procedure( gregOpenAbs( fname @optional ( fmode "w" ) "tt" ) prog( ( fnameFull ) fnameFull = fname gregOPort = outfile( fnameFull fmode ) ) ) procedure( gregClose( ) prog( ( ) close(gregOPort) ) ) procedure( makeSignal( xlist ylist ) prog( ( ggn sig ) gregOpen("./junk_temp.txt" "w") ggn = length(xlist)-1 for(icnt 0 ggn fprintf(gregOPort "%0.15e %0.10e\n" nth(icnt, xlist) nth(icnt, ylist)) ) gregClose() sig = getAsciiWave( "./junk_temp.txt" 1 2 ?xUnits "Secs" ?yUnits "V" ) return(sig) ) ) ; *************************************************** * **************************************************************************************** * Here is a simple script llCornerList = list( "C0" "C1" "C2" "C3" "C4" "C5" "C6" "C7" "C8" "C9" "C10" ) runCornerList = list( "C3" "C4" "C5" ) procedure( shanBack( ) prog(( f ggOutsList ) printf("\n") printf("Hello World\n") maeOpenResults( ?history gghist ) fp = outfile( "~/junk.jnk" "a" ) foreach( tname ggtestList ggOutsList = maeGetResultOutputs() foreach( outv ggOutsList foreach( corn runCornerList AVAL = maeGetOutputValue( outv tname ?cornerName corn ?evalType 'point ) printf("%s %s %s %A\n" tname outv corn AVAL) ) ) ) printf("Thank you\n") close( fp ) maeCloseResults() ) ) ggsess = maeOpenSetup( "matrix_warwar" "gdfamp" "maestro" ) ggtestList = maeGetSetup( ?session ggsess ) maeSetVar( "GVMID" 0.55 ) ; ********************************************************************** ; Set Corners ; ********************************************************************** maeSetSetup( ?corners list( "Nominal" ) ?enabled t) maeSetSetup( ?corners allCornerList ?enabled nil) maeSetSetup( ?corners runCornerList ?enabled t) maeSetSetup( ?corners list( "Nominal" ) ?enabled nil) ; ********************************************************************** ; ********************************************************************** ; Run Simulation ; ********************************************************************** maeRunSimulation(?session ggsess ?callback "shanBack()" ) * If you create an maestro view. You can probably run it with a script using a combination of mae... and axl... skill functions. I highly recommend not becoming too deep in this method however. You will waste a lot of time hitting brick walls, and hidden undocumented features. For example, I spent two days trying to read the skill documentation on how to do parametric sweeps. You can set these up fairly easily with variables in Explorer, but these variables do not even seem to be the same variables you can access with the maeGetVar() and maeSetVar() skill functions. The variables you set in the explorer GUI seem to be an undocumented kind of variable, and the parametric sweeps become a set of "SweepPoints" and "DataPoints" and you can find out how many of these there are with Skill for example with : maeGetSessions() ("fnxSession0") axlGetSetupInfo("fnxSession0") (nil Corners 1 SweepPoints 3 DataPoints 3) pinfo = axlGetSetupInfo("fnxSession0") pinfo->SweepPoints 3 pinfo->DataPoints 3 Here are some more potentially useful skill functions maeGetSetup(?typeName "variables") ("KRP") [[[ please note this variable was created with maeSetVar(). The variables created with the GUI do not show up here :( ]]] maeGetSetup(?typeName "tests") ("matrix_warwar_hdfamp_1") maeGetSetup(?typeName "corners") ("Nominal") maeGetTestOutputs("matrix_warwar_hdfamp_1")~>?? ((inValidObject nil uniqueName "JACKG" waveSpec nil yaxisUnit nil label nil yaxisLabel nil graphType nil timeStamp nil index 1 implicit nil march nil save nil plot t value nil selectionDetail nil areaTable nil type nil depList nil sweepSet nil origin nil lastEvalTime nil isReferenced nil saveMasterScriptFile nil updatedScriptFile nil saveScriptFile nil masterScriptFile nil masterName nil internalName nil displayIt nil evalType nil type2 nil scriptFile nil signal nil expression value(deriv(VS("/yout")) 0) name "JACKG" ) ) maeGetTestOutputs("matrix_warwar_hdfamp_1")~>uniqueName ("JACKG") maeGetTestOutputs("matrix_warwar_hdfamp_1")~>expression (value(deriv(VS("/yout")) 0)) maeGetOutputValue("JACKG" "matrix_warwar_hdfamp_1") 2.480702 maeGetOutputValue("JACKG" "matrix_warwar_hdfamp_1" ?pointId 1) 2.480702 maeGetOutputValue("JACKG" "matrix_warwar_hdfamp_1" ?pointId 2) 2.479009 maeGetOutputValue("JACKG" "matrix_warwar_hdfamp_1" ?pointId 3) 2.475444 * The calculator function thd() gives the percent distortion. For example, a signal like y = sin(x) + 0.1*sin(2x) with have thd = 10.0 In dB we would have 10*log(0.1^2 / 1.0^2) = -20dB Thus THD_db = 20.0*log(thd/100) ; * ************************************************************************************************* ; * maestro run stuff ; * ************************************************************************************************* ggsession = "NULL" alias( ggcalc sevOpenCalculator ) alias( ggbrowse sevOpenDRLBrowser ) procedure( ggdata() prog( () return( strcat( asiGetCalcResultsDir() "/psf" )))) procedure( ggload( ggff ) prog( () rdbLoadResults( _vivaGetSessionName() ggff ) ) ) procedure( ggreload( ggff ) prog( () rdbReloadResults( _vivaGetSessionName() ggff ) ) ) procedure( ggunload( ggff ) prog( () rdbUnloadResults( _vivaGetSessionName() ggff ) ) ) procedure( ggselect( ggff ) prog( () rdbSetCurrentDirectory( _vivaGetSessionName() ggff ) ) ) procedure( ggrun(lib cell) prog( () ggsession = maeOpenSetup( lib cell "maestro" ) gghist = maeRunSimulation() maeWaitUntilDone(gghist) maeOpenResults() ggfname = maeExportOutputView() printf("Outputs in : %s\n" ggfname) ) ) procedure( ggclose( @optional ( gopt "NA" ) "t" ) prog( () maeCloseResults() if( (gopt == "-d") then maeDeleteSimulationData(gghist) ) maeCloseSession(?session ggsession) ) ) ; ggff is the simulation data ; ggff = ggData() ; ggload(ggff) ; ggunload(ggff) ; * ************************************************************************************************* ; 888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 ; *********************************************************** ; Open the session ; *********************************************************** ggsession = maeOpenSetup("mylib" "mycell" "maestro") ; *********************************************************** ; *********************************************************** ; Run the simulation ; *********************************************************** gghist = maeRunSimulation() maeWaitUntilDone(gghist) ; *********************************************************** ; *********************************************************** ; Export the Results ; *********************************************************** ggfname = maeExportOutputView() printf("Outputs in %s\n" ggfname) ; *********************************************************** ; *********************************************************** ; Create some signals ; *********************************************************** maeOpenResults() wc = VT("/ck00") - VT("/ck12") wa = VT("/A") - VT("/vref") wy = VT("/ycp") - VT("/ycn") ocnPrint(wc wa wy ?output "~/gout_00.matlab" ?width 17 ?precision 15 ?numberNotation 'none) printf("done\n") ; *********************************************************** ; *********************************************************** ; Close the session ; *********************************************************** ; maeCloseResults() ; maeDeleteSimulationData(gghist) ; maeCloseSession(?session ggsession) ; *********************************************************** ; 888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 % 777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777 % yplot.m % 777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777 graphics_toolkit gnuplot % Right click a signal in Viva % Send_to --> Export --> yout (select Type=Matlab) % Now go to your RH terminal % zip -r yout.zip your.matlab % mv yout.zip ~ % Now go to Debian Terminal % cd wwoct % scp $RH:yout.zip . % unzip yout.zip % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % read in the data % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fp = fopen('yout.matlab', 'r'); % skip 1 line for i = 1:1 lbuff = fgetl(fp); disp(lbuff) end gdata = fscanf(fp, '%f,%f', [2 Inf]); fclose(fp); % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % ttvec is raw time points % yyvec is raw yval points % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ttvec = gdata(1, 1:end); yyvec = gdata(2, 1:end); NUMP = length(ttvec); % plot(ttvec, yyvec); % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Find the third falling edge crossing -0.45 % then find the next rising edge crossing -0.45 % then take the average of these as the ideal sample time % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ytar = -0.45 done = false; NR = 0; to = ttvec(1); yo = yyvec(1); i = 2; while (~done) t = ttvec(i); y = yyvec(i); if ((yo >= ytar) && (y < ytar)) NR = NR + 1; if (NR == 3) tf = to + (yo - ytar) / (yo - y) * (t - to); done = true; end end i = i + 1; to = t; yo = y; end done = false; while (~done) t = ttvec(i); y = yyvec(i); if ((yo <= ytar) && (y > ytar)) tr = to + (ytar - yo) / (y - yo) * (t - to); done = true; end i = i + 1; to = t; yo = y; end ts = (tf + tr) / 2.0; % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Now create the digital vector set % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % number of samples on left side of zero NL = round((2.0e-6 - ts) / 200e-12); NMAX = 2 * NL; svec = ts + (0:NMAX)*200e-12; hvec = interp1(ttvec, yyvec, svec); rvec = round(hvec/0.9); % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % qvec is raw integrated time points % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% qvec = cumsum(rvec); % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % dvec is the uniform running integral % avec is the running integral over t-100samples to t+100samples % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% NT2 = 100; NT = 2 * NT2 dvec = svec(1+NT2:end-NT2); a2vc = qvec(NT+1:end); a1vc = qvec(1:end-NT); avec = a2vc - a1vc; avec = (a2vc - a1vc) / 400.0 + 0.5; vvec = dvec / 4.0e-6 * 40e-3 - 20e-3; sig = 1.5e-3; mu = 0.5e-3 cvec = 0.5*(1.0+erf((vvec-mu)/(sig*sqrt(2)))); plot(vvec, avec, vvec, cvec) % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777 * ********************************************************************************************** Virtuoso ADE Explorer and Virtuoso ADE Assembler - RAK (hosted by Mike Kennedy) Try setting up variables, then run preview Try grouping two variables as a parametric set Also mulitest editor mae skill functions replace ocean * ********************************************************************************************** Spectre X uses 1.5 times number of tokens as APS In Explorer, plotting Templates not available when in "Append" mode * ********************************************************************************************** x --> descend_edit() b --> return() The most important form is Setup-->High-Performance * Always choose APS * Error Preset : Always choose "Do not override", and then set the accuracy in each simulation itself * APS Options : Do not enable ++aps unless you aren't able to go as fast as you need, want to try and speed up things, and never enable it if you are doing an RF sim * Post-Layout Optimization : Always enable this even if it is a post layout sim, even if it is a very critical sim. You need to have this enabled if it is post layout. You do not need to set the max frequency. you can leave it blank * ********************************************************************************************** Harmonic Balance (hb) Choose Analysis --> hb (Do not choose Analysis --> pss --> hb button) Option 1 --> Run Transient? : Yes Stop Time (tstab) : put a reasonable time Option 2 --> Run Transient? : "Decide automatically" Dynamic Parameter - You can modify a parameter based on time For example : reltol you could create a table of values vs. time (it can be a simulation parameter, or a design variable, but you can only have one!) Number of Tones : Fundamental Frequency : VAR("fin") (where fin is a design variable) Number of Harmonics : auto (auto is usually a good choice) Oversample Factor : 1 (1 for linear, 2 if non-linear, can use up to 4, but this setting slows down sim) Sweep : (you can sweep up to 3 variables) Period Study State (pss) (do not choose Harmonic Balance, always choose Shooting) Output Harmonics : 10 (this only affects what you see at the output) (this is not actually used by the solver, unlike in hb) Run Transient - This is same, you can choose automatic or set yourself pnoise - you must have done (pss) The sidebands number should match number of harmonics in pss or maxacfreq (in pss-->options-->Accuracy-->maxacfreq=(set to 50*fundamental)) hbnoise - you must have done (hb) maxmimum sidebands must match number harmonics in hb Plot Results-->Direct_Plot-->Main_Form (always check "Add To Outputs" and it will add to your results expressions for next time.) Scaler Expression --> Value At discreet points (new feature) If you do Analysis-->pss (do not choose Harmonic Balance, always choose Shooting) Output Harmonics : 10 (this only affects what you see at the output) (this is not actually used by the solver, unlike in hb) Run Transient - This is same, you can choose automatic or set yourself