~ubuntu-branches/ubuntu/maverick/electric/maverick

« back to all changes in this revision

Viewing changes to com/sun/electric/tool/simulation/test/ChainNode.java

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2010-01-09 16:26:04 UTC
  • mfrom: (1.1.4 upstream) (3.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100109162604-1ypvmy8ijmlc6oq7
Tags: 8.10-1
* New upstream version.
* debian/control
  - Add libjava3d-java and quilt build dependencies.
  - Update standards version to 3.8.3.
  - Add libjava3d-java as recommends to binary package.
* debian/rules
  - Use quilt patch system instead of simple patchsys.
  - Add java3d related jar files to DEB_JARS.
* debian/patches/*
  - Update as per current upstream source. Convert to quilt.
* debian/ant.properties
  - Do not disable 3D plugin anymore.
  - Use new property to disable compilation of OS X related classes.
* debian/wrappers/electric
  - Add java3d related jar files to runtime classpath.
* debian/README.source
  - Change text to the appropriate one for quilt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package com.sun.electric.tool.simulation.test;
 
2
 
 
3
import java.util.List;
 
4
import java.util.ArrayList;
 
5
 
 
6
/**
 
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.
 
12
 * <p>
 
13
 * 
 
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.
 
20
 * <p>
 
21
 * 
 
22
 * @author Eric Kim
 
23
 * @version 1.0 9/3/03
 
24
 * @author Tom O'Neill (toneill)
 
25
 * @version 1.1 7/22/04
 
26
 * Copyright (c) 2004,2005 by Sun Microsystems, Inc.
 
27
 *
 
28
 */
 
29
 
 
30
public class ChainNode extends SubchainNode {
 
31
 
 
32
    /**
 
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.
 
36
     */
 
37
    final private String opcode;
 
38
 
 
39
    /**
 
40
     * Scan chain bit pattern to be shifted into the chip during the next call
 
41
     * to this.shift().
 
42
     */
 
43
    protected BitVector inBits;
 
44
 
 
45
    /**
 
46
     * Scan chain bit pattern read back from the chip after last call to
 
47
     * this.shift(). Should only be modified by Netscan.
 
48
     */
 
49
    protected BitVector outBits;
 
50
 
 
51
    /**
 
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.
 
55
     */
 
56
    protected BitVector outBitsExpected;
 
57
 
 
58
    /** Expected value of outBits for the previous call to this.shift(). */
 
59
    protected BitVector oldOutBitsExpected;
 
60
 
 
61
    /**
 
62
     * State of the scan chain elements' shadow register, for those that have
 
63
     * one.
 
64
     */
 
65
    protected BitVector shadowState;
 
66
 
 
67
    /** Whether any data has been shifted to this scan chain */
 
68
    private boolean initialized = false;
 
69
 
 
70
    /**
 
71
     * A list of shift listeners
 
72
     */
 
73
    private List<ShiftListener> listeners;
 
74
 
 
75
 
 
76
    /**
 
77
     * Constructor for a root scan chain.
 
78
     * 
 
79
     * @param name
 
80
     *            node name
 
81
     * @param opcode
 
82
     *            on-chip address of root scan chain
 
83
     * @param newLength
 
84
     *            number of scan chain elements in node
 
85
     * @param comment
 
86
     *            comment attached to this node
 
87
     */
 
88
    public ChainNode(String name, String opcode, int newLength, String comment) {
 
89
        super(name, newLength, comment);
 
90
 
 
91
        this.opcode = opcode;
 
92
        listeners = new ArrayList<ShiftListener>();
 
93
 
 
94
        createBitVectors();
 
95
    }
 
96
 
 
97
    public String toString() {
 
98
        return super.toString() + " (op=" + opcode + ")";
 
99
    }
 
100
 
 
101
    /**
 
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.
 
105
     * 
 
106
     * @return Address of root scan chain (little endian)
 
107
     */
 
108
    String getOpcode() {
 
109
        return opcode;
 
110
    }
 
111
 
 
112
    /**
 
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}.
 
116
     */
 
117
    void setOutBits(BitVector newOutBits) {
 
118
        outBits.put(0, newOutBits);
 
119
    }
 
120
 
 
121
    /**
 
122
     * Get the scan chain bit pattern to be shifted into the chip during the next call
 
123
     * to this.shift().
 
124
     * @return the in bits
 
125
     */
 
126
    public BitVector getInBits() { return inBits; }
 
127
 
 
128
    /**
 
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
 
132
     */
 
133
    public BitVector getOutBits() { return outBits; }
 
134
 
 
135
    /**
 
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
 
140
     */
 
141
    public BitVector getOutBitsExpected() { return outBitsExpected; }
 
142
 
 
143
    /**
 
144
     * Get the expected value of outBits for the previous call to this.shift().
 
145
     * @return the old out bits expected
 
146
     */
 
147
    public BitVector getOldOutBitsExpected() { return oldOutBitsExpected; }
 
148
    
 
149
    /**
 
150
     * Get the state of the scan chain elements' shadow register, for those that have
 
151
     * one.
 
152
     * @return the shadow state bits
 
153
     */
 
154
    public BitVector getShadowState() { return shadowState; }
 
155
 
 
156
    /**
 
157
     * This is for ChainG display
 
158
     * @return the outbits
 
159
     */
 
160
    protected BitVector getOutBitsIndiscriminate() { return outBits; }
 
161
 
 
162
    /**
 
163
     * Returns ancestor <code>ChipNode</code>.
 
164
     * 
 
165
     * @return Chip node that is the ancestor to this <code>ChainNode</code>
 
166
     */
 
167
    ChipNode getParentChip() {
 
168
        MyTreeNode node = this;
 
169
        while (node.getClass() != ChipNode.class) {
 
170
            node = node.getParent();
 
171
            if (node == null) {
 
172
                Infrastructure.fatal(node
 
173
                        + " does not have a ChipNode as an ancestor");
 
174
            }
 
175
        }
 
176
        return (ChipNode) node;
 
177
    }
 
178
 
 
179
    /**
 
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
 
183
     * expected results.
 
184
     */
 
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();
 
190
 
 
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);
 
200
                }
 
