/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: SubchainNode.java
* Written by Eric Kim and Tom O'Neill, Sun Microsystems.
*
* Copyright (c) 2004, 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.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Represent a single node of a scan chain. This is a subset of a scan chain,
* chosen according to a hierarchy imposed in software. The division of the scan
* chain into subchains is for convenience in accessing specific scan chain
* elements, and does not have a direct functional significance with respect to
* the chip's scan chain.
* <p>
* By convention, the first bit in a BitVector or in a string always represents
* the last bit scanned into or out of the chip. Thus 1) the bit and character
* indices match the position of the corresponding scan chain element along the
* s_in chain, 2) the strings match the left-to-right order in which scan chain
* elements appear in most schematics, and 3) the order is consistent with the
* order of scan chain nodes in the XML file.
*/
public class SubchainNode extends TestNode {
/**
* Number of scan chain elements in or below this node. Includes
* contributions from all scan chain nodes underneath the current one.
*/
private int length;
/**
* Optional: name of I/O pad associated with this node. Currently used by
* {@link SamplerControl} to provide non-conflicting access to sampler
* output pins.
*/
public String pin;
/**
* Optional: name of data out wire or bus. This is the wire that the scan
* data is applied to on "write". For simulation purposes, the scan chain
* can be bypassed, and scan values can be applied directly to the data
* out bits.
*/
private DataNet dataNet;
private DataNet dataNet2;
/**
* Default constructor.
*
* @param name
* name identifying the node
* @param length
* number of scan chain elements in node
* @param comment
* comment attached to this node, if any
*/
public SubchainNode(String name, int length, String comment) {
super(name, comment);
setLength(length);
pin = null;
}
/**
* Default constructor.
*
* @param name
* name identifying the node
* @param length
* number of scan chain elements in node
* @param pin
* name of I/O pad associated with this node
* @param comment
* comment attached to this node, if any
* @param dataNet
* net (may be bus) name that data is written and read to.
* May contains options (RWI). ex: net1(RW).
* @param dataNet2
* net (may be bus) name that data is written and read to.
* May contains options (RWI). ex: net1(RW).
*/
public SubchainNode(String name, int length, String pin, String comment,
String dataNet, String dataNet2) {
super(name, comment);
setLength(length);
this.pin = pin;
if (dataNet == null) dataNet = "";
if (dataNet2 == null) dataNet2 = "";
this.dataNet = new DataNet(dataNet);
this.dataNet2 = new DataNet(dataNet2);
}
public String toString() {
return super.toString() + " (len=" + getLength() + ")";
}
/** Return number of scan chain elements in or below this node */
protected void setLength(int length) {
this.length = length;
}
/** Return number of scan chain elements in or below this node */
int getLength() {
return length;
}
public DataNet getDataNet() { return dataNet; }
public DataNet getDataNet2() { return dataNet2; }
/**
* Override addChild method: update length so that it includes the scan
* chain elements in the new child.
*/
void addChild(MyTreeNode newNode) {
super.addChild(newNode);
lengthChanged();
}
/**
* Called when the length of the current node changes, recomputes all of the
* affected lengths up to the scan chain root
*/
void lengthChanged() {
// Recompute current node's length, taking children into account
this.computeLength();
// If appropriate, (recursively) update the length of the parent
if (getParent() == null || getParent().getClass() == ChipNode.class) {
return;
}
((SubchainNode) getParent()).lengthChanged();
}
/**
* Return a copy of the scan chain bit pattern that will be written to
* current node on chip after the next call to {@link ChainNode#shift}
* for this chain. The first element of the bit vector represents the
* scan chain element that is scanned in last.
*
* @return Bit vector with pending bit pattern for current node
*/
BitVector getInBits() {
ChainNode root = getParentChain();
BitVector bitVector = root.getInBits().get(getBitIndex(), getLength());
return bitVector;
}
/**
* Return a copy of the scan chain bit pattern that was read from current
* node on chip after the last call to {@link ChainNode#shift} for
* this chain. The first element of the bit vector represents the scan chain
* element that is scanned out last.
*
* @return Bit vector with previous bit pattern for current node
*/
BitVector getOutBits() {
ChainNode root = getParentChain();
return root.getOutBits().get(getBitIndex(), getLength());
}
/**
* Return a copy of the scan chain bit pattern that was expected to be
* shifted out of the current node during the last call to
* {@link ChainNode#shift} for the parent chain. Often this is just
* the previous value of <code>inBits</code> from the second-to last call
* to shift(), but it can be modified by processMasterClear() and
* read-enabled shifts. The first element of the bit vector represents the
* scan chain element that would be scanned out last.
* <p>
* Note {@link ChainNode#oldOutBitsExpected}is more useful for debugging a
* scan chain than {@link ChainNode#outBitsExpected}, because in general
* does not generally correspond to what was used in the consistency
* checking.
*
* @return Bit vector with expected bit pattern for current node
*/
BitVector getOldOutBitsExpected() {
ChainNode root = getParentChain();
return root.getOldOutBitsExpected().getIndiscriminate(getBitIndex(),
getLength());
}
/**
* Set scan chain bit pattern that will be written to current node on chip
* after the next call to {@link ChainNode#shift} for this chain. The
* first element of the bit vector represents the scan chain element that is
* scanned in last.
*
* @param newBits
* Bit array containing new settings
*/
void setInBits(BitVector newBits) {
int nbits = newBits.getNumBits();
int nbitsNode = this.getLength();
if (nbits != nbitsNode) {
Infrastructure.fatal("Length of input BitVector " + newBits
+ " is " + nbits + ", but it must equal length "
+ nbitsNode + " of SubchainNode " + this);
}
ChainNode chainRoot = getParentChain();
int fromIndex = this.getBitIndex();
chainRoot.getInBits().put(fromIndex, newBits);
}
/**
* Set scan chain bit pattern that will be written to current node on chip
* after the next call to {@link ChainNode#shift} for this chain. The
* first character in the string represents the scan chain element that is
* scanned in last.
*
* @param newBits
* Character string containing new settings (e.g., "111001")
*/
void setInBits(String newBits) {
int nbits = newBits.length();
int nbitsNode = this.getLength();
if (nbits != nbitsNode) {
Infrastructure.fatal("Length of input BitVector " + newBits
+ " is " + nbits + ", but it must equal length "
+ nbitsNode + " of SubchainNode " + this);
}
ChainNode chainRoot = getParentChain();
int fromIndex = this.getBitIndex();
chainRoot.getInBits().put(fromIndex, newBits);
}
/**
* Recompute the length of the current node, by adding up the contributions
* from all of its children
*/
protected void computeLength() {
int childCount = getChildCount();
int newLength;
if (childCount > 0) {
newLength = 0;
for (int ind = 0; ind < childCount; ind++) {
newLength += ((SubchainNode) getChildAt(ind)).getLength();
}
setLength(newLength);
}
}
/**
* This is only used for ChainG display
* @return the outbits
*/
protected BitVector getOutBitsIndiscriminate() {
ChainNode root = getParentChain();
return root.getOutBits().getIndiscriminate(getBitIndex(), getLength());
}
/**
* This is only used for ChainG display
* @return the inbits
*/
protected BitVector getInBitsIndiscriminate() {
ChainNode root = getParentChain();
return root.getInBits().getIndiscriminate(getBitIndex(), getLength());
}
/**
* Return index along the scan chain of the first element of the node. The
* address is computed as the address of the parent plus the siblings before
* the node in the MyTreeNode hierarchy.
*
* @return absolute address of the node wrt the chain root
*/
public int getBitIndex() {
if (getParent() == null || getParent().getClass() == ChipNode.class || getParent().getClass() == TestNode.class) {
return 0;
} //chainRoot
int sumSibling = 0;
for (int iChild = 0; iChild < getParent().getIndex(this); iChild++) {
sumSibling += ((SubchainNode) getParent().getChildAt(iChild))
.getLength();
}
int addr = ((SubchainNode) getParent()).getBitIndex() + sumSibling;
return addr;
}
/** Return the chainRoot node that this node is a descendent of */
public ChainNode getParentChain() {
MyTreeNode node;
for (node = this; !ChainNode.class.isInstance(node); node = node
.getParent())
;
return (ChainNode) node;
}
/**
* Return path from chainRoot to this node. Suppresses the name of the
* system (root) node, since it is always the same. I.e., path starts at the
* chip level.
*/
public String getPathString() {
return getPathString(1);
}
// =======================================================================
public static class DataNet {
private final String name; // full path name of the net
private final boolean readable; // if scan chain can read from this net
private final boolean writeable; // if scan chain can write to this net
private final boolean inverted; // if sense of data is inverted
private static final Pattern namePat = Pattern.compile("(.+?)\\((.+?)\\)");
protected DataNet(String xmlNetName) {
Matcher m = namePat.matcher(xmlNetName);
String netname;
if (m.matches()) {
netname = m.group(1);
String options = m.group(2).toLowerCase();
readable = (options.indexOf('r') != -1) ? true : false;
writeable = (options.indexOf('w') != -1) ? true : false;
inverted = (options.indexOf('i') != -1) ? true : false;
} else {
netname = xmlNetName;
readable = false;
writeable = false;
inverted = false;
}
name = netname;
}
protected DataNet(String netName, boolean readable, boolean writeable, boolean inverted) {
this.name = netName;
this.readable = readable;
this.writeable = writeable;
this.inverted = inverted;
}
public String getName() { return name; }
public boolean isReadable() { return readable; }
public boolean isWriteable() { return writeable; }
public boolean isInverted() { return inverted; }
public String toString() { return "DataNet "+name+"("+(readable?"R":"")+(writeable?"W":"")+
(inverted?"I":"")+")"; }
}
// =======================================================================
/**
* Unit test. Creates a scan chain hierarchy: level0 -> {level1a, level1b};
* level1b -> {level2a, level2b}. Uses it to test the setBits() and
* getBits() methods.
*/
public static void main(String[] args) {
ChainNode level0 = new ChainNode("level0", "001", 0, "");
SubchainNode level1a = new SubchainNode("level1a", 5, "frog");
SubchainNode level1b = new SubchainNode("level1b", 0, "frog");
SubchainNode level2a = new SubchainNode("level2a", 7, "frog");
SubchainNode level2b = new SubchainNode("level2b", 3, "frog");
level0.addChild(level1a);
level0.addChild(level1b);
level1b.addChild(level2a);
level1b.addChild(level2b);
String path = level2a.getPathString();
System.out.println("path string, starting at level 1: " + path);
System.out.println(" length = " + level2a.getLength());
level2a.setInBits("1000111");
System.out.println("Set bits in level2a = " + level2a.getInBits());
System.out.println("Full bit sequence in level0 = " + level0.getInBits());
}
}