;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; test.ocn ;;; Erik Brunvand, University of Utah ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; The following are strings that you should set, or at least understand, before ; you load this file and run these functions... ; ; set the lists of values for output load (in F), and input slope (in s), ; and set the vdd in volts. Note that the loadlist and slopelist need to ; be lists of strings, and if you have a single-digit exponent, it needs to ; have a 0 in front (i.e. "3.2e-09"). These lists can have as many values ; in them as you like. This example has two values in each list so it will ; generate a 4x4 array of results. The loadlist will be the horizontal ; axis of the output array, and the slopelist will be the vertical. ; loadlist = list( "6.75e-15" "5.4e-14" "1.08e-13" "2.16e-13" "4.32e-13") slopelist = list("1e-10" "8e-10" "1.6e-09" "3.2e-09" "6e-09") ; ; define the template type you're using in your .lib file. ; This is in the lu_table_template section of the .lib file. In this example ; we're generating a 4x4 matrix so I'll assume it's called lu4x4, but ; this can be whatever you define in your .lib header tabletype = "lu5x5" ; ; set the vdd, and the stop time for the transient analysis ; time_unit is the time unit in the .lib file (i.e. 1ns) vdd = 5.0 trans_stop_time = "50n" time_unit = 1e-9 ; ; ; The name of the input pulse (input net) to the DUT, and the ; output net from the DUT that you're trying to measure, also the ; names for the variables that will be set for load capacitance and ; input slope. ; test_sch_name is the name of the schematic that holds your test. ; This is the schematic whose config view you want to simulate. ; inNode = "in" outNode = "out" loadvarname = "load" slopevarname = "slope" test_sch_name = "test_setup" cadencedir = "/home/elb/IC_CAD/cadence" ; your cadence directory ; ; Things below this line should be set based on the previous data. ; You shouldn't have to modify anything below here... But, you might ; want to look to make sure. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; update these dir names to reflect where your simulations will be ; If you've set the previous values, you shouldn't have to change this. ; desdir = strcat("/simulation/" test_sch_name); your simulation directory OFdir = strcat( cadencedir desdir ) ; where the output files go resdir = strcat( OFdir "/spectreS/config" ) ; where the sim results go ; make floating point versions of the load and slopelists. That is, convert ; the strings in the lists to floating point numbers. The reason we had the ; strings in the first place was so that we could use them to generate ; the directory names of the parametric result directories, but we also ; need them as numbers instead of strings for the input to the parametric ; simulation. loadlistF = list() slopelistF = list() foreach(load loadlist loadlistF = append1(loadlistF atof(load))) foreach(slope slopelist slopelistF = append1(slopelistF atof(slope))) ; construct some other values. These numbers are in terms of a ; percentage of vdd. ten = vdd * 0.1 ninety = vdd * 0.9 thirty = vdd * 0.3 seventy = vdd * 0.7 ; ; This procedure runs the parametric test with the values given earlier. ; The optional stop_time argument is a string that defines the ; stop time of the transient analysis. I.e. "50n" for 50 ns. ; This function needs to be called before you can print the ; table results in an output file. (procedure run_test( @optional (stop_time trans_stop_time)) ; ; define which simulator you're using, the design and results dir, ; and path to the transistor models ; simulator( 'spectreS ) design(strcat( resdir strcat("/netlist/" test_sch_name ".c"))) resultsDir( resdir ) path( "/uusoc/facility/cad_common/local/class/5710/spectre" "/uusoc/facility/cad_common/NCSU/CDK1.3/local/models/spectre/nom" ) ; make sure to set initial values of the design variables and temp. ; These will be reset in the parametric simulation so it's not really ; important what the values are... desVar( slopevarname 500p ) desVar( loadvarname .05p ) temp( 27 ) ; set up the transient analysis analysis('tran ?stop stop_time ) ; set up the parametric analysis based on the load and slopelists ; defined at the top of this file. Make sure to use the versions of the ; lists that have floating point numbers, not strings. paramAnalysis(loadvarname ?values loadlistF paramAnalysis(slopevarname ?values slopelistF)) ; run the simulation, and select the transient analysis as the results you ; want to look at. paramRun() selectResult( 'tran ) ; note that the plotting will only pop up a new window if you're running ; this script inside the analog environment, not if you're running ; ocean from the command line. save('v strcat("/" inNode) strcat("/" outNode)) plot(getData(strcat("/" inNode)) getData(strcat("/" outNode))) ) ; procedure run_test ; ; define a couple of helper procedures to make printing easier. ; ; Take a list of floating point numbers and print them out as ; "1, 2, 3, 4" ; in the file pointed to by OF (procedure fprint_flist(OF list) (fprintf OF "\"") (foreach element list (fprintf OF "%g" element) (if (not (equal element (car (last list)))) (fprintf OF ", "))) (fprintf OF "\" ") ) ; procedure fprint_flist ; Print the header of an array (procedure fprint_header(OF array_name array_type ) (fprintf OF "\n %s(%s) {\n" array_name array_type) (fprintf OF " values( \\\n") ) ; procedure fprint_header ; The "main" procedure which prints all four of the result tables based on the ; parametric simulation. ; filename is the name of the file that the results can go into. You can use this ; to make sure that you know which results are where. For example, the results ; from simulating the A->Y path in a nand gate can be called "nand_a_to_y" or ; something like that. ; If you don't give this procedure a gatetype parameter it will assume negative_unate. ; The choices for gatetype are 'neg and 'pos. (procedure fprint_results(filename @optional (gatetype 'neg)) ; open the output file for writing OF = (outfile (strcat OFdir "/" filename)) ; print each of the four tables in the output file (fprint_table OF 'cellrise gatetype) (fprint_table OF 'rise gatetype) (fprint_table OF 'cellfall gatetype) (fprint_table OF 'fall gatetype) ; make sure to close the file so that the data gets written (close OF) ) ; procedure fprint_results ; ; This will print a particular table into a particular file ; ; OF is the output file descriptor ; type is one of 'cellrise, 'cellfall, 'rise, and 'fall, ; gatetype is one of 'pos or 'neg meaning positive_unate or negative_unate. (procedure fprint_table(OF type gatetype) ; initialize the list that you're going to put each row ; of values into values = list(); ; initialize the table according to the type (caseq type (cellrise (fprint_header OF "cell_rise" tabletype)) (cellfall (fprint_header OF "cell_fall" tabletype)) (rise (fprint_header OF "rise_transition" tabletype)) (fall (fprint_header OF "fall_transition" tabletype))) ; now walk through the parametric simulation outputs and gather ; the data. Print it to the OF file one row at a time. foreach( slope slopelist foreach( load loadlist ; construct the name of each of the parametric result output ; directories. They are named by the values assigned to ; each of the load and slope variables in the test_setup file. ; the dir name for the results will be in the form ; /load=1.2e-09,slope=2.4e-10/psf ; under each dir, the results are in the psf dir dirname = strcat( "/load=" load ",slope=" slope ) respath = strcat( resdir dirname "/psf") ; open the results and select the transient analysis waveforms openResults(respath) selectResults('tran) ; get the voltage waveforms from that particular parametric ; run. ; v1 is the input waveform, and v2 is the output from the DUT v1 = v( inNode ?result "tran" ?resultsDir respath ) v2 = v( outNode ?result "tran" ?resultsDir respath ) ; compute delay. The "cross" function takes a voltage waveform ; and a value, and tells you where on the x axis the waveform ; reaches that value on the y. The next number is the instance ; of the edge (i.e. 1 is the first edge), and 'rising and 'falling ; say which type of edge. So, 1 'rising is the first rising edge ; in the waveform. ; ; For example, to find at which time the first rising edge of ; the input waveform reaches 10% of vdd use the following: ; var = cross( v1 ten 1 'rising ) ; build up the values in the value list according to type (caseq type (cellrise tv2SeventyR = cross( v2 seventy 1 'rising) tv1ThirtyR = cross( v1 thirty 1 'rising) tv1SeventyF = cross( v1 seventy 1 'falling) if( eq(gatetype 'neg) then Tpdr = tv2SeventyR - tv1SeventyF else Tpdr = tv2SeventyR - tv1ThirtyR) values = append1(values (Tpdr / time_unit))) (cellfall tv2ThirtyF = cross( v2 thirty 1 'falling) tv1ThirtyR = cross( v1 thirty 1 'rising) tv1SeventyF = cross( v1 seventy 1 'falling) if( eq(gatetype 'neg) then Tpdf = tv2ThirtyF - tv1ThirtyR else Tpdf = tv2ThirtyF - tv1SeventyF) values = append1(values (Tpdf / time_unit))) (rise tv2NinetyR = cross( v2 ninety 1 'rising ) tv2TenR = cross( v2 ten 1 'rising ) Trise = tv2NinetyR - tv2TenR values = append1(values (Trise / time_unit))) (fall tv2TenF = cross( v2 ten 1 'falling ) tv2NinetyF = cross( v2 ninety 1 'falling ) Tfall = tv2TenF - tv2NinetyF values = append1(values (Tfall / time_unit)))) ) ; foreach load ; The values list should have a row of the table now, so print it fprint_flist(OF values) ; add the row terminating strings (cond ((equal slope (car (last slopelist))) (fprintf OF ");}\n")) (t (fprintf OF ",\\\n"))) ; make sure to re-init the values list for the next row. values = nil ) ; foreach slope ) ; procedure fprintf_table ; ; A "do it all" function that runs the simulation and then generates the results (procedure run_all(filename @optional (gatetype 'neg)(stop_time trans_stop_time)) (run_test stop_time) (fprint_results filename gatetype) ) ; procedure run_all