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