/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: HsimModel.java * Written by Frankie Liu, Sun Microsystems. * * Copyright (c) 2008 Sun Microsystems and Static Free Software * * 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.test; import java.util.*; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.io.*; public class HsimModel extends NanosimModel { protected String simFile; public HsimModel() { super(); } /** * Set the voltage on node * @param node name of node * @param value voltage to set in volts */ public void setNodeVoltage(String node, double value) { if (assuraRCXNetlist) { node = node.replaceAll("\\.", "/"); } else if (starRCXTNetlist) { if (node.startsWith("x")) node = node.substring(1); node = node.replaceAll("\\.x?", "/"); } node = node.replaceAll("\\[","?"); node = node.replaceAll("\\]","?"); issueCommand("fv "+node+" "+value); } /** * Releases (forcing) on voltage on node * @param node name of node */ public void releaseNodeVoltage(String node){ if (assuraRCXNetlist) { node = node.replaceAll("\\.", "/"); } else if (starRCXTNetlist) { if (node.startsWith("x")) node = node.substring(1); node = node.replaceAll("\\.x?", "/"); } node = node.replaceAll("\\[","?"); node = node.replaceAll("\\]","?"); issueCommand("rv "+node+""); } /** * Sets voltage on node to 0 * @param node name of node */ public void disableNode(String node) { setNodeVoltage(node,0); // waitNS(timeStep); } /** * Same a releaseNodeVoltage * @param node name of node */ public void enableNode(String node) { releaseNodeVoltage(node); // waitNS(timeStep); } /** * Checks if simFile is from Assura RCX * @return true if no IOException */ protected boolean checkRcx() { // check if simfile is from assura RCX // if it is, we will have to replace hierarchy delimiter '.' with '/' System.out.println(simFile); try { BufferedReader freader = new BufferedReader(new FileReader(simFile)); // PROGRAM will be in the first 10 or so lines, so search up till line 20 for (int i=0; i<20; i++) { String line = freader.readLine(); if (line == null) break; if (line.matches("\\* PROGRAM .*?assura.*")) { assuraRCXNetlist = true; System.out.println("Info: Running on Assura extracted netlist, will replace all '.' in net names with '/'"); break; } else if (line.matches("\\*|PROGRAM .*?Star-RCXT.*")) { starRCXTNetlist = true; System.out.println("Info: Running on Star-RCXT extracted netlist, will replace all '.x' in net names with '/'"); break; } } } catch (IOException e) { System.out.println(e.getMessage()); return false; } return true; } boolean start_(String command, String simFile, int recordSim) { setPrompt("HSIM > "); this.simFile=simFile; if (!checkRcx()){ return false; } // consider the -top option when the top-level goo is wrapped in a .subckt // max sim time (-t) is 90071s // -wait_lic? if (!startProcess(command+" -time 90000 "+simFile+" -o "+simFile, null, null, simFile+".run")) return false; // get value of vdd //vdd = getNodeVoltage("vdd"); vdd = 0.9; if (DEBUG) System.out.println("Using VDD of "+vdd); timeStep = getSimTres(); if (DEBUG) System.out.println("Using time step of "+timeStep+" ns"); // initialize test devices for (Iterator it = logicSettables.iterator(); it.hasNext(); ) { NanosimLogicSettable ls = (NanosimLogicSettable)it.next(); if (!ls.init()) { System.out.println("LogicSettable initialization failed, aborting."); return false; } } for (Iterator it = jtagTesters.iterator(); it.hasNext(); ) { JtagTester tester = (JtagTester)it.next(); tester.reset(); } return true; } protected static final Pattern patSimTime = Pattern.compile("tnow=(\\S+)ns"); public static final double badtime = -1; /** * Gets simulation time * @return simulation time in ns */ public double getSimTime() { issueCommand("pt"); String result = getLastCommandOutput().toString(); if(!result.startsWith("tnow")){ System.out.println(">> Error in getSimTime : no tnow"); return badtime; } Matcher m = patSimTime.matcher(result); if (!m.find()){ System.out.println(">> Error in getSimTime : no match"); return badtime; } double tmp; try { tmp = Double.parseDouble(m.group(1)); } catch(NumberFormatException e) { System.out.println(">> Error in getSimTime : bad number conversion"); return badtime; } return tmp; } /** * Applies voltages and continues simualtion for a time * @param nanoseconds time to continue simuation * @param applyVoltages true if voltages are to be applied */ public void waitNS(double nanoseconds, boolean applyVoltages) { if (applyVoltages) applyVoltages(); double tmp = getSimTime(); if (tmp!=badtime) { simTime = tmp; } // calculate stop time (time at which to set breakpoint) double stopTime = simTime + nanoseconds; // set break point issueCommand("stop -at "+stopTime); // in ns issueCommand("cont"); simTime = stopTime; } /** * Get the simulation's time step * @return the simulation time step in nanoseconds */ public double getSimTres() { return 0.01; // default is 10ps } // ==================================================================== // ==================================================================== // Get/Set voltages // ==================================================================== // ==================================================================== /** * This is used to apply all voltages at the same time for the current time step. */ public void applyVoltages() { // release all forced nodes releaseNodes(new ArrayList(nodesToSet.keySet())); // all nodes are released, now apply all the values for (Iterator it = nodesToSet.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry)it.next(); String node = (String)entry.getKey(); Double voltage = (Double)entry.getValue(); if (assuraRCXNetlist) { node = node.replaceAll("\\.", "/"); } else if (starRCXTNetlist) { if (node.startsWith("x")) node = node.substring(1); node = node.replaceAll("\\.x?", "/"); } setNodeVoltage(node,voltage.doubleValue()); } nodesToSet.clear(); // waitNS(timeStep, false); } /** * release the list of nodes (Strings) */ public void releaseNodes(List nodes) { for (Iterator it = nodes.iterator(); it.hasNext(); ) { String node = (String)it.next(); if (assuraRCXNetlist) { node = node.replaceAll("\\.", "/"); } else if (starRCXTNetlist) { if (node.startsWith("x")) node = node.substring(1); node = node.replaceAll("\\.x?", "/"); } releaseNodeVoltage(node); } // waitNS(timeStep, false); } // sample output: // // HSIM > nv out // Node out (2): // V=0.628472, dV/dt=0.00371528 V/ns, time=100.000000ns // Capacitance report // Constant node capacitance : 10000 fF // Voltage-dependent node capacitance : 0 fF // Total node capacitance : 10000 fF protected static final Pattern patNodeInfo[] = { Pattern.compile(".*?V=(\\S+), dV/dt=(\\S+) (\\S+), time=(\\S+)"), Pattern.compile(".*?Constant node capacitance\\s+: (\\S+) (\\S+)"), Pattern.compile(".*?Voltage-dependent node capacitance\\s+: (\\S+) (\\S+)"), Pattern.compile(".*?Total node capacitance\\s+: (\\S+) (\\S+)") }; /** * Gets the voltages on the nodes * @param nodes the nodes to query * @param returnState defunct, not used * @return a list of voltages, or null on error */ protected List getNodeInfo(List nodes, boolean returnState) { // apply any outstanding voltages if (nodesToSet.size() > 0) applyVoltages(); if (assuraRCXNetlist || starRCXTNetlist) { List nodesfixed = new ArrayList(); for (Iterator it = nodes.iterator(); it.hasNext(); ) { String node = (String)it.next(); if (assuraRCXNetlist) { node = node.replaceAll("\\.", "/"); } else if (starRCXTNetlist) { if (node.startsWith("x")) node = node.substring(1); node = node.replaceAll("\\.x?", "/"); } nodesfixed.add(node); } nodes = nodesfixed; } List nodeslc = new ArrayList(); List voltages = new ArrayList(); StringBuffer cmd = new StringBuffer(); cmd.append("nv "); boolean error=false; for (Iterator it = nodes.iterator(); it.hasNext() && !error; ) { String node = (String)it.next(); node = node.toLowerCase(); nodeslc.add(node); String nodex = node; nodex = nodex.replaceAll("\\[","?"); nodex = nodex.replaceAll("\\]","?"); // HACK if (nodex.equals("vss")) { voltages.add(0); } else { cmd.append(nodex); issueCommand(cmd.toString()); String result = getLastCommandOutput().toString(); /* String [] results = result.toString().trim().split("\n"); int i = results.length; for (i=0;i<results.length;i++){ System.out.println("Results: "+i); System.out.println(results[i]); } */ if (!result.startsWith("Node "+node)) { System.out.println("Error on getInfoNode: for node "+node+"; result:\n "+result); error=true; continue; } Double voltage = new Double(0); Double dvdt = new Double(0); Double time = new Double(0); Double cap = new Double(0); Double vcap = new Double(0); Double tcap = new Double(0); for (int patternIndex=0; patternIndex < patNodeInfo.length && !error; patternIndex++) { Matcher m = patNodeInfo[patternIndex].matcher(result); if (!m.find()){ System.out.println(">> Error on getInfoNode : for node "+node); System.out.println(">> Pattern " + patternIndex +" : "+patNodeInfo[patternIndex]); System.out.println(">> String : "+result); error=true; continue; } try { switch (patternIndex) { case 0: voltage = Double.parseDouble(m.group(1)); dvdt = Double.parseDouble(m.group(2)); // time = Double.parseDouble(m.group(4)); break; case 1: cap = Double.parseDouble(m.group(1)); break; case 2: vcap = Double.parseDouble(m.group(1)); break; case 3: tcap = Double.parseDouble(m.group(1)); break; case 4: break; default: } } catch (NumberFormatException e) { System.out.println(">> Error on get_info_node: NumberFormatException for node "+node); System.out.println(">> Pattern: "+patNodeInfo[patternIndex]); System.out.println(">> String: "+result); for(int ngroup=0;ngroup<=m.groupCount();ngroup++){ System.out.println(">> Group "+ngroup+" : "+m.group(ngroup)); } error=true; continue; } result = result.substring(m.end()); if (DEBUG) { System.out.println(">> Pattern: "+patNodeInfo[patternIndex]); System.out.println(">> "+result); } } if (DEBUG) { System.out.println("getInfoNode "+node+":"); System.out.println(voltage); System.out.println(dvdt); System.out.println(time); System.out.println(cap); System.out.println(vcap); System.out.println(tcap); } voltages.add(returnState ? (voltage >= vdd/2 ? 1.0 : 0.0) : voltage); } } if (error) return null; else return voltages; } /** * Saves all nodes. Xref restartDatabase, see also .STORE/.RESTORE * @param filename */ public void saveDatabase(String filename) { issueCommand("savesim filename"); } /** * Restore all nodes. Xref saveDatabase, see also .STORE/.RESTORE * @param filename * @param timens some earlier time in nanoseconds, basically * one can restart many times, each output file will have .rs# suffix */ public void restartDatabase(String filename,double timens) { issueCommand("restart "+timens+" "+filename); } /** Unit Test * This test requires the file sim.spi in your working dir * */ public static void main(String[] args) { HsimModel nm = new HsimModel(); // the example file sim.spi needs to be in your working dir nm.start("hsim64", "rc.sp", 0); nm.issueCommand("pt"); nm.waitNS(2); nm.finish(); /* rc.sp * Title .option post vin vdd gnd 1 rin vdd out 10k cout out gnd 10p .ic v(out) 0 .tran 10p 1000n .param HSIMSTOPAT=100n *.stop at=100n .print v(*) .end */ } }