201
            }
 
202
        }
 
203
    }
 
204
 
 
205
    /**
 
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.
 
208
     */
 
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)
 
213
                inBits.set(i, true);
 
214
            else
 
215
                inBits.set(i, false);
 
216
        }
 
217
    }
 
218
 
 
219
    /**
 
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}&nbsp;to false to suppress "no bits being
 
224
     * compared" warning on next shift.
 
225
     */
 
226
    void invalidate() {
 
227
        outBitsExpected.invalidate();
 
228
        initialized = false;
 
229
    }
 
230
 
 
231
    /**
 
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.
 
235
     * 
 
236
     * @param jtag
 
237
     *            JTAG tester object to perform shift with
 
238
     * @param readEnable
 
239
     *            whether to set opcode's read-enable bit
 
240
     * @param writeEnable
 
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
 
248
     * @param logger
 
249
     *            Object with logging properties to use
 
250
     * 
 
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
 
256
     */
 
257
    boolean shift(JtagTester jtag, boolean readEnable, boolean writeEnable,
 
258
            int irBadSeverity, int noTestSeverity, int errTestSeverity,
 
259
            Logger logger) {
 
260
        logger.logOther("------ " + getPathString() + ", R=" + readEnable
 
261
                + ", W=" + writeEnable);
 
262
 
 
263
        jtag.shift(this, readEnable, writeEnable, irBadSeverity);
 
264
 
 
265
        boolean noErrors = checkOutBits(readEnable, noTestSeverity,
 
266
                errTestSeverity);
 
267
 
 
268
        // After shift, all elements should hold inBits
 
269
        oldOutBitsExpected.putIndiscriminate(0, outBitsExpected);
 
270
        outBitsExpected.put(0, inBits);
 
271
 
 
272
        // Update the expected bits from any shadow registers
 
273
        // Note: this implies that shadow registers are not modified by the chip
 
274
        if (readEnable) {
 
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);
 
281
                    }
 
282
                }
 
283
            }
 
284
        }
 
285
        // Update the shadowState of any elements that wrote to their
 
286
        // shadow registers
 
287
        if (writeEnable) {
 
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);
 
293
                }
 
294
            }
 
295
        }
 
296
        shiftCompleted();
 
297
 
 
298
        return noErrors;
 
299
    }
 
300
 
 
301
    /**
 
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
 
305
     * otherwise be used.
 
306
     * 
 
307
     * @param jtag
 
308
     *            JTAG tester object to perform shift with
 
309
     * @param readEnable
 
310
     *            whether to set opcode's read-enable bit
 
311
     * @param writeEnable
 
312
     *            whether to set opcode's write-enable bit
 
313
     * @param irBadSeverity
 
314
     *            action when bits scanned out of IR are wrong
 
315
     * @param logger
 
316
     *            Object with logging properties to use
 
317
     * @return the bit that got shifted out
 
318
     * 
 
319
     * @see Infrastructure#SEVERITY_NOMESSAGE
 
320
     * @see Infrastructure#SEVERITY_WARNING
 
321
     * @see Infrastructure#SEVERITY_NONFATAL
 
322
     * @see Infrastructure#SEVERITY_FATAL
 
323
     */
 
324
    boolean shiftOneBit(JtagTester jtag, boolean readEnable,
 
325
            boolean writeEnable, int irBadSeverity, Logger logger) {
 
326
        logger.logOther("***** " + getPathString() + ", inBits=" + inBits);
 
327
 
 
328
        /*
 
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.
 
332
         */
 
333
        int length = getLength();
 
334
        setLength(1);
 
335
        jtag.shift(this, readEnable, writeEnable, irBadSeverity);
 
336
        boolean outbit = outBits.get(0);
 
337
        setLength(length);
 
338
 
 
339
        /*
 
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
 
342
         */
 
343
        outBitsExpected.invalidate();
 
344
        oldOutBitsExpected.invalidate();
 
345
        shadowState.invalidate();
 
346
 
 
347
        return outbit;
 
348
    }
 
