/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: SamplerControl.java
* Written by Tom O'Neill, Sun Microsystems.
*
* Copyright (c) 2005, 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.test;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
/**
* Main API for sampler programming and calibration. The code assumes that a
* node controls a sampler if and only if it satisfies the following conditions:
* <ul>
* <li>It is an instance of <code>SubchainNode</code> (e.g, it is a
* <code>ChainNode</code>)</li>
* <li>The node includes a <tt>pin</tt> attribute</li>
* <li>The node contains one each of <tt>calibrate</tt>,<tt>enable</tt>,
* and <tt>enable_f</tt>
* <code>Subchain</code> nodes. (Other nodes are
* allowed as well.)</li>
* <li>The <tt>calibrate</tt>,<tt>enable</tt>, and <tt>enable_f</tt>
* nodes each contain a single scan chain element.
* </ul>
* If the pin attribute cannot be set in the XML file, it may be set using
* <code>ChainControl.setSubchainPin()</code>.
*/
public class SamplerControl extends Logger {
/** Object containing scan chain model/APIs */
ChainControl control;
/**
* Specifies whether chain control elements must be set <tt>HI</tt> to
* enable the corresponding on-chip signal.
*/
private final int polarity;
/** Mapping from scan chain paths to pin names */
public final Map map;
/**
* For each sampler control node, the value of the scan chain element
* required to enable the control setting
*/
private final String[] controlEnable = new String[CONTROL_NODES.length];
/**
* For each sampler control node, the value of the scan chain element
* required to disable the control setting
*/
private final String[] controlDisable = new String[CONTROL_NODES.length];
/** Name of calibrate sampler control node */
public final static String[] CONTROL_NODES = { "calibrate", "enable",
"enable_f" };
/** index of calibrate control node */
public final static int IND_CALIBRATE = 0;
public final static int IND_ENABLE = 1;
public final static int IND_ENABLE_F = 2;
/**
* <code>polarity</code> value when calibrate, enable, enable_f scan chain
* elements are set <tt>HI</tt> to set these signals true on chip.
*/
public final static int POLARITY_NORMAL = 0;
/**
* <code>polarity</code> value when calibrate, enable, enable_f scan chain
* elements are set <tt>LO</tt> to set these signals true on chip.
*/
public final static int POLARITY_INVERTED = 1;
/**
* Scan chain value required to enable a sampler control signal, depends on
* value of polarity.
*/
private final static String[] CONTROL_ENABLE = { "1", "0" };
/**
* Scan chain value required to disable a sampler control signal, depends on
* value of polarity.
*/
private final static String[] CONTROL_DISABLE = { "0", "1" };
/**
* Constructor. Identifies samplers in <code>control</code> using the
* conditions described at top. For each sampler, sets <code>inBits</code>
* necessary to disable it. Does not shift any data, since the rest of the
* chip state may not be specified.
* <p>
* Currently <code>polarity</code> value may be
* <code>POLARITY_NORMAL</code> or <code>POLARITY_INVERTED</code>.
*
* @param control
* Object containing scan chain model/APIs
* @param polarity
* whether sampler control signals come from non-inverting scan
* chain output
*/
public SamplerControl(ChainControl control, int polarity) {
super();
this.control = control;
if (polarity != POLARITY_NORMAL && polarity != POLARITY_INVERTED) {
Infrastructure.fatal("Bad polarity value " + polarity
+ ", only POLARITY_NORMAL and POLARITY_INVERTED are "
+ " supported");
}
this.polarity = polarity;
this.map = new java.util.HashMap();
// Fill controlEnable array according to polarity
java.util.Arrays.fill(controlEnable, CONTROL_ENABLE[polarity]);
java.util.Arrays.fill(controlDisable, CONTROL_DISABLE[polarity]);
// Get all nodes in the experimental system
String[] paths = control.getDescendents("");
for (int ind = 0; ind < paths.length; ind++) {
if (isSampler(paths[ind])) {
map.put(paths[ind], control.getSubchainPin(paths[ind]));
preclear(paths[ind]);
}
}
}
/**
* Prints some information about the sampler object, including which
* samplers are on each pin.
*/
public String toString() {
StringBuffer buffy = new StringBuffer("SamplerControl, control="
+ control);
buffy.append("\n Samplers on each pin:");
// Convert Collection of values to TreeSet for unique + ordered
java.util.Set pins = new java.util.TreeSet(map.values());
// For each pin, add which samplers are on it
for (java.util.Iterator iter = pins.iterator(); iter.hasNext();) {
String pin = (String) iter.next();
buffy.append("\n " + pin + ": ");
String[] samplers = getSamplersOnPin(pin);
for (int ind = 0; ind < samplers.length; ind++) {
buffy.append(" " + samplers[ind]);
}
}
buffy.append("\n");
return buffy.toString();
}
/**
* Checks if path to sampler scan chain node has correct format and
* identifies an actual sampler.
*
* @param path
* Path to the scan chain node for the sampler
*/
void checkPath(String path) {
if (map.containsKey(path) == false) {
Infrastructure.fatal("Path " + path + " is not a recognized "
+ "sampler" + "\nSee SamplerControl javadoc for how to "
+ "identify sampler nodes");
}
}
/**
* Disable the sampler at the specified <code>SubchainNode</code> by
* setting the <tt>calibrate</tt>,<tt>enable</tt>, and
* <tt>enable_f</tt> scan chain elements according to the sampler
* polarity.
*
* @param path
* Path to the scan chain node for the sampler
*/
public void clear(String path) {
preclear(path);
logSet("SamplerControl.clear(): clearing " + path);
control.shift(control.getParentChain(path), false, true);
}
/**
* Set the <code>inBits</code> values to disable the sampler at the
* specified <code>SubchainNode</code>, but do not shift the data into
* the chip. The <tt>calibrate</tt>,<tt>enable</tt>, and
* <tt>enable_f</tt> scan chain elements are set according to the sampler
* polarity.
*
* @param path
* Path to the subchain node for the sampler
*/
private void preclear(String path) {
checkPath(path);
for (int ind = 0; ind < CONTROL_NODES.length; ind++) {
control.setInBits(path + "." + CONTROL_NODES[ind],
controlDisable[ind]);
}
}
/**
* Enable the sampler at the specified <code>SubchainNode</code> by
* setting the <tt>enable</tt> and <tt>enable_f</tt> scan chain elements
* according to the sampler polarity. Disables the <tt>calibrate</tt> scan
* chain element.
* <p>
* If <code>enable</code> or <code>enable_f</code> is <tt>true</tt>,
* all samplers on the same output pin are disabled before setting the
* requested sampler. This is to prevent interference with the measurement.
*
* @param path
* Path to the scan chain node for the sampler
* @param enable
* Whether to enable the standard version of the sampler
* @param enable_f
* Whether to enable the source-follower version of the sampler
*/
public void setEnables(String path, boolean enable, boolean enable_f) {
checkPath(path);
if (enable || enable_f) {
clearSiblings(path);
}
setOne(path, false, enable, enable_f);
}
/**
* Enable or disable calibration for the sampler at the specified
* <code>SubchainNode</code> by setting the <tt>calibrate</tt> scan
* chain element according to the sampler polarity.
*
* @param path
* Path to the scan chain node for the sampler
* @param calibrate
* Whether to configure the sampler for calibration
*/
public void setCalibrate(String path, boolean calibrate) {
checkPath(path);
setControl(path, IND_CALIBRATE, calibrate);
logSet("SamplerControl.setCalibrate(): setting " + path
+ " to calibrate");
control.shift(control.getParentChain(path), false, true);
}
/**
* Clears all samplers on same pin as specified sampler.
*
* @param path
* Path to the scan chain node for the sampler
*/
private void clearSiblings(String path) {
String targetPin = (String) map.get(path);
String[] paths = getSamplersOnPin(targetPin);
for (int ind = 0; ind < paths.length; ind++) {
clear(paths[ind]);
}
}
/**
* Calibrates the specified sampler, writing the current versus voltage to
* the provided file. Assumes that <code>setEnables()</code> has been used
* to set at least one of <code>enable</code> and <code>enable_f</code>.
*
* @param fileName
* File to write the calibration data to
* @param path
* Path to the scan chain node for the sampler
* @param ivspec
* Object specifying the IV curve to measure
* @throws IOException
*/
public void calibrate(String fileName, String path, AmpsVsVolts ivspec)
throws IOException {
PrintWriter file = new PrintWriter(new FileWriter(fileName));
file.println("# calibration (voltage, current) for sampler at path "
+ path);
setCalibrate(path, true);
ivspec.measure(file);
setCalibrate(path, false);
file.close();
}
/**
* Returns <tt>true</tt> if the node at the specified path controls a
* sampler. See comments at top for the necessary conditions.
*
* @param path
* path name to potential sampler control
* @return whether specified node controls a sampler
*/
private boolean isSampler(String path) {
TestNode node = (TestNode) control.findNode(path);
if (node.getChildCount() < 3 || (node instanceof SubchainNode == false))
return false;
int[] numInstances = getNumInstances(node);
boolean oneOfEach = true, anyPresent = false;
for (int ind = 0; ind < CONTROL_NODES.length; ind++) {
if (numInstances[ind] != 1)
oneOfEach = false;
if (numInstances[ind] > 0)
anyPresent = true;
}
if (oneOfEach) {
if (control.getSubchainPin(path).length() <= 0) {
System.err.println("*** SamplerControl warning: node " + path
+ "\nappears to be a sampler, but does not have"
+ " a valid pin name. Please set the "
+ "\n'pin' attribute in the XML file or use"
+ " ChainControl.setSubchainPin()");
return false;
}
return true;
}
if (anyPresent) {
System.err.println("*** SamplerControl warning: node " + path
+ "\nmay be a sampler that does not contain "
+ "required nodes."
+ "\nSamplers must contain exactly one each of '"
+ CONTROL_NODES[0] + "', '" + CONTROL_NODES[1] + "', and '"
+ CONTROL_NODES[2] + "'");
return false;
}
return false;
}
/**
* Return path strings of all samplers on specified pin
*
* @param targetPin
* name of sampler current output pin
* @return path strings of all samplers on <code>targetPin</code>
*/
public String[] getSamplersOnPin(String targetPin) {
java.util.List list = new java.util.ArrayList();
for (java.util.Iterator iter = map.keySet().iterator(); iter.hasNext();) {
String path = (String) iter.next();
String pin = (String) map.get(path);
if (pin.equals(targetPin)) {
list.add(path);
}
}
String[] paths = new String[list.size()];
for (int ind = 0; ind < paths.length; ind++) {
paths[ind] = (String) list.get(ind);
}
return paths;
}
/**
* Enable or disable the specified sampler control
*
* @param path
* Path to sampler
* @param ind
* Index of control in CONTROL_NODES array
* @param enable
* Whether to enable the control
*/
private void setControl(String path, int ind, boolean enable) {
if (enable) {
control.setInBits(path + "." + CONTROL_NODES[ind],
controlEnable[ind]);
} else {
control.setInBits(path + "." + CONTROL_NODES[ind],
controlDisable[ind]);
}
}
/**
* Enable the sampler at the specified <code>SubchainNode</code> by
* setting the <tt>calibrate</tt>,<tt>enable</tt>, and
* <tt>enable_f</tt> scan chain elements according to the sampler
* polarity. Does not affect any other samplers.
*
* @param path
* Path to the scan chain node for the sampler
* @param calibrate
* Whether to configure the sampler for calibration
* @param enable
* Whether to enable the standard version of the sampler
* @param enable_f
* Whether to enable the source-follower version of the sampler
*/
private void setOne(String path, boolean calibrate, boolean enable,
boolean enable_f) {
checkPath(path);
if (calibrate && !enable && !enable_f) {
System.out.println("WARNING: Odd setting for sampler at " + path
+ ": calibrate true, but enable and enable_f false.");
}
setControl(path, IND_CALIBRATE, calibrate);
setControl(path, IND_ENABLE, enable);
setControl(path, IND_ENABLE_F, enable_f);
logSet("SamplerControl.setOne(): setting " + path);
control.shift(control.getParentChain(path), false, true);
}
/**
* Count number of children that are named after each of the required nodes
*
* @param node
* @return number of children that have each of the required names
*/
private int[] getNumInstances(TestNode node) {
int numInstances[] = new int[CONTROL_NODES.length];
for (int kidIndex = 0; kidIndex < node.getChildCount(); kidIndex++) {
TestNode kid = (TestNode) node.getChildAt(kidIndex);
String kidName = kid.getName();
for (int ind = 0; ind < CONTROL_NODES.length; ind++) {
if (kidName.equals(CONTROL_NODES[ind])) {
String kidPath = kid.getPathString(1);
int length = control.getLength(kidPath);
if (length == 1) {
numInstances[ind] += 1;
} else {
System.err.println("*** SamplerControl warning: node "
+ kidPath + " has length " + length
+ ", should have length 1");
}
}
}
}
return numInstances;
}
/** Unit test */
public static void main(String[] args) {
ChainControl control = new ChainControl("heater.xml");
control.setSubchainPin("heater.SW_expC.transmit.sample_cT", "frog");
control.setSubchainPin("heater.NW_expC.transmit.sample_cT", "frog");
control.setSubchainPin("heater.SE_expC.transmit.sample_cT", "toad");
control.setSubchainPin("heater.NE_expC.transmit.sample_cT", "bar");
SamplerControl samplers = new SamplerControl(control, POLARITY_INVERTED);
}
}