/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: SCRunBase.java
* Written by Jonathan Gainsley, Sun Microsystems.
*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.simulation.sctiming;
import com.sun.electric.database.geometry.ERectangle;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.variable.VarContext;
import com.sun.electric.tool.io.output.Spice;
import com.sun.electric.tool.lang.EvalJavaBsh;
import com.sun.electric.tool.simulation.SimulationTool;
import com.sun.electric.tool.user.User;
import com.sun.electric.util.TextUtils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
*
*/
public class SCRunBase {
/**
* Gates with pre-configured timing arcs
*/
public enum GateType {
/** Inverter */ INV,
/** High threshold inverter */ INVHT,
/** Low threshold inverter */ INVLT,
/** Clock threshold inverter */ INVCLK,
/** 2 input NAND */ NAND2EN,
/** 2 input NAND */ NAND2CLKEN,
/** 2 input NAND */ NAND2,
/** 3 input NAND */ NAND3,
/** 2 input NOR */ NOR2,
/** 2 input XOR */ XOR2
/** DDR flop */ //DDR, FLOPDDR,
/** SDR flop */ //SDR, FLOPSDR
}
/**
* Delay type, Max or Min path timing
*/
public enum DelayType {
/** Max delay */ MAX,
/** Min delay */ MIN,
}
/**
* Characterize all pre-configured cells in the current Electric library.
* @param settings the settings to use
* @return true on success, false on failure.
*/
public boolean characterizeCells(SCSettings settings, DelayType delayType) {
Library lib = Library.getCurrent();
if (lib == null) {
System.out.println("No current library to characterize");
return false;
}
// set up directories
File libraryDir = null;
if (lib.getLibFile() != null)
libraryDir = TextUtils.getFile(lib.getLibFile()).getParentFile();
else
libraryDir = new File(User.getWorkingDirectory());
File outputDir = new File(libraryDir, lib.getName()+"_chardata"+delayType.toString());
if (!outputDir.exists()) {
if (!outputDir.mkdir()) {
System.out.println("Cannot make char data directory "+outputDir.getPath());
return false;
}
}
System.out.println("Set output directory to "+outputDir.getPath());
settings.setLibrary(lib.getName());
LibData.Group library = settings.getLibrary();
// see if lib file already exists
File libertyFile = new File(libraryDir, lib.getName()+"."+delayType.toString()+".lib");
if (libertyFile.exists()) {
// read it
LibData libdata = parseExisting(libertyFile);
if (libdata != null) {
System.out.println("Found existing liberty file "+libertyFile.getPath());
System.out.println(" Using settings in existing liberty file");
System.out.println(" Characterizing new cells only");
settings.getSettingsFromLibData(libdata);
library = libdata.getLibrary();
} else {
System.out.println("Error reading existing liberty file");
return false;
}
}
// See if extracted netlist exists
Map<String,String> extractedCells = new HashMap<String,String>();
File extractedNetlist = new File(User.getWorkingDirectory(), lib.getName()+".sp");
if (extractedNetlist.exists()) {
try {
BufferedReader in = new BufferedReader(new FileReader(extractedNetlist));
String line = null;
while ( (line = in.readLine()) != null) {
if (line.startsWith(".SUBCKT")) {
String [] parts = line.split("\\s+");
if (parts.length >= 2) {
extractedCells.put(parts[1], parts[1]);
}
}
}
in.close();
} catch (IOException ee) {
System.out.println(ee.getMessage());
}
}
boolean warned = false;
// Characterize all cells in library for which we have characterization settings
List<String> messages = new ArrayList<String>();
for (Iterator<Cell> it = lib.getCells(); it.hasNext(); ) {
Cell c = it.next();
if (c.getView() == View.LAYOUT) {
if (c != c.getNewestVersion()) continue;
String verilogCellName = Spice.getSafeNetName(c.getName(), SimulationTool.SpiceEngine.SPICE_ENGINE_H);
// if data already in liberty file, ignore
List<LibData.Group> existing = library.getGroups("cell", verilogCellName);
if (existing.size() > 0) {
messages.add("Info: Skipped cell "+c.getName()+", already exists in liberty file data");
continue;
}
SCTiming timing = getSCTimingSetup(c, settings);
String cname = c.getName();
if (timing == null) {
messages.add("Warning: Skipping "+cname+": Unable to find timing arcs");
continue;
}
File cellDir = new File(outputDir, c.getName());
if (!cellDir.exists()) {
if (!cellDir.mkdir()) {
messages.add("Error: Cannot make cell char data directory "+cellDir.getPath()+"; skipping cell "+cname);
continue;
}
}
// Use either star rcxt extracted netlist or write netlist from Electric layout
File outputFile = new File(cellDir, c.getName()+".sp");
String cellName = Spice.getSafeNetName(c.getName(), SimulationTool.SpiceEngine.SPICE_ENGINE_H);
if (extractedCells.containsKey(cellName)) {
try {
PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
writer.println("* Characterization file for Cell "+cellName);
writer.println("*");
writer.println(".include '"+extractedNetlist.getAbsolutePath()+"'");
writer.println(".include '"+settings.commonHeaderFile+"'");
writer.println();
writer.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
timing.setTopCellName(cellName);
} else {
// set correct settings for spice netlisting
Spice.SpicePreferences sp = new Spice.SpicePreferences(true, false);
sp.writeSubcktTopCell = true;
sp.writeTopCellInstance = false;
sp.writeTransSizeInLambda = true;
sp.writeEmptySubckts = false;
sp.cdlIgnoreResistors = false;
sp.useCellParameters = true;
sp.parasiticsLevel = SimulationTool.SpiceParasitics.RC_CONSERVATIVE;
sp.writeFinalDotEnd = false;
sp.parasiticsUseExemptedNetsFile = false;
sp.parasiticsExtractsR = true;
sp.parasiticsExtractsC = true;
if (settings.commonHeaderFile.length() > 0)
sp.headerCardInfo = settings.commonHeaderFile;
// write spice netlist
sp.doOutput(c, VarContext.globalContext, outputFile.getPath());
timing.setTopCellName(c.getName());
}
timing.setOutputDir(cellDir.getPath());
timing.setTopCell(c);
timing.setTopCellNameLiberty(verilogCellName);
timing.setInputFile(outputFile.getPath());
try {
timing.characterize_(delayType);
} catch (SCTimingException e) {
messages.add("Error: Failed to characterize cell "+c.describe(false)+": "+e.getMessage());
continue;
}
timing.getCellLibData(library);
// set area of cell
List<LibData.Group> list = library.getGroups("cell", verilogCellName);
ERectangle rect = c.getBounds();
double scale = c.getTechnology().getScale() / 1000; // lambda to microns
double area = rect.getWidth() * rect.getHeight() * scale * scale;
for (LibData.Group g : list) {
g.putAttribute("area", area);
}
}
}
System.out.println("\nCharacterization Complete\n");
for (String message : messages) {
System.out.println(message);
}
if (libertyFile.exists()) {
File temp = new File(libertyFile.getPath());
File backup = new File(libertyFile.getParent(), libertyFile.getName()+".old");
System.out.println("Renaming existing liberty file to "+backup.getName());
if (!temp.renameTo(backup)) {
System.out.println("Warning, unable to rename "+libertyFile.getName()+" to "+backup.getName());
}
}
LibData libData = new LibData();
libData.setLibrary(library);
libData.write(libertyFile.getPath());
System.out.println("Wrote liberty file to "+libertyFile.getPath());
return true;
}
protected LibData parseExisting(File libertyFile) {
return null;
}
/**
* Get an SCTiming object with Timing Arcs for the given cell
* @param cell the cell
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSCTimingSetup(Cell cell, SCSettings settings) {
SCTiming timing = null;
for (Iterator<Cell> itc = cell.getCellGroup().getCells(); itc.hasNext(); ) {
Cell acell = itc.next();
if (acell.getView() == View.DOC && acell == acell.getNewestVersion()) {
timing = getSetupFromScript(acell.getTextViewContents(), settings);
break;
}
}
if (timing == null) {
String cname = cell.getName().toLowerCase();
for (GateType type : GateType.values()) {
if (cname.matches(type.toString().toLowerCase()+"_x[0-9.]+")) {
String size = cname.substring(cname.lastIndexOf("x")+1, cname.length());
double xsize = Double.parseDouble(size);
timing = getSCTimingSetup(type, settings, xsize);
break;
}
}
}
return timing;
}
private static Pattern cellsize1 = Pattern.compile(".*?_([0-9.]+)x");
private static Pattern cellsize2 = Pattern.compile(".*?_x([0-9.]+)");
public static double getCellSize(String cellname) {
String s = null;
Matcher m1 = cellsize1.matcher(cellname);
if (m1.matches()) {
s = m1.group(1);
} else {
Matcher m2 = cellsize2.matcher(cellname);
if (m2.matches()) {
s = m2.group(1);
}
}
if (s != null) {
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {
return 1.0;
}
}
return 1.0;
}
public static SCTiming getSetupFromScript(String [] script, SCSettings settings) {
EvalJavaBsh bsh = new EvalJavaBsh();
bsh.doEvalLine("import com.sun.electric.tool.simulation.sctiming.*;");
SCTiming timing = new SCTiming();
timing.setSettings(settings);
bsh.setVariable("timing", timing);
bsh.setVariable("settings", settings);
boolean run = false;
boolean scriptFound = false;
for (String line : script) {
if (line.toLowerCase().startsWith("--start characterization script")) {
run = true;
scriptFound = true;
continue;
}
if (line.toLowerCase().startsWith("--end characterization script")) {
run = false;
continue;
}
if (run)
bsh.doEvalLine(line);
}
Object t = bsh.getVariable("timing");
if (scriptFound && t instanceof SCTiming)
return (SCTiming)t;
return null;
}
/**
* Get an SCTiming object with Timing Arcs for the given gate type
* @param type recognized gate type
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSCTimingSetup(GateType type, SCSettings settings, double xsize) {
switch (type) {
case INV: return getSetupInv(settings, xsize);
case INVHT: return getSetupInv(settings, xsize);
case INVLT: return getSetupInv(settings, xsize);
case INVCLK: return getSetupInv(settings, xsize);
case NAND2: return getSetupNand2(settings, xsize);
case NAND2EN: return getSetupNand2en(settings, xsize);
case NAND2CLKEN: return getSetupNand2en(settings, xsize);
case NAND3: return getSetupNand3(settings, xsize);
case NOR2: return getSetupNor2(settings, xsize);
//case XOR2: return getSetupXor2(settings, xsize);
//case DDR: return getSetupFlopDDR(settings);
//case FLOPDDR: return getSetupFlopDDR(settings);
//case SDR: return getSetupFlopSDR(settings);
//case FLOPSDR: return getSetupFlopSDR(settings);
}
return null;
}
/**
* Get an SCTiming object with Timing Arcs for an Inverter type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupInv(SCSettings settings, double xsize) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionCombinational("out", "!in");
String outputLoads = getLoadSweep(xsize);
String buffers = getInputBufferSweep(xsize);
Arc arc = new Arc();
arc.setInputTransition("in", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("in", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
return timing;
}
/**
* Get an SCTiming object with Timing Arcs for a NAND2 type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupNand2(SCSettings settings, double xsize) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionCombinational("out", "!(ina * inb)");
String outputLoads = getLoadSweep(xsize);
String buffers = getInputBufferSweep(xsize);
Arc arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
return timing;
}
/**
* Get an SCTiming object with Timing Arcs for a NAND2EN type gate
* NOTE: this assumes inb is the enable input
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupNand2en(SCSettings settings, double xsize) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionCombinational("out", "!(ina * inb)");
String outputLoads = getLoadSweep(xsize);
String buffers = getInputBufferSweep(xsize);
Arc arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
//arc.setOutputLoadSweep("2 4 8 12 24 26 28 30");
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
//arc.setOutputLoadSweep("2 4 8 12 24 26 28 30");
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
return timing;
}
/**
* Get an SCTiming object with Timing Arcs for a NAND3 type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupNand3(SCSettings settings, double xsize) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionCombinational("out", "!(ina * inb * inc)");
String outputLoads = getLoadSweep(xsize);
String buffers = getInputBufferSweep(xsize);
Arc arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
arc.addStableInput("inc", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
arc.addStableInput("inc", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.addStableInput("inc", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.addStableInput("inc", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inc", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inc", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("ina", PinEdge.Transition.STABLE1);
arc.addStableInput("inb", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
return timing;
}
/**
* Get an SCTiming object with Timing Arcs for a NOR2 type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupNor2(SCSettings settings, double xsize) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionCombinational("out", "!(ina + inb)");
String outputLoads = getLoadSweep(xsize);
String buffers = getInputBufferSweep(xsize);
Arc arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("inb", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("inb", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addStableInput("ina", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addStableInput("ina", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
return timing;
}
/**
* Get an SCTiming object with Timing Arcs for a XOR2 type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupXor2(SCSettings settings, double xsize) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionCombinational("out", "ina ^ inb");
String outputLoads = getLoadSweep(xsize);
String buffers = getInputBufferSweep(xsize);
Arc arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addDependentStableInput("inb", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addDependentStableInput("inb", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addDependentStableInput("inb", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("ina", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addDependentStableInput("inb", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addDependentStableInput("ina", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addDependentStableInput("ina", PinEdge.Transition.STABLE1);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.RISE);
arc.setOutputTransition("out", PinEdge.Transition.RISE);
arc.addDependentStableInput("ina", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("inb", PinEdge.Transition.FALL);
arc.setOutputTransition("out", PinEdge.Transition.FALL);
arc.addDependentStableInput("ina", PinEdge.Transition.STABLE0);
arc.setOutputLoadSweep(outputLoads);
arc.setInputBufferSweep(buffers);
timing.addTimingArc(arc);
return timing;
}
// params for load and input buffer sweeps
private static double lowerBound = 0.00001;
private static int upperBound = 310;
private static int numSizes = 8;
/**
* Get sweep of loads based on dut xsize
* @param xsize size of gate to characterize
* @return list of sizes to use for loads
*/
public static String getLoadSweep(double xsize) {
// config, hard coded for now.
double minStepup = 0.5;
double maxStepup = 12;
double minSize = xsize*minStepup;
double maxSize = xsize*maxStepup;
double stepX = (maxSize - minSize) / numSizes;
double su = Math.pow(maxStepup/minStepup, 1.0/(numSizes-1));
StringBuffer loads = new StringBuffer();
for (int i=0; i<numSizes; i++) {
//double size = minSize+(i)*stepX;
double size = xsize * minStepup * Math.pow(su, i);
if (size < lowerBound || size > upperBound) continue;
loads.append(TextUtils.formatDouble(size,2)+" ");
}
return loads.toString().trim();
}
public static String getInputBufferSweep(double xsize) {
double minStepup = 1.0/12;
double maxStepup = 2.0;
double su = Math.pow(maxStepup/minStepup, 1.0/(numSizes-1));
StringBuffer loads = new StringBuffer();
for (int i=numSizes-1; i>=0; i--) {
double size = xsize * minStepup * Math.pow(su, i);
size = size/2; // account for second inverter in buffer that is double size
if (size < lowerBound || size > upperBound) continue;
loads.append(TextUtils.formatDouble(size,2)+" ");
}
return loads.toString().trim();
}
/**
* Get an SCTiming object with Timing Arcs for a DDR Flop type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupFlopDDR(SCSettings settings) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionFlipFlop("Q", "QB", "D", "clkt");
Arc arc = new Arc();
arc.setInputTransition("D", PinEdge.Transition.RISE);
arc.setOutputTransition("Q", PinEdge.Transition.RISE);
arc.setClkTransition("clkt", PinEdge.Transition.RISE);
arc.setClkFalseTransition("clkf", PinEdge.Transition.FALL);
arc.addDUTInitialCondition("topnode2", settings.vdd);
arc.addDUTInitialCondition("topnode1", 0);
arc.addDUTInitialCondition("botnode2", settings.vdd);
arc.addDUTInitialCondition("botnode1", 0);
arc.setInputTransition("clr", PinEdge.Transition.STABLE0);
arc.setInputTransition("init", PinEdge.Transition.STABLE0);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("D", PinEdge.Transition.FALL);
arc.setOutputTransition("Q", PinEdge.Transition.FALL);
arc.setClkTransition("clkt", PinEdge.Transition.RISE);
arc.setClkFalseTransition("clkf", PinEdge.Transition.FALL);
arc.addDUTInitialCondition("topnode2", 0);
arc.addDUTInitialCondition("topnode1", settings.vdd);
arc.addDUTInitialCondition("botnode2", 0);
arc.addDUTInitialCondition("botnode1", settings.vdd);
arc.setInputTransition("clr", PinEdge.Transition.STABLE0);
arc.setInputTransition("init", PinEdge.Transition.STABLE0);
timing.addTimingArc(arc);
return timing;
}
/**
* Get an SCTiming object with Timing Arcs for a SDR Flop type gate
* @param settings global settings
* @return SCTiming object for characterization
*/
public static SCTiming getSetupFlopSDR(SCSettings settings) {
SCTiming timing = new SCTiming();
timing.setSettings(settings);
timing.setFunctionFlipFlop("Q", "QB", "D", "clkt");
Arc arc = new Arc();
arc.setInputTransition("D", PinEdge.Transition.RISE);
arc.setOutputTransition("Q", PinEdge.Transition.RISE);
arc.setClkTransition("clkt", PinEdge.Transition.RISE);
arc.setClkFalseTransition("clkf", PinEdge.Transition.FALL);
timing.addTimingArc(arc);
arc = new Arc();
arc.setInputTransition("D", PinEdge.Transition.FALL);
arc.setOutputTransition("Q", PinEdge.Transition.FALL);
arc.setClkTransition("clkt", PinEdge.Transition.RISE);
arc.setClkFalseTransition("clkf", PinEdge.Transition.FALL);
timing.addTimingArc(arc);
return timing;
}
}