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