get rid of ChainControls
[fleet.git] / src / edu / berkeley / fleet / marina / ProperStopper.java
1 package edu.berkeley.fleet.marina;
2 import com.sun.electric.tool.simulation.test.*;
3 import java.util.ArrayList;
4 import java.util.List;
5 import edu.berkeley.fleet.marina.MarinaUtils.StateWireState;
6
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;
15         
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;
21         
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]";
29
30     /*
31     private boolean traceFill = true;
32     private boolean traceDrain = true;
33     */
34     private boolean traceFill = false;
35     private boolean traceDrain = false;
36         
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;
44
45     private final String pathToCounter;
46
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); }
50         
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();
58         sb.append('x');
59         for (int i=0; i<path.length(); i++) {
60             char c = path.charAt(i);
61             sb.append(c);
62             if (c=='.')  sb.append('x');
63         }
64         return sb.toString();
65     }
66   
67     private void shiftControl(boolean readEnable, boolean writeEnable) {
68         controlChain.shift(Marina.CONTROL_CHAIN, readEnable, writeEnable);
69     }
70     private void shiftData(boolean readEnable, boolean writeEnable) {
71         dataChain.shift(Marina.DATA_CHAIN, readEnable, writeEnable);
72         if (writeEnable) {
73             if (clockHack && model instanceof NanosimModel) {
74                 NanosimModel nanoModel = (NanosimModel) model;
75                 nanoModel.setNodeState(captureClock, 1);
76                 nanoModel.waitNS(1);
77                 nanoModel.setNodeState(captureClock, 0);
78             } else if (clockHack && model instanceof VerilogModel) {
79                 VerilogModel nanoModel = (VerilogModel) model;
80                 nanoModel.setNodeState(captureClock, 1);
81                 nanoModel.waitNS(1);
82                 nanoModel.setNodeState(captureClock, 0);
83             }
84         }
85     }
86     private void shiftReport(boolean readEnable, boolean writeEnable) {
87         reportChain.shift(Marina.REPORT_CHAIN, readEnable, writeEnable);
88     }
89
90     private StateWireState boolToState(boolean b) {
91         return b ? StateWireState.FULL : StateWireState.EMPTY;
92     }
93
94     private CommandCodes fdcstate = null;
95
96     public void setCounterEnable(boolean enable) {
97         this.extra = enable;
98         setFillDrainControl(fdcstate);
99     }
100
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);
108     }
109
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();
116     }
117
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);
121         fdcstate = ccc;
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));
126         }
127         controlChain.setInBits(controlPath, val);
128         shiftControl(false, true);
129     }
130     // The last bit of the control chain controls the general purpose
131     // output
132     public void setGeneralPurposeOutput(Boolean b) {
133         BitVector val = controlChain.getInBits(controlPath);
134         val.set(GENERAL_PURPOSE_STROBE_NDX,b);
135         shiftControl(false, true);
136     }
137     
138     //-------------------------- public methods ----------------------------
139
140     /** Put stopper in RUN state */
141     public void run() {
142         setFillDrainControl(CommandCodes.RUN);
143     }
144     /** Put stopper in IDLE state */
145     public void idle() {
146         setFillDrainControl(CommandCodes.IDLE);
147     }
148     /** Put stopper in FILL state */
149     public void fill() {
150         setFillDrainControl(CommandCodes.FILL);
151     }
152     /** Put stopper in BLOCK state */
153     public void block() {
154         setFillDrainControl(CommandCodes.BLOCK);
155     }
156     /** Put stopper in STOP state */
157     public void stop() {
158         setFillDrainControl(CommandCodes.STOP);
159     }
160     /** Put stopper in CLEAR state */
161     public void clear() {
162         setFillDrainControl(CommandCodes.CLEAR);
163     }
164     /** Put stopper in SOURCE state */
165     public void source() {
166         setFillDrainControl(CommandCodes.SOURCE);
167     }
168     /** Put stopper in STOPSOURCE state */
169     public void stopSource() {
170         setFillDrainControl(CommandCodes.STOPSOURCE);
171     }
172     /** Put stopper in SINK state */
173     public void sink() {
174         setFillDrainControl(CommandCodes.SINK);
175     }
176     /** Put stopper in STOPSINK state */
177     public void stopSink() {
178         setFillDrainControl(CommandCodes.STOPSINK);
179     }
180
181     public boolean extra = false;
182
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() {
187         stop();                                 // go = 0
188         idle();                                 // block = 1
189         block();                                // go = 1
190         //      idle();                                 // go = 0
191     }
192
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));
200     }
201
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);
208     }
209
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));
214     }
215
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);
220     }
221
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();
231     }
232
233     /** construct a ProperStopper */
234     public ProperStopper(String name,
235                          String propInst,
236                          ChainControl controlChain,
237                          ChainControl dataChain,
238                          ChainControl reportChain,
239                          ChipModel model,
240                          boolean clockHack,
241                          Indenter indenter,
242                          String pathToCounter) {
243         this.name = name;
244         this.controlPath = Marina.CONTROL_CHAIN+'.'+propInst;
245         this.dataPath = Marina.DATA_CHAIN+'.'+propInst;
246         this.reportPath = Marina.REPORT_CHAIN+'.'+propInst;
247         this.model = model;
248         this.captureClock = 
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;
257     }
258
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");
263         we.setFromLong(0);
264         packet.setFromLong(0);
265         BitVector wdta = we.cat(packet);
266         dataChain.setInBits(dataPath, wdta);
267     }
268     
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) {
274         adjustIndent(2);
275         
276         int n = dta.getNumBits();
277         fatal(n!=(37+1+14), "fill: wrong num bits: "+n);
278         
279         // make sure fill stage is empty
280         StateWireState myState = getFillStateWire();
281         fatal(myState!=StateWireState.EMPTY, "fill: fill stage already full");
282         
283         idle();                                 // block = 1, go = 0
284
285         BitVector wrEn = new BitVector(2, "write enable");
286         wrEn.setFromLong(3);
287         dataChain.setInBits(dataPath, wrEn.cat(dta));
288         shiftData(false, true);
289         
290         fill();                                 // fill = 1
291         idle();                                 // fill = 0
292         block();                                // go = 1
293         //      idle();
294         
295         model.waitNS(5);
296
297         // debugging
298         if (traceFill) prln(getReportString());
299         
300         // if data chain is shifted in the future, don't write!
301         wrEn.setFromLong(0);
302         dataChain.setInBits(dataPath, wrEn.cat(dta));
303         
304         adjustIndent(-2);
305         if (traceFill) prln("End fill");
306     }
307
308     public void fill(BitVector dat) {
309         if (traceFill) prln("Begin fill. stopper="+name);
310         if (traceFill) prln("writing data: "+new MarinaPacket(dat));
311         fill_(dat);
312     }
313
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());
318     }
319
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());
325         adjustIndent(2);
326         int cnt = 0;
327         for (BitVector bv : data) {
328             if (traceFill) prln("fillStopperMany: writing word number: "+cnt++);
329             fill(bv);
330         }
331         adjustIndent(-2);
332         prln("end fillMany");
333     }
334
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
341         
342         // make sure an item is available
343         StateWireState myState=getFillStateWire();
344         fatal(myState==StateWireState.EMPTY, "drain: fill stage empty");
345
346         return drainNoCheck();
347     }
348
349     /** Remove one item from fill stage. Return that item.
350      * Assume that an item is available. 
351      * entry state: stop
352      * exit state: stop */
353     private BitVector drainNoCheck() {
354         shiftData(true, false);
355
356         // strip the two write enable bits
357         BitVector ans = dataChain.getOutBits(dataPath).get(2, 52);
358
359         idle();                                 // block = 1
360         clear();                                // clear = 1
361         idle();                                 // clear = 0
362         stop();                                 // block = 0
363
364         if (traceDrain) prln("drain stopper="+name+" data="+new MarinaPacket(ans));
365         return ans;
366     }
367
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);
373     }
374
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) {
379         adjustIndent(2);
380         
381         stop();
382         
383         List<BitVector> ans = new ArrayList<BitVector>();
384         
385         int cnt = 0;
386         while (true) {
387             StateWireState myState=getFillStateWire();
388
389             // debugging
390             if (traceDrain) prln(getReportString());
391
392             if (myState==StateWireState.EMPTY || cnt>=maxNbItems) break;
393                 
394             cnt++;
395             indenter.pr("  drain"+(maxNbItems==0?"":"Many")+
396                         ": reading word"+(maxNbItems==0?":":" number "+cnt+
397                         "/"+(maxNbItems==Integer.MAX_VALUE
398                              ?"unlimited":("at-most-"+maxNbItems))+": "));
399
400             BitVector d = drainNoCheck();
401             if (maxNbItems>1)
402                 prln("  got "+new MarinaPacket(d));
403
404             ans.add(d);
405         }
406         
407         prln("end drainMany, got "+ans.size()+" items");
408         adjustIndent(-2);
409         
410         return ans;
411     }
412
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)
419
420     /**
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
426      *
427      * Caution: Ivan changes the order of the ProperStopper control bits 
428      * from chip to chip.  Here is the current order for Marina
429      * as of 14 Aug 2008: 
430      *  Block, Fill, Go, Silent, Clear
431      *
432      *  The old bit order for Infinity was: Fill, Block, Clear, Silent, Go
433      */
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");
450         }
451         public BitVector bits(boolean extra) {
452             return extra ? scanBits1 : scanBits0;
453         }
454     }
455
456 }