1
package com.sun.electric.tool.simulation.test;
4
import java.util.regex.Pattern;
5
import java.util.regex.Matcher;
9
* Created by IntelliJ IDEA.
13
* Copyright (c) 2004,2005 by Sun Microsystems, Inc.
16
public class NanosimModel extends SimulationModel {
18
protected static final boolean DEBUG = false;
20
/** list of jtag testers */
21
protected final List jtagTesters;
22
/** list of logic settables */
23
protected final List logicSettables;
25
protected double simTime; // current simulation time in ns
27
protected double timeStep; // simulation time step in ns
28
protected final HashMap nodesToSet = new HashMap(); // key: node name, value: Double voltage
29
protected boolean assuraRCXNetlist = false;
30
protected boolean starRCXTNetlist = false;
33
* Create a new NanosimModel to simulate the behavior of the real chip
35
public NanosimModel() {
36
super("Nanosim", "quit", "ERROR", "");
37
jtagTesters = new ArrayList();
38
logicSettables = new ArrayList();
43
public JtagTester createJtagTester(String tckName, String tmsName, String trstbName, String tdiName, String tdobName) {
44
if (isProcessRunning()) {
45
System.out.println("Error: JtagTester test device must be created before process is started.");
48
NanosimJtagTester tester = new NanosimJtagTester(this, tckName, tmsName, trstbName, tdiName, tdobName);
49
jtagTesters.add(tester);
54
* Create a subchain tester based on the 8- or 9-wire jtag interface.
55
* jtag[8:0] = {scan_data_return, phi2_return, phi1_return, rd, wr, phi1, phi2, sin, mc*}
56
* Note that mc is not present on older designs, so they are jtag[8:1].
57
* @param jtagInBus the name of the 9-bit wide input bus, i.e. "jtagIn" or "jtagIn[8:0]"
58
* @param jtagOutBus the name of the 9-bit wide output bus, i.e. "jtagOut" or "jtagOut[8:0]"
60
public JtagTester createJtagSubchainTester(String jtagInBus, String jtagOutBus) {
61
if (isProcessRunning()) {
62
System.out.println("Error: JtagTester test device must be created before process is started.");
65
NanosimJtagSubchainTester tester = new NanosimJtagSubchainTester(this, jtagInBus, jtagOutBus);
66
jtagTesters.add(tester);
71
* Create a subchain tester based on the 5-wire jtag interface.
72
* @param phi2 name of the phi2 signal
73
* @param phi1 name of the phi1 signal
74
* @param write name of the write signal
75
* @param read name of the read signal
76
* @param sin name of the scan data in signal
77
* @param sout name of the scan data out signal
79
public JtagTester createJtagSubchainTester(String phi2, String phi1, String write, String read, String sin, String sout) {
80
if (isProcessRunning()) {
81
System.out.println("Error: JtagTester test device must be created before process is started.");
84
NanosimJtagSubchainTester tester = new NanosimJtagSubchainTester(this, phi2, phi1, write, read, sin, sout);
85
jtagTesters.add(tester);
89
public LogicSettable createLogicSettable(String portName) {
90
if (isProcessRunning()) {
91
System.out.println("Error: LogicSettable test device must be created before process is started.");
94
NanosimLogicSettable ls = new NanosimLogicSettable(this, portName);
95
logicSettables.add(ls);
99
public LogicSettable createLogicSettable(List portNames) {
100
if (portNames == null || portNames.size() < 1) {
101
System.out.println("Error: createLogicSettable given null or empty list of ports");
104
System.out.println("Error: createLogicSettable(List) is not supported by Nanosim, only using first port "+portNames.get(0));
105
return new NanosimLogicSettable(this, (String)portNames.get(0));
108
public void disableNode(String node) {
109
issueCommand("force_node_v v=0 no="+node);
113
public void enableNode(String node) {
114
issueCommand("rel_node_v no="+node);
118
public double getSimulationTime() {
122
boolean start_(String command, String simFile, int recordSim) {
123
// first, find out the nanosim version, as that determines the prompt in interactive mode
124
// setup the reader which will read the output of the process
125
PipedOutputStream ostream = new PipedOutputStream();
126
BufferedReader reader;
128
PipedInputStream istream = new PipedInputStream(ostream);
129
reader = new BufferedReader(new InputStreamReader(istream));
130
} catch (java.io.IOException e) {
131
System.out.println("Unable to create pipe to process output: "+e.getMessage());
134
ExecProcess process = new ExecProcess(command+" --version", null, null, ostream, ostream);
136
boolean found = false;
137
String version = null;
138
StringBuffer buf = new StringBuffer();
141
while ((line = reader.readLine()) != null) {
142
buf.append(line+"\n");
144
String [] args = line.split("\\s+");
145
if (args.length < 4) continue;
146
if (args[1].equals("Version")) {
148
setPrompt("Ver "+version+" >");
153
} catch (java.io.IOException e) {
155
System.out.println("Error determining nanosim version: "+e.getMessage());
156
System.out.println(buf);
161
System.out.println("Error determining nanosim version");
162
System.out.println(buf);
166
System.out.println("Using nanosim version "+version);
168
// check if simfile is from assura RCX
169
// if it is, we will have to replace hierarchy delimiter '.' with '/'
171
BufferedReader freader = new BufferedReader(new FileReader(simFile));
172
// PROGRAM will be in the first 10 or so lines, so search up till line 20
173
for (int i=0; i<20; i++) {
174
String line = freader.readLine();
175
if (line == null) break;
176
if (line.matches("\\* PROGRAM .*?assura.*")) {
177
assuraRCXNetlist = true;
178
System.out.println("Info: Running on Assura extracted netlist, will replace all '.' in net names with '/'");
180
} else if (line.matches("\\*|PROGRAM .*?Star-RCXT.*")) {
181
starRCXTNetlist = true;
182
System.out.println("Info: Running on Star-RCXT extracted netlist, will replace all '.x' in net names with '/'");
186
} catch (IOException e) {
187
System.out.println(e.getMessage());
191
// max sim time (-t) is 90071s
192
String cmd = command+" -n "+simFile+" -i -t 90071s -o "+simFile;
193
if (!startProcess(cmd, null, null, simFile+".run"))
197
vdd = getNodeVoltage("vdd");
199
System.out.println("Using VDD of "+vdd);
200
timeStep = getSimTres();
202
System.out.println("Using time step of "+timeStep+" ns");
204
// initialize test devices
205
for (Iterator it = logicSettables.iterator(); it.hasNext(); ) {
206
NanosimLogicSettable ls = (NanosimLogicSettable)it.next();
208
System.out.println("LogicSettable initialization failed, aborting.");
212
for (Iterator it = jtagTesters.iterator(); it.hasNext(); ) {
213
JtagTester tester = (JtagTester)it.next();
220
* Get the voltage of VDD for the simulation. The simulation must have been
221
* started for this method to return a valid value.
222
* @return the VDD voltage, in volts.
224
public double getVdd() { return vdd; }
226
protected static final Pattern patSimTime = Pattern.compile("The simulation time is\\s+: ([0-9\\.]+) ns");
228
public void wait(float seconds) {
229
waitNS(seconds*1.0e9);
233
* Wait the specified number of nano-seconds. In this case, this means
234
* run the simulator until that point in time, when control will return
235
* to the test software.
236
* @param nanoseconds the time to wait (simulate) in nanoseconds
238
public void waitNS(double nanoseconds) {
239
waitNS(nanoseconds, true);
242
// internal only method; applyVoltages calls this with the boolean false so no infinite recursion
243
protected void waitNS(double nanoseconds, boolean applyVoltages) {
245
issueCommand("get_sim_time");
246
StringBuffer buf = getLastCommandOutput();
247
Matcher m = patSimTime.matcher(buf.toString());
251
cur_time = Double.parseDouble(m.group(1));
252
} catch (NumberFormatException e) {
253
System.out.println("Error in get_sim_time, could not parse time "+m.group(1)+" from:\n"+buf);
257
System.out.println("Error determining current time, get_sim_time returned: "+buf);
261
// first apply any voltages that have been set
265
if (nanoseconds < timeStep) {
266
System.out.println("Warning: cannot run simulator in increments less than time step (currently "+timeStep+" ns), setting it to "+timeStep+" ns");
267
nanoseconds = timeStep;
269
// round wait time to the nearest time step, otherwise nanosim gets confused
270
nanoseconds = (int)(nanoseconds/timeStep) * timeStep;
272
// calculate stop time (time at which to set breakpoint)
273
double stopTime = simTime + nanoseconds;
275
issueCommand("set_time_break "+stopTime+"ns");
276
issueCommand("cont_sim");
280
public void waitPS(double ps) {
284
public double getTimeNS() {
287
issueCommand("get_sim_time");
288
StringBuffer buf = getLastCommandOutput();
289
Matcher m = patSimTime.matcher(buf.toString());
293
cur_time = Double.parseDouble(m.group(1));
294
} catch (NumberFormatException e) {
295
System.out.println("Error in get_sim_time, could not parse time "+m.group(1)+" from:\n"+buf);
299
System.out.println("Error determining current time, get_sim_time returned: "+buf);
306
protected static final Pattern getSimTime_tres = Pattern.compile("The engine time resolution is\\s+: ([0-9\\.]+) ns");
308
* Get the simulation's time step
309
* @return the simulation time step in nanoseconds
311
protected double getSimTres() {
312
issueCommand("get_sim_time");
313
StringBuffer buf = getLastCommandOutput();
314
Matcher m = getSimTime_tres.matcher(buf);
317
double d = Double.parseDouble(m.group(1));
319
} catch (NumberFormatException e) {
320
System.out.println("Error converting string to double in "+m.group(0)+": "+e.getMessage());
323
double d = 0.01; // default is 10ps
324
System.out.println("Cannot determine time step, using default of "+d+" ns");
328
// ====================================================================
329
// ====================================================================
333
// ====================================================================
334
// ====================================================================
337
* Force node to a state. Note that 1 is high and 0 is low.
339
* case-insensitive, and may be a hierarchical spice name, such as 'Xtop.Xfoo.net@12'.
340
* It should match the name from the spice file that nanosim is simulating.
341
* @param node the hierarchical spice node name
342
* @param state the state to set to, must be 1 or 0.
344
public void setNodeState(String node, int state) {
345
node = node.toLowerCase();
346
if (state != 0 && state != 1) {
347
System.out.println("Illegal state passed to setNodeState: "+state+". Expected 0 or 1.");
350
setNodeVoltage(node, state*vdd);
354
* Set a node in the nanosim simulation to the specified voltage.
356
* case-insensitive, and may be a hierarchical spice name, such as 'Xtop.Xfoo.net@12'.
357
* It should match the name from the spice file that nanosim is simulating.
358
* @param node the hierarchical spice node name
359
* @param voltage the voltage to set the node to
361
public void setNodeVoltage(String node, double voltage) {
362
node = node.toLowerCase();
363
//issueCommand("set_node_v "+node+" "+voltage+" r=5 l=1n");
364
nodesToSet.put(node, new Double(voltage));
368
* This is used to apply all voltages at the same time for the current time step.
370
protected void applyVoltages() {
371
// release all forced nodes
372
releaseNodes(new ArrayList(nodesToSet.keySet()));
374
// all nodes are released, now apply all the values
375
for (Iterator it = nodesToSet.entrySet().iterator(); it.hasNext(); ) {
376
Map.Entry entry = (Map.Entry)it.next();
377
String node = (String)entry.getKey();
378
Double voltage = (Double)entry.getValue();
379
if (assuraRCXNetlist) {
380
node = node.replaceAll("\\.", "/");
381
} else if (starRCXTNetlist) {
382
if (node.startsWith("x")) node = node.substring(1);
383
node = node.replaceAll("\\.x?", "/");
385
issueCommand("force_node_v v="+voltage.doubleValue()+" no="+node);
388
waitNS(timeStep, false);
391
// release the list of nodes (Strings)
392
public void releaseNodes(List nodes) {
394
// Ajanta and I have found that release does not always work,
395
// and sometimes the node remains "forced". Issuing another
396
// release seems to remove the forced state, though, so the
397
// following code issues releases until it is released
398
// (or stops after 10 tries)
400
int nodesReleased = 0;
401
while (nodesReleased < nodes.size() && i<10) {
402
// make sure all nodes to set are not forced
404
boolean releasedIssued = false;
405
for (Iterator it = nodes.iterator(); it.hasNext(); ) {
406
String node = (String)it.next();
407
if (assuraRCXNetlist) {
408
node = node.replaceAll("\\.", "/");
409
} else if (starRCXTNetlist) {
410
if (node.startsWith("x")) node = node.substring(1);
411
node = node.replaceAll("\\.x?", "/");
413
issueCommand("get_node_info detail=on "+node);
414
StringBuffer output = getLastCommandOutput();
415
if (output.indexOf("IS_FORCED: 1") != -1) {
416
// we need to release node
417
issueCommand("rel_node_v no="+node);
418
releasedIssued = true;
420
nodesReleased++; // this node is already released
423
if (releasedIssued) {
424
// advance time to try apply release
425
waitNS(timeStep, false);
431
List getNodeVoltages(List nodes) {
432
return getNodeInfo(nodes, false);
435
List getNodeStates(List nodes) {
436
return getNodeInfo(nodes, true);
440
* Get the state of a node. Returns 1 or 0.
442
* case-insensitive, and may be a hierarchical spice name, such as 'Xtop.Xfoo.net@12'.
443
* It should match the name from the spice file that nanosim is simulating.
444
* May return -1 if not a valid state.
445
* @param node the hierarchical spice node name
447
public int getNodeState(String node) {
448
List list = new ArrayList();
450
List vals = getNodeInfo(list, true);
451
if (vals != null && vals.size() > 0)
452
return ((Number)vals.get(0)).intValue();
457
* Get the voltage on a node.
459
* case-insensitive, and may be a hierarchical spice name, such as 'Xtop.Xfoo.net@12'.
460
* It should match the name from the spice file that nanosim is simulating.
461
* @param node the hierarchical spice node name
462
* @return the voltage, or -1 if error
464
public double getNodeVoltage(String node) {
465
List list = new ArrayList();
467
List vals = getNodeInfo(list, false);
468
if (vals != null && vals.size() > 0)
469
return ((Double)vals.get(0)).doubleValue();
473
protected static final Pattern patNodeInfo = Pattern.compile("Node status of (.*?)\\((\\d+)\\): (.*?) \\(([0-9\\.\\-]+) V\\)");
475
protected static final Pattern patNodeInfo2 = Pattern.compile("Node status of (.*?)\\((\\d+)\\): (\\d+)");
478
* Gets the voltages on the nodes, unless returnState is true, in
479
* which case it returns a list of 1's and 0's representing the logic state,
480
* rather than the actual voltages. Also returns -2 for undefined logic state, or -1 on error.
481
* @param nodes the nodes to query
482
* @param returnState true to convert voltages to 1 or 0 logic states
483
* @return a list of voltages/states, or null on error
485
protected List getNodeInfo(List nodes, boolean returnState) {
486
// apply any outstanding voltages
487
if (nodesToSet.size() > 0)
489
if (assuraRCXNetlist || starRCXTNetlist) {
490
List nodesfixed = new ArrayList();
491
for (Iterator it = nodes.iterator(); it.hasNext(); ) {
492
String node = (String)it.next();
493
if (assuraRCXNetlist) {
494
node = node.replaceAll("\\.", "/");
495
} else if (starRCXTNetlist) {
496
if (node.startsWith("x")) node = node.substring(1);
497
node = node.replaceAll("\\.x?", "/");
499
nodesfixed.add(node);
505
List nodeslc = new ArrayList();
506
StringBuffer cmd = new StringBuffer();
507
cmd.append("get_node_info ");
508
for (Iterator it = nodes.iterator(); it.hasNext(); ) {
509
String node = (String)it.next();
510
node = node.toLowerCase();
512
cmd.append(node+" ");
516
issueCommand(cmd.toString());
517
StringBuffer result = getLastCommandOutput();
518
String [] results = result.toString().trim().split("\n");
520
List voltages = new ArrayList();
521
List states = new ArrayList();
523
for (int i=0; i<results.length; i++) {
524
if (!results[i].startsWith("Node status")) continue; // quick check
525
Matcher m = patNodeInfo.matcher(results[i]);
526
Matcher m2 = patNodeInfo2.matcher(results[i]);
527
String node = (String)nodes.get(nodeIndex);
529
// don't do this check anymore, as nanosim can map the hierarchical name to the real name
530
//if (!m.group(1).equals(node)) {
531
// System.out.println("Error on get_info_node: expected info for node "+node+" but got info for node "+m.group(1));
535
// state can be one of 1, 0, or U
536
if (m.group(3).equals("1"))
537
state = new Integer(1);
538
else if (m.group(3).equals("0"))
539
state = new Integer(0);
540
else if (m.group(3).equals("U"))
541
state = new Integer(-2);
543
System.out.println("Uknown state of "+node+": "+m.group(3)+", setting it to -1 (Undefined)");
544
state = new Integer(-1);
548
voltage = new Double(m.group(4));
549
} catch (NumberFormatException e) {
550
System.out.println("Error on get_info_node: NumberFormatException converting node "+node+" state/voltage ("+m.group(3)+"/"+m.group(4)+") to integer/double");
554
voltages.add(voltage);
557
if (DEBUG) System.out.println("get_info_node "+node+": \tstate="+state+"\tvoltage="+voltage);
558
} else if (m2.find() && returnState) {
560
if (!m2.group(1).equals(node)) {
561
System.out.println("Error on get_info_node: expected info for node "+node+" but got info for node "+m.group(1));
565
// state can be one of 1, 0, or U
566
if (m2.group(3).equals("1"))
567
state = new Integer(1);
568
else if (m2.group(3).equals("0"))
569
state = new Integer(0);
570
else if (m2.group(3).equals("U"))
571
state = new Integer(-2);
573
System.out.println("Uknown state of "+node+": "+m2.group(3)+", setting it to -1 (Undefined)");
574
state = new Integer(-1);
578
if (DEBUG) System.out.println("get_info_node "+node+": \tstate="+state);
581
if (returnState) return states;
586
* Saves the state of all nodes at the given time to an external .ic file,
587
* using the report_node_ic command.
588
* @param time time in nanoseconds
590
public void reportNodeIC(double time) {
591
issueCommand("report_node_ic all "+time+"ns");
595
* Saves the state of all nodes at the current time to an external .ic file,
596
* using the report_node_ic command.
598
public void reportNodeIC() {
599
issueCommand("report_node_ic all");
603
* This test requires the file sim.spi in your working dir
605
public static void main(String[] args) {
606
NanosimModel nm = new NanosimModel();
607
// the example file sim.spi needs to be in your working dir
608
nm.start("nanosim", "sim.spi", 0);
609
nm.issueCommand("get_sim_time");