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;
37 private final String controlPath, dataPath, reportPath;
38 private final ChainControl controlChain;
39 private final ChainControl dataChain;
40 private final ChainControl reportChain;
41 private final String captureClock;
42 private final ChipModel model;
43 private final Indenter indenter;
45 private final String pathToCounter;
47 protected static void fatal(boolean pred, String msg) { MarinaUtils.fatal(pred, msg); }
48 private void prln(String msg) { indenter.prln(msg); }
49 private void adjustIndent(int n) { indenter.adjustIndent(n); }
51 /** NanosimModel.setNodeState() requires special path names.
52 * Each instance name in the path must begin with the character 'x'.
53 * Return a path with the added X's. */
54 private String prefixInstNamesInPathWithX(String path) {
55 if (model==null) throw new RuntimeException();
56 if (!(model instanceof NanosimModel)) return path;
57 StringBuffer sb = new StringBuffer();
59 for (int i=0; i<path.length(); i++) {
60 char c = path.charAt(i);
62 if (c=='.') sb.append('x');
67 private void shiftControl(boolean readEnable, boolean writeEnable) {
68 controlChain.shift(Marina.CONTROL_CHAIN, readEnable, writeEnable);
70 private void shiftData(boolean readEnable, boolean writeEnable) {
71 dataChain.shift(Marina.DATA_CHAIN, readEnable, writeEnable);
73 if (clockHack && model instanceof NanosimModel) {
74 NanosimModel nanoModel = (NanosimModel) model;
75 nanoModel.setNodeState(captureClock, 1);
77 nanoModel.setNodeState(captureClock, 0);
78 } else if (clockHack && model instanceof VerilogModel) {
79 VerilogModel nanoModel = (VerilogModel) model;
80 nanoModel.setNodeState(captureClock, 1);
82 nanoModel.setNodeState(captureClock, 0);
86 private void shiftReport(boolean readEnable, boolean writeEnable) {
87 reportChain.shift(Marina.REPORT_CHAIN, readEnable, writeEnable);
90 private StateWireState boolToState(boolean b) {
91 return b ? StateWireState.FULL : StateWireState.EMPTY;
94 private CommandCodes fdcstate = null;
96 public void setCounterEnable(boolean enable) {
98 setFillDrainControl(fdcstate);
101 public void setCounterValue(int val) {
102 SubchainNode chainNode = (SubchainNode) dataChain.findNode(pathToCounter);
103 int bitIndex = chainNode.getBitIndex();
104 ChainNode root = chainNode.getParentChain();
105 for(int i=0; i<31; i++)
106 root.getInBits().set(bitIndex+i, ((1<<i) & val)!=0);
107 shiftData(false, true);
110 // DOES NOT SHIFT THE CHAIN!!!!
111 public int getCounterValue() {
112 SubchainNode chainNode = (SubchainNode) dataChain.findNode(pathToCounter);
113 int bitIndex = chainNode.getBitIndex();
114 ChainNode root = chainNode.getParentChain();
115 return (int)root.getOutBits().get(bitIndex, 30).bitReverse().toLong();
118 // The first 5 bits of the control chain control the fill and drain stages
119 private void setFillDrainControl(CommandCodes ccc) {
120 BitVector fdCtl = ccc.bits(extra);
122 fatal(fdCtl.getNumBits()!=6, "expect 6 proper stopper control bits");
123 BitVector val = controlChain.getInBits(controlPath);
124 for (int i=0; i<fdCtl.getNumBits(); i++) {
125 val.set(i, fdCtl.get(i));
127 controlChain.setInBits(controlPath, val);
128 shiftControl(false, true);
130 // The last bit of the control chain controls the general purpose
132 public void setGeneralPurposeOutput(Boolean b) {
133 BitVector val = controlChain.getInBits(controlPath);
134 val.set(GENERAL_PURPOSE_STROBE_NDX,b);
135 shiftControl(false, true);
138 //-------------------------- public methods ----------------------------
140 /** Put stopper in RUN state */
142 setFillDrainControl(CommandCodes.RUN);
144 /** Put stopper in IDLE state */
146 setFillDrainControl(CommandCodes.IDLE);
148 /** Put stopper in FILL state */
150 setFillDrainControl(CommandCodes.FILL);
152 /** Put stopper in BLOCK state */
153 public void block() {
154 setFillDrainControl(CommandCodes.BLOCK);
156 /** Put stopper in STOP state */
158 setFillDrainControl(CommandCodes.STOP);
160 /** Put stopper in CLEAR state */
161 public void clear() {
162 setFillDrainControl(CommandCodes.CLEAR);
164 /** Put stopper in SOURCE state */
165 public void source() {
166 setFillDrainControl(CommandCodes.SOURCE);
168 /** Put stopper in STOPSOURCE state */
169 public void stopSource() {
170 setFillDrainControl(CommandCodes.STOPSOURCE);
172 /** Put stopper in SINK state */
174 setFillDrainControl(CommandCodes.SINK);
176 /** Put stopper in STOPSINK state */
177 public void stopSink() {
178 setFillDrainControl(CommandCodes.STOPSINK);
181 public boolean extra = false;
183 /** Stop a running stopper in order to add items. Ensure that we don't
184 * lose the item in the fill stage.
185 * Exit state: block */
186 public void stopToFill() {
193 /** get value of the state wire preceding the fill stage */
194 public StateWireState getPrevStateWire() {
195 shiftReport(true, false);
196 BitVector b = reportChain.getOutBits(reportPath);
197 int n = b.getNumBits();
198 fatal(n!=4, "Bad number of Stopper report bits: "+n);
199 return boolToState(reportChain.getOutBits(reportPath).get(PREV_STATE_IN_NDX));
202 /** get the value of drain stage fill wire.
203 * The fill wire will be interesting if we doubt that the
204 * scan chain works. */
205 public boolean getFillStrobe() {
206 shiftReport(true, false);
207 return reportChain.getOutBits(reportPath).get(FILL_STROBE_IN_NDX);
210 /** get value of state wire between the fill and drain stages */
211 public StateWireState getFillStateWire() {
212 shiftReport(true, false);
213 return boolToState(reportChain.getOutBits(reportPath).get(FILL_STATE_IN_NDX));
216 /** get value of drain stage stopped wire */
217 public boolean getStopped() {
218 shiftReport(true, false);
219 return reportChain.getOutBits(reportPath).get(STOPPED_IN_NDX);
222 public String getReportString() {
223 StringBuffer sb = new StringBuffer();
224 sb.append("Stopper's prev state: ");
225 sb.append(getPrevStateWire()+"\n");
226 sb.append("Stopper's fill stage: ");
227 sb.append(getFillStateWire()+"\n");
228 sb.append("Stopper's stopped: ");
229 sb.append(getStopped()+"\n");
230 return sb.toString();
233 /** construct a ProperStopper */
234 public ProperStopper(String name,
236 ChainControl controlChain,
237 ChainControl dataChain,
238 ChainControl reportChain,
242 String pathToCounter) {
244 this.controlPath = Marina.CONTROL_CHAIN+'.'+propInst;
245 this.dataPath = Marina.DATA_CHAIN+'.'+propInst;
246 this.reportPath = Marina.REPORT_CHAIN+'.'+propInst;
249 prefixInstNamesInPathWithX(propInst+'.'+captureClockRelPath)
250 +'.'+captureClockName;
251 this.clockHack = clockHack;
252 this.indenter = indenter;
253 this.pathToCounter = Marina.DATA_CHAIN+'.'+pathToCounter;
254 this.controlChain = controlChain;
255 this.dataChain = dataChain;
256 this.reportChain = reportChain;
259 /** Reset ProperStopper after the JTAG TRST has been pulsed */
260 public void resetAfterMasterClear() {
261 BitVector we = new BitVector(2, "write enable");
262 BitVector packet = new BitVector(MarinaPacket.PACKET_WIDTH, "packet");
264 packet.setFromLong(0);
265 BitVector wdta = we.cat(packet);
266 dataChain.setInBits(dataPath, wdta);
269 /** Insert one item into the fill stage.
270 * Fill stage must be empty.
271 * You must stop stopper before calling fill.
272 * exit state: block */
273 private void fill_(BitVector dta) {
276 int n = dta.getNumBits();
277 fatal(n!=(37+1+14), "fill: wrong num bits: "+n);
279 // make sure fill stage is empty
280 StateWireState myState = getFillStateWire();
281 fatal(myState!=StateWireState.EMPTY, "fill: fill stage already full");
283 idle(); // block = 1, go = 0
285 BitVector wrEn = new BitVector(2, "write enable");
287 dataChain.setInBits(dataPath, wrEn.cat(dta));
288 shiftData(false, true);
298 if (traceFill) prln(getReportString());
300 // if data chain is shifted in the future, don't write!
302 dataChain.setInBits(dataPath, wrEn.cat(dta));
305 if (traceFill) prln("End fill");
308 public void fill(BitVector dat) {
309 if (traceFill) prln("Begin fill. stopper="+name);
310 if (traceFill) prln("writing data: "+new MarinaPacket(dat));
314 public void fill(MarinaPacket mp) {
315 if (traceFill) prln("Begin fill. stopper="+name);
316 if (traceFill) prln("writing data: "+mp);
317 fill_(mp.toSingleBitVector());
320 /** Insert items from a list, one by one.
321 * You must stop stopper before calling fillMany()
322 * exit state: block */
323 public void fillMany(List<BitVector> data) {
324 prln("Begin fillMany. stopper="+name+" numWords="+data.size());
327 for (BitVector bv : data) {
328 if (traceFill) prln("fillStopperMany: writing word number: "+cnt++);
332 prln("end fillMany");
335 /** Remove one item from fill stage. Return that item.
336 * An item must be available.
337 * drain() will stop cleanly.
338 * exit state: stop */
339 public BitVector drain() {
340 stop(); // all zero, block = 0, go = 0
342 // make sure an item is available
343 StateWireState myState=getFillStateWire();
344 fatal(myState==StateWireState.EMPTY, "drain: fill stage empty");
346 return drainNoCheck();
349 /** Remove one item from fill stage. Return that item.
350 * Assume that an item is available.
352 * exit state: stop */
353 private BitVector drainNoCheck() {
354 shiftData(true, false);
356 // strip the two write enable bits
357 BitVector ans = dataChain.getOutBits(dataPath).get(2, 52);
360 clear(); // clear = 1
364 if (traceDrain) prln("drain stopper="+name+" data="+new MarinaPacket(ans));
368 /** Remove as many items as possible from the fill stage.
369 * drainStopperMany() will stop cleanly.
370 * exit state: stop */
371 public List<BitVector> drainMany() {
372 return drainMany(Integer.MAX_VALUE);
375 /** Remove up to maxNbItems items from the fill stage.
376 * drainStopperMany() will stop cleanly.
377 * exit state: stop */
378 public List<BitVector> drainMany(int maxNbItems) {
383 List<BitVector> ans = new ArrayList<BitVector>();
387 StateWireState myState=getFillStateWire();
390 if (traceDrain) prln(getReportString());
392 if (myState==StateWireState.EMPTY || cnt>=maxNbItems) break;
395 indenter.pr(" drain"+(maxNbItems==0?"":"Many")+
396 ": reading word"+(maxNbItems==0?":":" number "+cnt+
397 "/"+(maxNbItems==Integer.MAX_VALUE
398 ?"unlimited":("at-most-"+maxNbItems))+": "));
400 BitVector d = drainNoCheck();
402 prln(" got "+new MarinaPacket(d));
407 prln("end drainMany, got "+ans.size()+" items");
413 // proper stopper ring occupancy bits
414 //southFif@1.upDown8w@1.weakStag@18.scanEx1@0 REPORT chain
415 //18, 22, 19, 23, 20, 24, 21, 25
416 //northFif@1.upDown8w@2...
417 // south fifo tap stage:
418 // southFif@1.tapPropS@1.tapStage@2.scanEx1@0 (also REPORT chain)
421 * (Note by Bill and Adam: Ivan has struck again!)
422 * As of 05 March 2009 the new bits are:
423 * Block Extra Fill Go Clear Silent
424 * => Note: "Extra" gets fed to the mux in the counter
425 * that selects the frequency output that goes off-chip
427 * Caution: Ivan changes the order of the ProperStopper control bits
428 * from chip to chip. Here is the current order for Marina
430 * Block, Fill, Go, Silent, Clear
432 * The old bit order for Infinity was: Fill, Block, Clear, Silent, Go
434 private static enum CommandCodes {
435 RUN ("000100","010100"),
436 IDLE ("100000","110000"),
437 FILL ("101000","111000"),
438 BLOCK ("100100","110100"),
439 STOP ("000000","010000"),
440 CLEAR ("100010","110010"),
441 SOURCE ("001100","011100"),
442 STOPSOURCE ("001000","011000"),
443 SINK ("000101","010101"),
444 STOPSINK ("000001","010001");
445 private BitVector scanBits0;
446 private BitVector scanBits1;
447 CommandCodes(String bits0,String bits1) {
448 scanBits0 = new BitVector(bits0,"CommandCodes");
449 scanBits1 = new BitVector(bits1,"CommandCodes");
451 public BitVector bits(boolean extra) {
452 return extra ? scanBits1 : scanBits0;