1 package com.sun.vlsi.chips.marina.test;
2 import java.util.ArrayList;
5 import com.sun.async.test.BitVector;
6 import com.sun.async.test.ChainControl;
7 import com.sun.async.test.ChipModel;
8 import com.sun.async.test.Infrastructure;
9 import com.sun.async.test.NanosimModel;
10 import com.sun.vlsi.chips.marina.test.MarinaUtils.StateWireState;
12 public class ProperStopper {
13 // position of strobes in the control chain
14 private static final int BLOCK_STROBE_NDX = 0;
15 private static final int FILL_STROBE_NDX = 1;
16 private static final int GO_STROBE_NDX = 2;
17 private static final int SILENT_STROBE_NDX = 3;
18 private static final int CLEAR_STROBE_NDX = 4;
19 private static final int GENERAL_PURPOSE_STROBE_NDX = 5;
21 // position of inputs in report chain
22 private static final int PREV_STATE_IN_NDX = 0;
23 private static final int FILL_STROBE_IN_NDX = 1;
24 private static final int FILL_STATE_IN_NDX = 2;
25 private static final int STOPPED_IN_NDX = 3;
27 private final String name;
28 private final String captureClockRelPath = "fillStag@1.gaspFill@0.fillScan@1";
29 // test library direct write mode doesn't understand per register write
30 // enables. We get simulation to work by toggling write clock.
31 private final boolean clockHack;
32 private final String captureClockName = "si[4]";
34 private boolean traceFill = true;
35 private boolean traceDrain = true;
37 private final String controlChain, controlPath,
39 reportChain, reportPath;
40 private final String captureClock;
41 private final ChainControls cc;
42 private final ChipModel model;
43 private final Indenter indenter;
45 protected static void fatal(boolean pred, String msg) { if (pred) Infrastructure.fatal(msg); }
46 private void prln(String msg) { indenter.prln(msg); }
47 private void adjustIndent(int n) { indenter.adjustIndent(n); }
49 /** NanosimModel.setNodeState() requires special path names.
50 * Each instance name in the path must begin with the character 'x'.
51 * Return a path with the added X's. */
52 private String prefixInstNamesInPathWithX(String path) {
53 StringBuffer sb = new StringBuffer();
55 for (int i=0; i<path.length(); i++) {
56 char c = path.charAt(i);
58 if (c=='.') sb.append('x');
63 private void shiftControl(boolean readEnable, boolean writeEnable) {
64 cc.shift(controlChain, readEnable, writeEnable);
66 private void shiftData(boolean readEnable, boolean writeEnable) {
67 cc.shift(dataChain, readEnable, writeEnable);
69 if (clockHack && model instanceof NanosimModel) {
70 NanosimModel nanoModel = (NanosimModel) model;
71 nanoModel.setNodeState(captureClock, 1);
73 nanoModel.setNodeState(captureClock, 0);
77 private void shiftReport(boolean readEnable, boolean writeEnable) {
78 cc.shift(reportChain, readEnable, writeEnable);
81 private StateWireState boolToState(boolean b) {
82 return b ? StateWireState.FULL : StateWireState.EMPTY;
84 // The first 5 bits of the control chain control the fill and drain stages
85 private void setFillDrainControl(BitVector fdCtl) {
86 fatal(fdCtl.getNumBits()!=6, "expect 6 proper stopper control bits");
87 BitVector val = cc.getInBits(controlPath);
88 for (int i=0; i<fdCtl.getNumBits(); i++) {
89 val.set(i, fdCtl.get(i));
91 cc.setInBits(controlPath, val);
92 shiftControl(false, true);
94 // The last bit of the control chain controls the general purpose
96 public void setGeneralPurposeOutput(Boolean b) {
97 BitVector val = cc.getInBits(controlPath);
98 val.set(GENERAL_PURPOSE_STROBE_NDX,b);
99 shiftControl(false, true);
102 //-------------------------- public methods ----------------------------
104 /** Put stopper in RUN state */
106 setFillDrainControl(CommandCodes.RUN.bits());
108 /** Put stopper in IDLE state */
110 setFillDrainControl(CommandCodes.IDLE.bits());
112 /** Put stopper in FILL state */
114 setFillDrainControl(CommandCodes.FILL.bits());
116 /** Put stopper in BLOCK state */
117 public void block() {
118 setFillDrainControl(CommandCodes.BLOCK.bits());
120 /** Put stopper in STOP state */
122 setFillDrainControl(CommandCodes.STOP.bits());
124 /** Put stopper in CLEAR state */
125 public void clear() {
126 setFillDrainControl(CommandCodes.CLEAR.bits());
128 /** Put stopper in SOURCE state */
129 public void source() {
130 setFillDrainControl(CommandCodes.SOURCE.bits());
132 /** Put stopper in STOPSOURCE state */
133 public void stopSource() {
134 setFillDrainControl(CommandCodes.STOPSOURCE.bits());
136 /** Put stopper in SINK state */
138 setFillDrainControl(CommandCodes.SINK.bits());
140 /** Put stopper in STOPSINK state */
141 public void stopSink() {
142 setFillDrainControl(CommandCodes.STOPSINK.bits());
145 /** Stop a running stopper in order to add items. Ensure that we don't
146 * lose the item in the fill stage.
147 * Exit state: block */
148 public void stopToFill() {
155 /** get value of the state wire preceding the fill stage */
156 public StateWireState getPrevStateWire() {
157 shiftReport(true, false);
158 BitVector b = cc.getOutBits(reportPath);
159 int n = b.getNumBits();
160 fatal(n!=4, "Bad number of Stopper report bits: "+n);
161 return boolToState(cc.getOutBits(reportPath).get(PREV_STATE_IN_NDX));
164 /** get the value of drain stage fill wire.
165 * The fill wire will be interesting if we doubt that the
166 * scan chain works. */
167 public boolean getFillStrobe() {
168 shiftReport(true, false);
169 return cc.getOutBits(reportPath).get(FILL_STROBE_IN_NDX);
172 /** get value of state wire between the fill and drain stages */
173 public StateWireState getFillStateWire() {
174 shiftReport(true, false);
175 return boolToState(cc.getOutBits(reportPath).get(FILL_STATE_IN_NDX));
178 /** get value of drain stage stopped wire */
179 public boolean getStopped() {
180 shiftReport(true, false);
181 return cc.getOutBits(reportPath).get(STOPPED_IN_NDX);
184 public String getReportString() {
185 StringBuffer sb = new StringBuffer();
186 sb.append("Stopper's prev state: ");
187 sb.append(getPrevStateWire()+"\n");
188 sb.append("Stopper's fill stage: ");
189 sb.append(getFillStateWire()+"\n");
190 sb.append("Stopper's stopped: ");
191 sb.append(getStopped()+"\n");
192 return sb.toString();
195 /** construct a ProperStopper */
196 public ProperStopper(String propInst,
197 String controlChain, String dataChain,
199 ChainControls cc, ChipModel model,
202 this.name = propInst;
203 this.controlChain = controlChain;
204 this.controlPath = controlChain+'.'+propInst;
205 this.dataChain = dataChain;
206 this.dataPath = dataChain+'.'+propInst;
207 this.reportChain = reportChain;
208 this.reportPath = reportChain+'.'+propInst;
210 prefixInstNamesInPathWithX(propInst+'.'+captureClockRelPath)
211 +'.'+captureClockName;
214 this.clockHack = clockHack;
215 this.indenter = indenter;
218 /** Reset ProperStopper after the JTAG TRST has been pulsed */
219 public void resetAfterMasterClear() {
220 BitVector we = new BitVector(2, "write enable");
221 BitVector packet = new BitVector(MarinaPacket.PACKET_WIDTH, "packet");
223 packet.setFromLong(0);
224 BitVector wdta = we.cat(packet);
225 cc.setInBits(dataPath, wdta);
228 /** Insert one item into the fill stage.
229 * Fill stage must be empty.
230 * You must stop stopper before calling fill.
231 * exit state: block */
232 public void fill(BitVector dta) {
233 if (traceFill) prln("Begin fill. stopper="+name);
236 int n = dta.getNumBits();
237 fatal(n!=(37+1+14), "fill: wrong num bits: "+n);
239 // make sure fill stage is empty
240 StateWireState myState = getFillStateWire();
241 fatal(myState!=StateWireState.EMPTY, "fill: fill stage already full");
243 if (traceFill) prln("writing data: "+new MarinaPacket(dta));
245 idle(); // block = 1, go = 0
247 BitVector wrEn = new BitVector(2, "write enable");
249 cc.setInBits(dataPath, wrEn.cat(dta));
250 shiftData(false, true);
260 if (traceFill) prln(getReportString());
262 // if data chain is shifted in the future, don't write!
264 cc.setInBits(dataPath, wrEn.cat(dta));
267 if (traceFill) prln("End fill");
270 public void fill(MarinaPacket mp) {
271 fill(mp.toSingleBitVector());
274 /** Insert items from a list, one by one.
275 * You must stop stopper before calling fillMany()
276 * exit state: block */
277 public void fillMany(List<BitVector> data) {
278 prln("Begin fillMany. stopper="+name+" numWords="+data.size());
281 for (BitVector bv : data) {
282 if (traceFill) prln("fillStopperMany: writing word number: "+cnt++);
286 prln("end fillMany");
289 /** Remove one item from fill stage. Return that item.
290 * An item must be available.
291 * drain() will stop cleanly.
292 * exit state: stop */
293 public BitVector drain() {
294 stop(); // all zero, block = 0, go = 0
296 // make sure an item is available
297 StateWireState myState=getFillStateWire();
298 fatal(myState==StateWireState.EMPTY, "drain: fill stage empty");
300 return drainNoCheck();
303 /** Remove one item from fill stage. Return that item.
304 * Assume that an item is available.
306 * exit state: stop */
307 protected BitVector drainNoCheck() {
308 shiftData(true, false);
310 // strip the two write enable bits
311 BitVector ans = cc.getOutBits(dataPath).get(2, 52);
314 clear(); // clear = 1
318 if (traceDrain) prln("drain stopper="+name+" data="+new MarinaPacket(ans));
322 /** Remove as many items as possible from the fill stage.
323 * drainStopperMany() will stop cleanly.
324 * exit state: stop */
325 public List<BitVector> drainMany() {
326 return drainMany(Integer.MAX_VALUE);
329 /** Remove up to maxNbItems items from the fill stage.
330 * drainStopperMany() will stop cleanly.
331 * exit state: stop */
332 public List<BitVector> drainMany(int maxNbItems) {
333 prln("begin drainMany. stopper="+name);
338 List<BitVector> ans = new ArrayList<BitVector>();
342 StateWireState myState=getFillStateWire();
345 if (traceDrain) prln(getReportString());
347 if (myState==StateWireState.EMPTY || cnt>=maxNbItems) break;
349 if (traceDrain) prln("drainMany: reading word number: "+cnt++);
351 BitVector d = drainNoCheck();
357 prln("end drainMany, got "+ans.size()+" items");
364 * (Note by Bill and Adam: Ivan has struck again!)
365 * As of 05 March 2009 the new bits are:
366 * Block Extra Fill Go Clear Silent
367 * => Note: "Extra" gets fed to the mux in the counter
368 * that selects the frequency output that goes off-chip
370 * Caution: Ivan changes the order of the ProperStopper control bits
371 * from chip to chip. Here is the current order for Marina
373 * Block, Fill, Go, Silent, Clear
375 * The old bit order for Infinity was: Fill, Block, Clear, Silent, Go
377 private static enum CommandCodes {
385 STOPSOURCE ("001000"),
388 private BitVector scanBits;
389 CommandCodes(String bits) {
390 scanBits = new BitVector(bits,"CommandCodes");
392 public BitVector bits() {return scanBits;}