Merge marina project in subdirectory marina/
[fleet.git] / marina / testCode / com / sun / vlsi / chips / marina / test / ProperStopper.java
1 package com.sun.vlsi.chips.marina.test;
2 import java.util.ArrayList;
3 import java.util.List;
4
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.async.test.VerilogModel;
11 import com.sun.vlsi.chips.marina.test.MarinaUtils.StateWireState;
12
13 public class ProperStopper {
14     // position of strobes in the control chain
15     private static final int BLOCK_STROBE_NDX = 0;
16     private static final int FILL_STROBE_NDX = 1;
17     private static final int GO_STROBE_NDX = 2;
18     private static final int SILENT_STROBE_NDX = 3;
19     private static final int CLEAR_STROBE_NDX = 4;
20     private static final int GENERAL_PURPOSE_STROBE_NDX = 5;
21         
22     // position of inputs in report chain
23     private static final int PREV_STATE_IN_NDX = 0;
24     private static final int FILL_STROBE_IN_NDX = 1;
25     private static final int FILL_STATE_IN_NDX = 2;
26     private static final int STOPPED_IN_NDX = 3;
27         
28     private final String name;
29     //private final String captureClockRelPath = "fillStag@1.gaspFill@0.fillScan@1";
30     private final String captureClockRelPath = "fillStag@1";
31     // test library direct write mode doesn't understand per register write 
32     // enables. We get simulation to work by toggling write clock.
33     private final boolean clockHack;
34     private final String captureClockName = "sx[4]";
35
36     /*
37     private boolean traceFill = true;
38     private boolean traceDrain = true;
39     */
40     private boolean traceFill = false;
41     private boolean traceDrain = false;
42         
43     private final String controlChain, controlPath, 
44         dataChain, dataPath, 
45         reportChain, reportPath;
46     private final String captureClock;
47     private final ChainControls cc;
48     private final ChipModel model;
49     private final Indenter indenter;
50
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); }
54         
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();
62         sb.append('x');
63         for (int i=0; i<path.length(); i++) {
64             char c = path.charAt(i);
65             sb.append(c);
66             if (c=='.')  sb.append('x');
67         }
68         return sb.toString();
69     }
70   
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");
75     }
76     private void shiftData(boolean readEnable, boolean writeEnable) {
77         //System.out.println("start shiftdata");
78         cc.shift(dataChain, readEnable, writeEnable);
79         if (writeEnable) {
80             if (clockHack && model instanceof NanosimModel) {
81                 NanosimModel nanoModel = (NanosimModel) model;
82                 nanoModel.setNodeState(captureClock, 1);
83                 nanoModel.waitNS(1);
84                 nanoModel.setNodeState(captureClock, 0);
85             } else if (clockHack && model instanceof VerilogModel) {
86                 VerilogModel nanoModel = (VerilogModel) model;
87                 nanoModel.setNodeState(captureClock, 1);
88                 nanoModel.waitNS(1);
89                 nanoModel.setNodeState(captureClock, 0);
90             }
91         }
92         //System.out.println("  end shiftdata");
93     }
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");
98     }
99
100     private StateWireState boolToState(boolean b) {
101         return b ? StateWireState.FULL : StateWireState.EMPTY;
102     }
103     // The first 5 bits of the control chain control the fill and drain stages
104     private void setFillDrainControl(BitVector fdCtl) {
105         fatal(fdCtl.getNumBits()!=6, "expect 6 proper stopper control bits");
106         BitVector val = cc.getInBits(controlPath);
107         for (int i=0; i<fdCtl.getNumBits(); i++) {
108             val.set(i, fdCtl.get(i));
109         }
110         cc.setInBits(controlPath, val);
111         shiftControl(false, true);
112     }
113     // The last bit of the control chain controls the general purpose
114     // output
115     public void setGeneralPurposeOutput(Boolean b) {
116         BitVector val = cc.getInBits(controlPath);
117         val.set(GENERAL_PURPOSE_STROBE_NDX,b);
118         shiftControl(false, true);
119     }
120     
121     //-------------------------- public methods ----------------------------
122
123     /** Put stopper in RUN state */
124     public void run() {
125         setFillDrainControl(CommandCodes.RUN.bits());
126     }
127     /** Put stopper in IDLE state */
128     public void idle() {
129         setFillDrainControl(CommandCodes.IDLE.bits());
130     }
131     /** Put stopper in FILL state */
132     public void fill() {
133         setFillDrainControl(CommandCodes.FILL.bits());
134     }
135     /** Put stopper in BLOCK state */
136     public void block() {
137         setFillDrainControl(CommandCodes.BLOCK.bits());
138     }
139     /** Put stopper in STOP state */
140     public void stop() {
141         setFillDrainControl(CommandCodes.STOP.bits());
142     }
143     /** Put stopper in CLEAR state */
144     public void clear() {
145         setFillDrainControl(CommandCodes.CLEAR.bits());
146     }
147     /** Put stopper in SOURCE state */
148     public void source() {
149         setFillDrainControl(CommandCodes.SOURCE.bits());
150     }
151     /** Put stopper in STOPSOURCE state */
152     public void stopSource() {
153         setFillDrainControl(CommandCodes.STOPSOURCE.bits());
154     }
155     /** Put stopper in SINK state */
156     public void sink() {
157         setFillDrainControl(CommandCodes.SINK.bits());
158     }
159     /** Put stopper in STOPSINK state */
160     public void stopSink() {
161         setFillDrainControl(CommandCodes.STOPSINK.bits());
162     }
163
164     /** Stop a running stopper in order to add items.  Ensure that we don't
165      * lose the item in the fill stage.  
166      * Exit state: block */
167     public void stopToFill() {
168         stop();                                 // go = 0
169         idle();                                 // block = 1
170         block();                                // go = 1
171         //      idle();                                 // go = 0
172     }
173
174     /** get value of the state wire preceding the fill stage */
175     public StateWireState getPrevStateWire() {
176         shiftReport(true, false);
177         BitVector b = cc.getOutBits(reportPath);
178         int n = b.getNumBits(); 
179         fatal(n!=4, "Bad number of Stopper report bits: "+n);
180         return boolToState(cc.getOutBits(reportPath).get(PREV_STATE_IN_NDX));
181     }
182
183     /** get the value of drain stage fill wire.
184      * The fill wire will be interesting if we doubt that the
185      * scan chain works. */
186     public boolean getFillStrobe() {
187         shiftReport(true, false);
188         return cc.getOutBits(reportPath).get(FILL_STROBE_IN_NDX);
189     }
190
191     /** get value of state wire between the fill and drain stages */
192     public StateWireState getFillStateWire() {
193         shiftReport(true, false);
194         return boolToState(cc.getOutBits(reportPath).get(FILL_STATE_IN_NDX));
195     }
196
197     /** get value of drain stage stopped wire */
198     public boolean getStopped() {
199         shiftReport(true, false);
200         return cc.getOutBits(reportPath).get(STOPPED_IN_NDX);
201     }
202
203     public String getReportString() {
204         StringBuffer sb = new StringBuffer();
205         sb.append("Stopper's prev state: ");
206         sb.append(getPrevStateWire()+"\n");
207         sb.append("Stopper's fill stage: ");
208         sb.append(getFillStateWire()+"\n");
209         sb.append("Stopper's stopped: ");
210         sb.append(getStopped()+"\n");
211         return sb.toString();
212     }
213
214     /** construct a ProperStopper */
215     public ProperStopper(String name,
216                          String propInst,
217                          String controlChain, String dataChain, 
218                          String reportChain,
219                          ChainControls cc, ChipModel model,
220                          boolean clockHack,
221                          Indenter indenter) {
222         this.name = name;
223         this.controlChain = controlChain;
224         this.controlPath = controlChain+'.'+propInst;
225         this.dataChain = dataChain;
226         this.dataPath = dataChain+'.'+propInst;
227         this.reportChain = reportChain;
228         this.reportPath = reportChain+'.'+propInst;
229         this.model = model;
230         this.captureClock = 
231             prefixInstNamesInPathWithX(propInst+'.'+captureClockRelPath)
232             +'.'+captureClockName;
233         this.cc = cc;
234         this.clockHack = clockHack;
235         this.indenter = indenter;
236     }
237
238     /** Reset ProperStopper after the JTAG TRST has been pulsed */
239     public void resetAfterMasterClear() {
240         BitVector we = new BitVector(2, "write enable");
241         BitVector packet = new BitVector(MarinaPacket.PACKET_WIDTH, "packet");
242         we.setFromLong(0);
243         packet.setFromLong(0);
244         BitVector wdta = we.cat(packet);
245         cc.setInBits(dataPath, wdta);
246     }
247     
248     /** Insert one item into the fill stage.
249      * Fill stage must be empty. 
250      * You must stop stopper before calling fill.
251      * exit state: block */
252     private void fill_(BitVector dta) {
253         adjustIndent(2);
254         
255         int n = dta.getNumBits();
256         fatal(n!=(37+1+14), "fill: wrong num bits: "+n);
257         
258         // make sure fill stage is empty
259         StateWireState myState = getFillStateWire();
260         fatal(myState!=StateWireState.EMPTY, "fill: fill stage already full");
261         
262         idle();                                 // block = 1, go = 0
263
264         BitVector wrEn = new BitVector(2, "write enable");
265         wrEn.setFromLong(3);
266         cc.setInBits(dataPath, wrEn.cat(dta));
267         shiftData(false, true);
268         
269         fill();                                 // fill = 1
270         idle();                                 // fill = 0
271         block();                                // go = 1
272         //      idle();
273         
274         model.waitNS(5);
275
276         // debugging
277         if (traceFill) prln(getReportString());
278         
279         // if data chain is shifted in the future, don't write!
280         wrEn.setFromLong(0);
281         cc.setInBits(dataPath, wrEn.cat(dta));
282         
283         adjustIndent(-2);
284         if (traceFill) prln("End fill");
285     }
286
287     public void fill(BitVector dat) {
288         if (traceFill) prln("Begin fill. stopper="+name);
289         if (traceFill) prln("writing data: "+new MarinaPacket(dat));
290         fill_(dat);
291     }
292
293     public void fill(MarinaPacket mp) {
294         if (traceFill) prln("Begin fill. stopper="+name);
295         if (traceFill) prln("writing data: "+mp);
296         fill_(mp.toSingleBitVector());
297     }
298
299     /** Insert items from a list, one by one. 
300      * You must stop stopper before calling fillMany()
301      * exit state: block */
302     public void fillMany(List<BitVector> data) {
303         prln("Begin fillMany. stopper="+name+" numWords="+data.size());
304         adjustIndent(2);
305         int cnt = 0;
306         for (BitVector bv : data) {
307             if (traceFill) prln("fillStopperMany: writing word number: "+cnt++);
308             fill(bv);
309         }
310         adjustIndent(-2);
311         prln("end fillMany");
312     }
313
314     /** Remove one item from fill stage. Return that item.
315      * An item must be available.
316      * drain() will stop cleanly.
317      * exit state: stop */
318     public BitVector drain() {
319         stop();                                 // all zero, block = 0, go = 0
320         
321         // make sure an item is available
322         StateWireState myState=getFillStateWire();
323         fatal(myState==StateWireState.EMPTY, "drain: fill stage empty");
324
325         return drainNoCheck();
326     }
327
328     /** Remove one item from fill stage. Return that item.
329      * Assume that an item is available. 
330      * entry state: stop
331      * exit state: stop */
332     private BitVector drainNoCheck() {
333         shiftData(true, false);
334
335         // strip the two write enable bits
336         BitVector ans = cc.getOutBits(dataPath).get(2, 52);
337
338         idle();                                 // block = 1
339         clear();                                // clear = 1
340         idle();                                 // clear = 0
341         stop();                                 // block = 0
342
343         if (traceDrain) prln("drain stopper="+name+" data="+new MarinaPacket(ans));
344         return ans;
345     }
346
347     /** Remove as many items as possible from the fill stage.
348      * drainStopperMany() will stop cleanly.
349      * exit state: stop */
350     public List<BitVector> drainMany() {
351         return drainMany(Integer.MAX_VALUE);
352     }
353
354     /** Remove up to maxNbItems items from the fill stage.
355      * drainStopperMany() will stop cleanly.
356      * exit state: stop */
357     public List<BitVector> drainMany(int maxNbItems) {
358         adjustIndent(2);
359         
360         stop();
361         
362         List<BitVector> ans = new ArrayList<BitVector>();
363         
364         int cnt = 0;
365         while (true) {
366             StateWireState myState=getFillStateWire();
367
368             // debugging
369             if (traceDrain) prln(getReportString());
370
371             if (myState==StateWireState.EMPTY || cnt>=maxNbItems) break;
372                 
373             cnt++;
374             indenter.pr("  drain"+(maxNbItems==0?"":"Many")+
375                         ": reading word"+(maxNbItems==0?":":" number "+cnt+
376                         "/"+(maxNbItems==Integer.MAX_VALUE
377                              ?"unlimited":("at-most-"+maxNbItems))+": "));
378
379             BitVector d = drainNoCheck();
380             if (maxNbItems>1)
381                 prln("  got "+new MarinaPacket(d));
382
383             ans.add(d);
384         }
385         
386         prln("end drainMany, got "+ans.size()+" items");
387         adjustIndent(-2);
388         
389         return ans;
390     }
391
392
393     /**
394      * (Note by Bill and Adam: Ivan has struck again!)
395      * As of 05 March 2009 the new bits are:
396      *    Block Extra Fill Go Clear Silent
397      *      => Note: "Extra" gets fed to the mux in the counter
398      *         that selects the frequency output that goes off-chip
399      *
400      * Caution: Ivan changes the order of the ProperStopper control bits 
401      * from chip to chip.  Here is the current order for Marina
402      * as of 14 Aug 2008: 
403      *  Block, Fill, Go, Silent, Clear
404      *
405      *  The old bit order for Infinity was: Fill, Block, Clear, Silent, Go
406      */
407     private static enum CommandCodes {
408         RUN        ("000100"),
409             IDLE       ("100000"),
410             FILL       ("101000"),
411             BLOCK      ("100100"),
412             STOP       ("000000"),
413             CLEAR      ("100010"),
414             SOURCE     ("001100"),
415             STOPSOURCE ("001000"),
416             SINK       ("000101"),
417             STOPSINK   ("000001");
418         private BitVector scanBits;
419         CommandCodes(String bits) {
420             scanBits = new BitVector(bits,"CommandCodes");
421         }
422         public BitVector bits() {return scanBits;}
423     }
424
425 }