349
 
 
350
    /**
 
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.
 
355
     */
 
356
    void lengthChanged() {
 
357
 
 
358
        // Recompute current node's length, taking children into account
 
359
        this.computeLength();
 
360
 
 
361
        createBitVectors();
 
362
    }
 
363
 
 
364
    /**
 
365
     * Find descendent of current <code>ChainNode</code> that contains the
 
366
     * scan chain element at index bitIndex.
 
367
     * 
 
368
     * @param bitIndex
 
369
     *            index of scan chain element
 
370
     * @return scan chain node containing the specified element.
 
371
     */
 
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());
 
376
        }
 
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();
 
382
 
 
383
            if (nextIndex <= bitIndex) {
 
384
                // Target not within this node, accumlate length and try
 
385
                // next sibling
 
386
                nodeIndex = nextIndex;
 
387
            } else {
 
388
                // Within this node. If leaf node, we have found it. Else,
 
389
                // try first child.
 
390
                int nkids = node.getChildCount();
 
391
                if (nkids == 0) {
 
392
                    return node;
 
393
                }
 
394
                parent = node;
 
395
                indChild = 0;
 
396
            }
 
397
            node = (SubchainNode) parent.getChildAt(indChild);
 
398
        }
 
399
    }
 
400
 
 
401
 
 
402
    /*
 
403
     * Called by constructor or when length changed, replaces the BitVector
 
404
     * members with new versions of the correct length.
 
405
     */
 
406
    protected void createBitVectors() {
 
407
        int newLength = getLength();
 
408
        if (newLength < 0)
 
409
            newLength = 0;
 
410
 
 
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");
 
418
    }
 
419
 
 
420
    /**
 
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.
 
423
     * 
 
424
     * @param readEnable
 
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
 
431
     */
 
432
    private boolean checkOutBits(boolean readEnable, int noTestSeverity,
 
433
            int errTestSeverity) {
 
434
 
 
435
        int length = getLength();
 
436
 
 
437
        /*
 
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
 
440
         * previous inBits
 
441
         */
 
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()) {
 
447
 
 
448
                /*
 
449
                 * Can only know read value of an element with a shadow register
 
450
                 * that is in a known state
 
451
                 */
 
452
                if (node.usesShadow() && shadowState.isValid(ind)) {
 
453
                    outBitsExpected.set(ind, shadowState.get(ind));
 
454
                } else {
 
455
                    outBitsExpected.invalidate(ind);
 
456
                }
 
457
            }
 
458
        }
 
459
 
 
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");
 
467
            }
 
468
        }
 
469
        initialized = true;
 
470
 
 
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)) {
 
476
                errors.set(iBit);
 
477
            } else {
 
478
                errors.clear(iBit);
 
479
            }
 
480
        }
 
481
 
 
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.");
 
489
        }
 
490
        return noErrors;
 
491
    }
 
492
 
 
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();
 
500
 
 
501
        int ind;
 
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) {
 
509
                return ind;
 
510
            }
 
511
        }
 
512
 
 
513
        return ind;
 
514
    }
 
515
 
 
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);
 
527
        }
 
528
 
 
529
        int thisIndex = 0, thatIndex = 0;
 
530
        while (thisIndex < length && thatIndex < length) {
 
531
            SubchainNode thisSubchain = findNodeAtIndex(thisIndex);
 
532
            SubchainNode thatSubchain = that.findNodeAtIndex(thatIndex);
 
533
 
 
534
            int thisStartIndex = thisIndex;
 
535
            int thatStartIndex = thatIndex;
 
536
            thisIndex = findRun(thisIndex);
 
537
            thatIndex = that.findRun(thatIndex);
 
538
 
 
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());
 
551
            }
 
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 "
 
559
                        + thatState);
 
560
            }
 
561
        }
 
562
    }
 
563
 
 
564
    public static interface ShiftListener {
 
565
        public void shiftCompleted(ChainNode node);
 
566
    }
 
567
 
 
568
    public void addListener(ShiftListener l) {
 
569
        listeners.add(l);
 
570
    }
 
571
 
 
572
    public void removeListener(ShiftListener l) {
 
573
        listeners.remove(l);
 
574
    }
 
575
 
 
576
    private void shiftCompleted() {
 
577
        for (ShiftListener l : listeners) {
 
578
            l.shiftCompleted(this);
 
579
        }
 
580
    }
 
581
 
 
582
 
 
583
    public static void main(String[] args) {
 
584
        String filename, path;
 
585
        int index;
 
586
        if (args.length >= 3) {
 
587
            filename = args[0];
 
588
            path = args[1];
 
589
            index = Integer.parseInt(args[2]);
 
590
        } else {
 
591
            filename = "heater.xml";
 
592
            path = "heater.pScan";
 
593
            index = 40;
 
594
        }
 
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());
 
599
    }
 
600
}