1 package edu.berkeley.fleet.marina;
2 import com.sun.electric.tool.simulation.test.*;
3 import java.util.ArrayList;
5 import edu.berkeley.fleet.marina.MarinaUtils.StateWireState;
7 public class ProperStopper {
8 // position of strobes in the control chain
9 private static final int BLOCK_STROBE_NDX = 0;
10 private static final int FILL_STROBE_NDX = 1;
11 private static final int GO_STROBE_NDX = 2;
12 private static final int SILENT_STROBE_NDX = 3;
13 private static final int CLEAR_STROBE_NDX = 4;
14 private static final int GENERAL_PURPOSE_STROBE_NDX = 5;
16 // position of inputs in report chain
17 private static final int PREV_STATE_IN_NDX = 0;
18 private static final int FILL_STROBE_IN_NDX = 1;
19 private static final int FILL_STATE_IN_NDX = 2;
20 private static final int STOPPED_IN_NDX = 3;
22 private final String name;
23 //private final String captureClockRelPath = "fillStag@1.gaspFill@0.fillScan@1";
24 private final String captureClockRelPath = "fillStag@1";
25 // test library direct write mode doesn't understand per register write
26 // enables. We get simulation to work by toggling write clock.
27 private final boolean clockHack;
28 private final String captureClockName = "sx[4]";
31 private boolean traceFill = true;
32 private boolean traceDrain = true;
34 private boolean traceFill = false;
35 private boolean traceDrain = false;
38 controlChain = Marina.CONTROL_CHAIN,
40 dataChain = Marina.DATA_CHAIN,
42 reportChain = Marina.REPORT_CHAIN,
44 private final String captureClock;
45 private final ChainControls cc;
46 private final ChipModel model;
47 private final Indenter indenter;
49 private final String pathToCounter;
51 protected static void fatal(boolean pred, String msg) { MarinaUtils.fatal(pred, msg); }
52 private void prln(String msg) { indenter.prln(msg); }
53 private void adjustIndent(int n) { indenter.adjustIndent(n); }
55 /** NanosimModel.setNodeState() requires special path names.
56 * Each instance name in the path must begin with the character 'x'.
57 * Return a path with the added X's. */
58 private String prefixInstNamesInPathWithX(String path) {
59 if (model==null) throw new RuntimeException();
60 if (!(model instanceof NanosimModel)) return path;
61 StringBuffer sb = new StringBuffer();
63 for (int i=0; i<path.length(); i++) {
64 char c = path.charAt(i);
66 if (c=='.') sb.append('x');
71 private void shiftControl(boolean readEnable, boolean writeEnable) {
72 //System.out.println("start shiftcontrol");
73 cc.shift(controlChain, readEnable, writeEnable);
74 //System.out.println(" end shiftcontrol");
76 private void shiftData(boolean readEnable, boolean writeEnable) {
77 //System.out.println("start shiftdata");
78 cc.shift(dataChain, readEnable, writeEnable);
80 if (clockHack && model instanceof NanosimModel) {
81 NanosimModel nanoModel = (NanosimModel) model;
82 nanoModel.setNodeState(captureClock, 1);
84 nanoModel.setNodeState(captureClock, 0);
85 } else if (clockHack && model instanceof VerilogModel) {
86 VerilogModel nanoModel = (VerilogModel) model;
87 nanoModel.setNodeState(captureClock, 1);
89 nanoModel.setNodeState(captureClock, 0);
92 //System.out.println(" end shiftdata");
94 private void shiftReport(boolean readEnable, boolean writeEnable) {
95 //System.out.println("start shiftreport");
96 cc.shift(reportChain, readEnable, writeEnable);
97 //System.out.println(" end shiftreport");
100 private StateWireState boolToState(boolean b) {
101 return b ? StateWireState.FULL : StateWireState.EMPTY;
104 private CommandCodes fdcstate = null;
106 public void setCounterEnable(boolean enable) {
108 setFillDrainControl(fdcstate);
111 public void setCounterValue(int val) {
112 SubchainNode chainNode = (SubchainNode) cc.getChainControlFromPath(dataChain).findNode(pathToCounter);
113 int bitIndex = chainNode.getBitIndex();
114 ChainNode root = chainNode.getParentChain();
115 for(int i=0; i<31; i++)
116 root.getInBits().set(bitIndex+i, ((1<<i) & val)!=0);
117 shiftData(false, true);
120 // DOES NOT SHIFT THE CHAIN!!!!
121 public int getCounterValue() {
122 SubchainNode chainNode = (SubchainNode) cc.getChainControlFromPath(dataChain).findNode(pathToCounter);
123 int bitIndex = chainNode.getBitIndex();
124 ChainNode root = chainNode.getParentChain();
125 return (int)root.getOutBits().get(bitIndex, 30).bitReverse().toLong();
128 // The first 5 bits of the control chain control the fill and drain stages
129 private void setFillDrainControl(CommandCodes ccc) {
130 BitVector fdCtl = ccc.bits(extra);
132 fatal(fdCtl.getNumBits()!=6, "expect 6 proper stopper control bits");
133 BitVector val = cc.getInBits(controlPath);
134 for (int i=0; i<fdCtl.getNumBits(); i++) {
135 val.set(i, fdCtl.get(i));
137 cc.setInBits(controlPath, val);
138 shiftControl(false, true);
140 // The last bit of the control chain controls the general purpose
142 public void setGeneralPurposeOutput(Boolean b) {
143 BitVector val = cc.getInBits(controlPath);
144 val.set(GENERAL_PURPOSE_STROBE_NDX,b);
145 shiftControl(false, true);
148 //-------------------------- public methods ----------------------------
150 /** Put stopper in RUN state */
152 setFillDrainControl(CommandCodes.RUN);
154 /** Put stopper in IDLE state */
156 setFillDrainControl(CommandCodes.IDLE);
158 /** Put stopper in FILL state */
160 setFillDrainControl(CommandCodes.FILL);
162 /** Put stopper in BLOCK state */
163 public void block() {
164 setFillDrainControl(CommandCodes.BLOCK);
166 /** Put stopper in STOP state */
168 setFillDrainControl(CommandCodes.STOP);
170 /** Put stopper in CLEAR state */
171 public void clear() {
172 setFillDrainControl(CommandCodes.CLEAR);
174 /** Put stopper in SOURCE state */
175 public void source() {
176 setFillDrainControl(CommandCodes.SOURCE);
178 /** Put stopper in STOPSOURCE state */
179 public void stopSource() {
180 setFillDrainControl(CommandCodes.STOPSOURCE);
182 /** Put stopper in SINK state */
184 setFillDrainControl(CommandCodes.SINK);
186 /** Put stopper in STOPSINK state */
187 public void stopSink() {
188 setFillDrainControl(CommandCodes.STOPSINK);
191 public boolean extra = false;
193 /** Stop a running stopper in order to add items. Ensure that we don't
194 * lose the item in the fill stage.
195 * Exit state: block */
196 public void stopToFill() {
203 /** get value of the state wire preceding the fill stage */
204 public StateWireState getPrevStateWire() {
205 shiftReport(true, false);
206 BitVector b = cc.getOutBits(reportPath);
207 int n = b.getNumBits();
208 fatal(n!=4, "Bad number of Stopper report bits: "+n);
209 return boolToState(cc.getOutBits(reportPath).get(PREV_STATE_IN_NDX));
212 /** get the value of drain stage fill wire.
213 * The fill wire will be interesting if we doubt that the
214 * scan chain works. */
215 public boolean getFillStrobe() {
216 shiftReport(true, false);
217 return cc.getOutBits(reportPath).get(FILL_STROBE_IN_NDX);
220 /** get value of state wire between the fill and drain stages */
221 public StateWireState getFillStateWire() {
222 shiftReport(true, false);
223 return boolToState(cc.getOutBits(reportPath).get(FILL_STATE_IN_NDX));
226 /** get value of drain stage stopped wire */
227 public boolean getStopped() {
228 shiftReport(true, false);
229 return cc.getOutBits(reportPath).get(STOPPED_IN_NDX);
232 public String getReportString() {
233 StringBuffer sb = new StringBuffer();
234 sb.append("Stopper's prev state: ");
235 sb.append(getPrevStateWire()+"\n");
236 sb.append("Stopper's fill stage: ");
237 sb.append(getFillStateWire()+"\n");
238 sb.append("Stopper's stopped: ");
239 sb.append(getStopped()+"\n");
240 return sb.toString();
243 /** construct a ProperStopper */
244 public ProperStopper(String name,
246 ChainControls cc, ChipModel model,
249 String pathToCounter) {
251 this.controlPath = controlChain+'.'+propInst;
252 this.dataPath = dataChain+'.'+propInst;
253 this.reportPath = reportChain+'.'+propInst;
256 prefixInstNamesInPathWithX(propInst+'.'+captureClockRelPath)
257 +'.'+captureClockName;
259 this.clockHack = clockHack;
260 this.indenter = indenter;
261 this.pathToCounter = dataChain+'.'+pathToCounter;
264 /** Reset ProperStopper after the JTAG TRST has been pulsed */
265 public void resetAfterMasterClear() {
266 BitVector we = new BitVector(2, "write enable");
267 BitVector packet = new BitVector(MarinaPacket.PACKET_WIDTH, "packet");
269 packet.setFromLong(0);
270 BitVector wdta = we.cat(packet);
271 cc.setInBits(dataPath, wdta);
274 /** Insert one item into the fill stage.
275 * Fill stage must be empty.
276 * You must stop stopper before calling fill.
277 * exit state: block */
278 private void fill_(BitVector dta) {
281 int n = dta.getNumBits();
282 fatal(n!=(37+1+14), "fill: wrong num bits: "+n);
284 // make sure fill stage is empty
285 StateWireState myState = getFillStateWire();
286 fatal(myState!=StateWireState.EMPTY, "fill: fill stage already full");
288 idle(); // block = 1, go = 0
290 BitVector wrEn = new BitVector(2, "write enable");
292 cc.setInBits(dataPath, wrEn.cat(dta));
293 shiftData(false, true);
303 if (traceFill) prln(getReportString());
305 // if data chain is shifted in the future, don't write!
307 cc.setInBits(dataPath, wrEn.cat(dta));
310 if (traceFill) prln("End fill");
313 public void fill(BitVector dat) {
314 if (traceFill) prln("Begin fill. stopper="+name);
315 if (traceFill) prln("writing data: "+new MarinaPacket(dat));
319 public void fill(MarinaPacket mp) {
320 if (traceFill) prln("Begin fill. stopper="+name);
321 if (traceFill) prln("writing data: "+mp);
322 fill_(mp.toSingleBitVector());
325 /** Insert items from a list, one by one.
326 * You must stop stopper before calling fillMany()
327 * exit state: block */
328 public void fillMany(List<BitVector> data) {
329 prln("Begin fillMany. stopper="+name+" numWords="+data.size());
332 for (BitVector bv : data) {
333 if (traceFill) prln("fillStopperMany: writing word number: "+cnt++);
337 prln("end fillMany");
340 /** Remove one item from fill stage. Return that item.
341 * An item must be available.
342 * drain() will stop cleanly.
343 * exit state: stop */
344 public BitVector drain() {
345 stop(); // all zero, block = 0, go = 0
347 // make sure an item is available
348 StateWireState myState=getFillStateWire();
349 fatal(myState==StateWireState.EMPTY, "drain: fill stage empty");
351 return drainNoCheck();
354 /** Remove one item from fill stage. Return that item.
355 * Assume that an item is available.
357 * exit state: stop */
358 private BitVector drainNoCheck() {
359 shiftData(true, false);
361 // strip the two write enable bits
362 BitVector ans = cc.getOutBits(dataPath).get(2, 52);
365 clear(); // clear = 1
369 if (traceDrain) prln("drain stopper="+name+" data="+new MarinaPacket(ans));
373 /** Remove as many items as possible from the fill stage.
374 * drainStopperMany() will stop cleanly.
375 * exit state: stop */
376 public List<BitVector> drainMany() {
377 return drainMany(Integer.MAX_VALUE);
380 /** Remove up to maxNbItems items from the fill stage.
381 * drainStopperMany() will stop cleanly.
382 * exit state: stop */
383 public List<BitVector> drainMany(int maxNbItems) {
388 List<BitVector> ans = new ArrayList<BitVector>();
392 StateWireState myState=getFillStateWire();
395 if (traceDrain) prln(getReportString());
397 if (myState==StateWireState.EMPTY || cnt>=maxNbItems) break;
400 indenter.pr(" drain"+(maxNbItems==0?"":"Many")+
401 ": reading word"+(maxNbItems==0?":":" number "+cnt+
402 "/"+(maxNbItems==Integer.MAX_VALUE
403 ?"unlimited":("at-most-"+maxNbItems))+": "));
405 BitVector d = drainNoCheck();
407 prln(" got "+new MarinaPacket(d));
412 prln("end drainMany, got "+ans.size()+" items");
418 // proper stopper ring occupancy bits
419 //southFif@1.upDown8w@1.weakStag@18.scanEx1@0 REPORT chain
420 //18, 22, 19, 23, 20, 24, 21, 25
421 //northFif@1.upDown8w@2...
422 // south fifo tap stage:
423 // southFif@1.tapPropS@1.tapStage@2.scanEx1@0 (also REPORT chain)
426 * (Note by Bill and Adam: Ivan has struck again!)
427 * As of 05 March 2009 the new bits are:
428 * Block Extra Fill Go Clear Silent
429 * => Note: "Extra" gets fed to the mux in the counter
430 * that selects the frequency output that goes off-chip
432 * Caution: Ivan changes the order of the ProperStopper control bits
433 * from chip to chip. Here is the current order for Marina
435 * Block, Fill, Go, Silent, Clear
437 * The old bit order for Infinity was: Fill, Block, Clear, Silent, Go
439 private static enum CommandCodes {
440 RUN ("000100","010100"),
441 IDLE ("100000","110000"),
442 FILL ("101000","111000"),
443 BLOCK ("100100","110100"),
444 STOP ("000000","010000"),
445 CLEAR ("100010","110010"),
446 SOURCE ("001100","011100"),
447 STOPSOURCE ("001000","011000"),
448 SINK ("000101","010101"),
449 STOPSINK ("000001","010001");
450 private BitVector scanBits0;
451 private BitVector scanBits1;
452 CommandCodes(String bits0,String bits1) {
453 scanBits0 = new BitVector(bits0,"CommandCodes");
454 scanBits1 = new BitVector(bits1,"CommandCodes");
456 public BitVector bits(boolean extra) {
457 return extra ? scanBits1 : scanBits0;