1
package com.sun.electric.tool.simulation.test;
4
import java.util.ArrayList;
7
* Represents an entire scan chain, covering all of the scan chain elements at a
8
* single address on the chip's JTAG controller. Sometimes called a "root" scan
9
* chain, to emphasize distinction from a sub-chain. I/O to the chip occurs to
10
* the entire root scan chain, rather than to individual
11
* <code>SubchainNode</code>s.
14
* By convention, the first bit in a BitVector or in a string always represents
15
* the last bit scanned into or out of the chip. Thus 1) the bit and character
16
* indices match the position of the corresponding scan chain element along the
17
* s_in chain, 2) the strings match the left-to-right order in which scan chain
18
* elements appear in most schematics, and 3) the order is consistent with the
19
* order of scan chain nodes in the XML file.
24
* @author Tom O'Neill (toneill)
25
* @version 1.1 7/22/04
26
* Copyright (c) 2004,2005 by Sun Microsystems, Inc.
30
public class ChainNode extends SubchainNode {
33
* Little-endian character string (e.g., "101010") representation of the
34
* root scan chain's address at the JTAG controller. Bits 6 and 7 (the read
35
* and write enable) are ignored during I/O with the chip.
37
final private String opcode;
40
* Scan chain bit pattern to be shifted into the chip during the next call
43
protected BitVector inBits;
46
* Scan chain bit pattern read back from the chip after last call to
47
* this.shift(). Should only be modified by Netscan.
49
protected BitVector outBits;
52
* Expected value of outBits during the next call to this.shift(). Usually
53
* this is just the previous value of inBits, but it can be modified by
54
* Master Clears and reading from the chip.
56
protected BitVector outBitsExpected;
58
/** Expected value of outBits for the previous call to this.shift(). */
59
protected BitVector oldOutBitsExpected;
62
* State of the scan chain elements' shadow register, for those that have
65
protected BitVector shadowState;
67
/** Whether any data has been shifted to this scan chain */
68
private boolean initialized = false;
71
* A list of shift listeners
73
private List<ShiftListener> listeners;
77
* Constructor for a root scan chain.
82
* on-chip address of root scan chain
84
* number of scan chain elements in node
86
* comment attached to this node
88
public ChainNode(String name, String opcode, int newLength, String comment) {
89
super(name, newLength, comment);
92
listeners = new ArrayList<ShiftListener>();
97
public String toString() {
98
return super.toString() + " (op=" + opcode + ")";
102
* Little-endian character string (e.g., "101010") representation of the
103
* root scan chain's address at the JTAG controller. These are the low-order
104
* 6 bits of the instruction register needed to access the chain.
106
* @return Address of root scan chain (little endian)
113
* Set most recent bit sequence that was shifted out of the root scan chain
114
* during this.shift(). Should only be used by
115
* {@link NetscanGeneric#netScan_DR}.
117
void setOutBits(BitVector newOutBits) {
118
outBits.put(0, newOutBits);
122
* Get the scan chain bit pattern to be shifted into the chip during the next call
124
* @return the in bits
126
public BitVector getInBits() { return inBits; }
129
* Get the scan chain bit pattern read back from the chip after last call to
130
* this.shift(). Should only be modified by Netscan.
131
* @return the out bits
133
public BitVector getOutBits() { return outBits; }
136
* Get expected value of outBits during the next call to this.shift(). Usually
137
* this is just the previous value of inBits, but it can be modified by
138
* Master Clears and reading from the chip.
139
* @return the out bits expected
141
public BitVector getOutBitsExpected() { return outBitsExpected; }
144
* Get the expected value of outBits for the previous call to this.shift().
145
* @return the old out bits expected
147
public BitVector getOldOutBitsExpected() { return oldOutBitsExpected; }
150
* Get the state of the scan chain elements' shadow register, for those that have
152
* @return the shadow state bits
154
public BitVector getShadowState() { return shadowState; }
157
* This is for ChainG display
158
* @return the outbits
160
protected BitVector getOutBitsIndiscriminate() { return outBits; }
163
* Returns ancestor <code>ChipNode</code>.
165
* @return Chip node that is the ancestor to this <code>ChainNode</code>
167
ChipNode getParentChip() {
168
MyTreeNode node = this;
169
while (node.getClass() != ChipNode.class) {
170
node = node.getParent();
172
Infrastructure.fatal(node
173
+ " does not have a ChipNode as an ancestor");
176
return (ChipNode) node;
180
* Update shadowState data structure in response to a master clear. Call
181
* this on a transition of master clear to <tt>HI</tt> _or_ <tt>LO</tt>,
182
* or you may get false complaints about data shifted out not equalling
185
void processMasterClear() {
186
for (int ind = 0; ind < getLength(); ind++) {
187
SubchainNode node = findNodeAtIndex(ind);
188
if (node.usesShadow() || node.usesDualPortedShadow()) {
189
int clears = node.getClearBehavior();
191
// Note clearing has no effect on elements with CLEARS_NOT.
192
// Otherwise sets the shadow register to HI, LO, or to an
193
// unknown (invalid) state.
194
if (clears == TestNode.CLEARS_LO) {
195
shadowState.clear(ind);
196
} else if (clears == TestNode.CLEARS_HI) {
197
shadowState.set(ind);
198
} else if (clears == TestNode.CLEARS_UNKNOWN) {
199
shadowState.invalidate(ind);
206
* Resets all inBits to zero, or to clears state if clearable and specified to do so
207
* @param useMasterClearState true to reset to clears state if clearable.
209
public void resetInBits(boolean useMasterClearState) {
210
for (int i=0; i<getLength(); i++) {
211
SubchainNode node = findNodeAtIndex(i);
212
if (useMasterClearState && node.getClearBehavior() == TestNode.CLEARS_HI)
215
inBits.set(i, false);
220
* Invalidate expected scan chain element values for this scan chain. Call
221
* this after a period at a low voltage, or you may get false complaints
222
* about data shifted out not equalling expected results. Sets
223
* {@link ChainNode#initialized} to false to suppress "no bits being
224
* compared" warning on next shift.
227
outBitsExpected.invalidate();
232
* Shift data in this.inBits into the appropriate scan chain on the chip.
233
* The previous data on the chip is shifted out into this.outBits, which is
234
* then compared with expectation.
237
* JTAG tester object to perform shift with
239
* whether to set opcode's read-enable bit
241
* whether to set opcode's write-enable bit
242
* @param irBadSeverity
243
* action when bits scanned out of IR are wrong
244
* @param noTestSeverity
245
* action when no consistency check is possible
246
* @param errTestSeverity
247
* action when consistency check fails
249
* Object with logging properties to use
251
* @return true if the bits scanned out equal their expected values
252
* @see Infrastructure#SEVERITY_NOMESSAGE
253
* @see Infrastructure#SEVERITY_WARNING
254
* @see Infrastructure#SEVERITY_NONFATAL
255
* @see Infrastructure#SEVERITY_FATAL
257
boolean shift(JtagTester jtag, boolean readEnable, boolean writeEnable,
258
int irBadSeverity, int noTestSeverity, int errTestSeverity,
260
logger.logOther("------ " + getPathString() + ", R=" + readEnable
261
+ ", W=" + writeEnable);
263
jtag.shift(this, readEnable, writeEnable, irBadSeverity);
265
boolean noErrors = checkOutBits(readEnable, noTestSeverity,
268
// After shift, all elements should hold inBits
269
oldOutBitsExpected.putIndiscriminate(0, outBitsExpected);
270
outBitsExpected.put(0, inBits);
272
// Update the expected bits from any shadow registers
273
// Note: this implies that shadow registers are not modified by the chip
275
for (int ind = 0; ind < getLength(); ind++) {
276
SubchainNode node = findNodeAtIndex(ind);
277
if (node.isReadable() && (node.usesShadow() && !node.usesDualPortedShadow())) {
278
if (shadowState.isValid(ind)) {
279
boolean state = shadowState.get(ind);
280
outBitsExpected.set(ind, state);
285
// Update the shadowState of any elements that wrote to their
288
for (int ind = 0; ind < getLength(); ind++) {
289
SubchainNode node = findNodeAtIndex(ind);
290
if (node.isWriteable() && (node.usesShadow() || node.usesDualPortedShadow())) {
291
boolean state = inBits.get(ind);
292
shadowState.set(ind, state);
302
* Shift one bit of data in this.inBits into the appropriate scan chain on
303
* the chip. No consistency checking is performed on bit scanned out. This
304
* is provided only for measuring chain length in ChainTest, and should not
308
* JTAG tester object to perform shift with
310
* whether to set opcode's read-enable bit
312
* whether to set opcode's write-enable bit
313
* @param irBadSeverity
314
* action when bits scanned out of IR are wrong
316
* Object with logging properties to use
317
* @return the bit that got shifted out
319
* @see Infrastructure#SEVERITY_NOMESSAGE
320
* @see Infrastructure#SEVERITY_WARNING
321
* @see Infrastructure#SEVERITY_NONFATAL
322
* @see Infrastructure#SEVERITY_FATAL
324
boolean shiftOneBit(JtagTester jtag, boolean readEnable,
325
boolean writeEnable, int irBadSeverity, Logger logger) {
326
logger.logOther("***** " + getPathString() + ", inBits=" + inBits);
329
* Temporarily change chain length to 1. Note outBits could potentially
330
* be clobbered after each length change (currently it isn't), so safest
331
* to store intermediate outbit.
333
int length = getLength();
335
jtag.shift(this, readEnable, writeEnable, irBadSeverity);
336
boolean outbit = outBits.get(0);
340
* Since this is only needed during development of the scan chain XML
341
* file, it's not worth figuring out resulting state of chain
343
outBitsExpected.invalidate();
344
oldOutBitsExpected.invalidate();
345
shadowState.invalidate();
351
* Called when the length of a node underneath this root node changes,
352
* recomputes the root node's length. In addition, resizes the inBits and
353
* outBits arrays to account for the change. Previous array contents are
354
* overwritten with 0. Note method overrides that in parent.
356
void lengthChanged() {
358
// Recompute current node's length, taking children into account
359
this.computeLength();
365
* Find descendent of current <code>ChainNode</code> that contains the
366
* scan chain element at index bitIndex.
369
* index of scan chain element
370
* @return scan chain node containing the specified element.
372
SubchainNode findNodeAtIndex(int bitIndex) {
373
if (bitIndex < 0 || bitIndex > this.getLength()) {
374
throw new IllegalArgumentException("bitIndex " + bitIndex +
375
" not in allowed range 0.." + this.getLength());
377
SubchainNode node = this;
378
SubchainNode parent = null;
379
for (int indChild=0, nodeIndex = 0;; indChild++) {
380
// Find index in scan chain of next sibling node
381
int nextIndex = nodeIndex + node.getLength();
383
if (nextIndex <= bitIndex) {
384
// Target not within this node, accumlate length and try
386
nodeIndex = nextIndex;
388
// Within this node. If leaf node, we have found it. Else,
390
int nkids = node.getChildCount();
397
node = (SubchainNode) parent.getChildAt(indChild);
403
* Called by constructor or when length changed, replaces the BitVector
404
* members with new versions of the correct length.
406
protected void createBitVectors() {
407
int newLength = getLength();
411
inBits = new BitVector(newLength, getPathString() + ".inBits");
412
outBitsExpected = new BitVector(newLength, getPathString()
413
+ ".outBitsExpected");
414
oldOutBitsExpected = new BitVector(newLength, getPathString()
415
+ ".oldOutBitsExpected");
416
outBits = new BitVector(newLength, getPathString() + ".outBits");
417
shadowState = new BitVector(newLength, getPathString() + ".shadowState");
421
* Checks if the bits scanned out of the scan chain equal their expected
422
* values. Optionally prints a warning to stderr if deviations are found.
425
* whether readable chain elements read values in
426
* @param noTestSeverity
427
* action when no consistency check is possible
428
* @param errTestSeverity
429
* action when consistency check fails
430
* @return true if no deviations found
432
private boolean checkOutBits(boolean readEnable, int noTestSeverity,
433
int errTestSeverity) {
435
int length = getLength();
438
* All elements, except those that are unpredictable or have read a
439
* value from another part of the chip, should now have the value in the
442
for (int ind = 0; ind < length; ind++) {
443
SubchainNode node = findNodeAtIndex(ind);
444
if (node.isUnpredictable()) {
445
outBitsExpected.invalidate(ind);
446
} else if (readEnable && node.isReadable()) {
449
* Can only know read value of an element with a shadow register
450
* that is in a known state
452
if (node.usesShadow() && shadowState.isValid(ind)) {
453
outBitsExpected.set(ind, shadowState.get(ind));
455
outBitsExpected.invalidate(ind);
460
// If no bits being compared, optionally print warning message
461
if (outBitsExpected.isInvalid()) {
462
if (initialized || noTestSeverity == Infrastructure.SEVERITY_FATAL
463
|| noTestSeverity == Infrastructure.SEVERITY_NONFATAL) {
464
Infrastructure.error(noTestSeverity, getPathString()
465
+ ".shift() warning: no bits being compared, "
466
+ "see ${TEST_ROOT}/FAQ.html");
471
// Create a BitVector that has a bit set for every deviation
472
BitVector errors = new BitVector(length, "checkOutBits()-errors");
473
for (int iBit = 0; iBit < length; iBit++) {
474
if (outBitsExpected.isValid(iBit)
475
&& outBits.get(iBit) != outBitsExpected.get(iBit)) {
482
boolean noErrors = errors.isEmpty();
483
if (noErrors == false) {
484
Infrastructure.error(errTestSeverity, getPathString()
485
+ ".shift() error:\n expected: " + outBitsExpected
486
+ "\n outBits: " + outBits
487
+ "\nFor details, see the Appendix in 'Using the Test"
488
+ "\nSoftware Library' for details about this error.");
493
int findRun(int indStart) {
494
SubchainNode start = findNodeAtIndex(indStart);
495
int clears = start.getClearBehavior();
496
boolean read = start.isReadable();
497
boolean write = start.isWriteable();
498
boolean shadow = start.usesShadow();
499
boolean unpredictable = start.isUnpredictable();
502
for (ind = indStart; ind < getLength(); ind++) {
503
SubchainNode subchain = findNodeAtIndex(ind);
504
if (subchain.getClearBehavior() != clears
505
|| subchain.isReadable() != read
506
|| subchain.isWriteable() != write
507
|| subchain.usesShadow() != shadow
508
|| subchain.isUnpredictable() != unpredictable) {
516
/** Helper for CompareXML */
517
void compare(ChainNode that, String thisFile, String thatFile) {
518
// System.out.println("Differences for chain " + this);
519
super.compare(that, thisFile, thatFile);
520
int length = getLength();
521
if (that.getLength() != length) {
522
System.out.println("**** Chain " + thisFile + ":" + this
523
+ " has length " + length + ", but " + thatFile + ":"
524
+ that + " has " + that.getLength()
525
+ ". Aborting comparison");
526
Infrastructure.exit(1);
529
int thisIndex = 0, thatIndex = 0;
530
while (thisIndex < length && thatIndex < length) {
531
SubchainNode thisSubchain = findNodeAtIndex(thisIndex);
532
SubchainNode thatSubchain = that.findNodeAtIndex(thatIndex);
534
int thisStartIndex = thisIndex;
535
int thatStartIndex = thatIndex;
536
thisIndex = findRun(thisIndex);
537
thatIndex = that.findRun(thatIndex);
539
// System.out.println("Comparing run from " + thisStartIndex
540
// + " to " + thisIndex + ", starting at "
541
// + thisSubchain.getPathString());
542
if ((thisIndex - thisStartIndex) != (thatIndex - thatStartIndex)) {
543
System.out.println("**** " + thisFile
544
+ " has subchain run of length "
545
+ +(thisIndex - thisStartIndex)
546
+ " starting at subchain "
547
+ thisSubchain.getPathString() + ", but " + thatFile
548
+ " has run of length " + (thatIndex - thatStartIndex)
549
+ " starting at subchain "
550
+ thatSubchain.getPathString());
552
String thisState = thisSubchain.getState();
553
String thatState = thatSubchain.getState();
554
if (thisState.equals(thatState) == false) {
555
System.out.println("**** Subchain run starting at " + thisFile
556
+ ":" + thisSubchain.getPathString() + " has mode "
557
+ thisState + ", but run starting at " + thatFile
558
+ ": " + thatSubchain.getPathString() + " has mode "
564
public static interface ShiftListener {
565
public void shiftCompleted(ChainNode node);
568
public void addListener(ShiftListener l) {
572
public void removeListener(ShiftListener l) {
576
private void shiftCompleted() {
577
for (ShiftListener l : listeners) {
578
l.shiftCompleted(this);
583
public static void main(String[] args) {
584
String filename, path;
586
if (args.length >= 3) {
589
index = Integer.parseInt(args[2]);
591
filename = "heater.xml";
592
path = "heater.pScan";
595
ChainModel cm = new ChainModel(filename);
596
ChainNode node = (ChainNode) cm.findNode(path);
597
SubchainNode found = node.findNodeAtIndex(index);
598
System.out.println(found.getPathString());