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