revamp demos
[slipway.git] / src / edu / berkeley / slipway / demos / FastestMicropipelineFifoDemo.java
1 package edu.berkeley.slipway.demos;
2
3 import java.io.*;
4 import java.util.*;
5 import java.awt.*;
6 import com.atmel.fpslic.*;
7 import edu.berkeley.slipway.*;
8 import edu.berkeley.slipway.gui.*;
9 import static com.atmel.fpslic.FpslicConstants.*;
10
11 public class FastestMicropipelineFifoDemo extends MicropipelineFifoDemo {
12
13     public static void main(String[] s) throws Exception {
14         new FastestMicropipelineFifoDemo().mainx(s);
15     }
16
17     //////////////////////////////////////////////////////////////////////////////
18
19     public FpslicDevice.Cell start;
20     public FastestMicropipelineFifoDemo() throws Exception {
21         start = fpslic.cell(21, 21);
22     }
23
24     protected FpslicDevice.Cell masterCell() { return start.north().north(); }
25
26     private int dividers = 0;
27     protected int numDivisors() { return dividers; }
28
29     /** drive this plane high to cause the "master" fifo stage to pause (hold current value) */
30     public static final int PLANE_PAUSE_MASTER_WHEN_HIGH  = L0;
31
32     /** drive this plane high to cause the "slave" fifo stages to pause (hold current value) */
33     public static final int PLANE_PAUSE_SLAVES_WHEN_HIGH  = L1;
34
35     /** drive this plane low to cause the "slave" fifo stages to pause (hold current value) */
36     public static final int PLANE_PAUSE_SLAVES_WHEN_LOW   = L2;
37
38     /** drive this plane low to cause all fifo stages to reset (set current value to 0) */
39     public static final int PLANE_RESET_ALL_WHEN_LOW      = L3;
40
41     /** unpauses the master stage */
42     public void unPauseMaster() {
43         fpslic.cell(0,PLANE_PAUSE_MASTER_WHEN_HIGH).ylut(0x00);
44         fpslic.flush();
45     }
46
47     /** unpauses the slave stages */
48     public void unPauseSlaves() {
49         fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_HIGH).ylut(0x00);
50         fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_LOW).ylut(0xff);
51         fpslic.flush();
52     }
53
54     /** pauses the master stage */
55     public void pauseMaster() {
56         fpslic.cell(0,PLANE_PAUSE_MASTER_WHEN_HIGH).ylut(0xff);
57         fpslic.flush();
58     }
59
60     /** pauses the slave stages */
61     public void pauseSlaves() {
62         fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_HIGH).ylut(0xff);
63         fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_LOW).ylut(0x00);
64         fpslic.flush();
65     }
66
67     /** reset all stages (should be paused before doing this) */
68     public void resetAll() {
69         fpslic.cell(0,PLANE_RESET_ALL_WHEN_LOW).ylut(0x00);
70         fpslic.flush();
71         fpslic.cell(0,PLANE_RESET_ALL_WHEN_LOW).ylut(0xff);
72         fpslic.flush();
73     }
74
75     /** configures the ylut of the cell at (0,plane) to drive plane "plane" across the entire chip */
76     private void drivePlane(int plane) {
77         for(int i=0; i<=23; i++){
78             FpslicDevice.Cell c = fpslic.cell(0, i);
79             c.h(plane, true);
80             c.v(plane, true);
81             if (c.vwire(plane).south() != null)
82                 c.vwire(plane).south().drives(c.vwire(plane), true);
83             for(FpslicDevice.SectorWire sw = c.hwire(plane).east();
84                 sw!=null;
85                 sw=sw.east())
86                 sw.west().drives(sw, true);
87         }
88         fpslic.cell(0, plane-L0).c(YLUT);
89         fpslic.cell(0, plane-L0).b(false);
90         fpslic.cell(0, plane-L0).f(false);
91         fpslic.cell(0, plane-L0).out(plane, true);
92     }
93
94     /** causes the master cell's successor output to be set to the given value */
95     protected void forceMasterSuccessor(boolean high) {
96         masterCell().ylut(0xff);
97         masterCell().xo(false);
98         masterCell().yo(false);
99         masterCell().xlut(high ? 0xff : 0x00);
100         fpslic.flush();
101     }
102
103     /** causes the master cell's successor output to resume normal functionality, leaving it in state "state" */
104     protected void unForceMasterSuccessor(boolean state) {
105         pauseSlaves();
106         masterCell().xo(true);
107         masterCell().yo(true);
108         masterCell().xlut(LUT_Z);
109         fpslic.flush();
110         masterCell().ylut(!state ? 0x00 : 0xff);
111         fpslic.flush();
112         pauseMaster();
113         masterCell().ylut((LUT_SELF & ~LUT_OTHER) |
114                        (LUT_Z & ~LUT_OTHER) |
115                        (LUT_Z & LUT_SELF));
116         fpslic.flush();
117         unPauseMaster();
118         unPauseSlaves();
119     }
120
121
122     protected int init(int size) {
123         return init(size, this.start);
124     }
125     protected int init(int size, FpslicDevice.Cell start) {
126         for(int x=1; x<24; x++)
127             for(int y=0; y<24; y++) {
128                 FpslicDevice.Cell c = fpslic.cell(x, y);
129                 c.xlut(0x00);
130                 c.ylut(0x00);
131                 c.b(false);
132                 c.f(false);
133                 c.c(YLUT);
134             }
135         ExperimentUtils.setupScanCell(fpslic);
136         fpslic.flush();
137
138         this.start = start;
139         drivePlane(L0);
140         drivePlane(L1);
141         drivePlane(L2);
142         drivePlane(L3);
143
144         int rsize = 0;
145
146         // create a column of dividers
147         FpslicDevice.Cell div;
148
149         if (size == 4) {
150             rsize = 4;
151             pipe(start.west().north(), start.west().north().north(), new int[] { NE, SOUTH, NW, SOUTH });
152             div = start.east();
153             // annoying "bridge cell", because dividers must take input from the north
154             div.north().yo(start.north());
155             div.north().xo(start.north());
156         } else {
157             rsize = size-createPipeline(start, true, size-4, false);
158             unPauseMaster();
159             unPauseSlaves();
160             pipe(start.west().north(), start.west(), new int[] { NE, EAST, SW, SOUTH });
161             div = start.east();
162             // annoying "bridge cell", because dividers must take input from the north
163             div.north().yo(start.north());
164             div.north().xo(start.north());
165         }
166
167         dividers = 0;
168         while(div != null) {
169             FpslicDevice.Cell xdiv = ExperimentUtils.divider(div);
170             dividers++;
171             if (xdiv==null) break;
172             div = xdiv;
173         }
174         div = div.south().east();  // lower-right hand corner of the last divider placed
175         if (dividers < 10) {
176         div.east().yo(div);
177         div = div.east();
178         while(div.north() != null) {
179             div.north().yo(div);
180             div = div.north();
181         }
182         div.xo(div.south());
183         div.east().yo(div);
184         div.east().xo(div);
185         div = div.east();
186         div.east().xo(div);
187         div.east().yo(div);
188         div.south().yo(div);
189         div = div.south();
190         while(div != null && dividers < 10) {
191             FpslicDevice.Cell xdiv = ExperimentUtils.divider(div);
192             dividers++;
193             if (xdiv==null) { div = div.south().east(); break; }
194             if (dividers >= 10)  { div = div.south().east(); break; }
195             div = xdiv;
196         }
197         }
198         while(div.south() != null) {
199             div.south().yo(div);
200             div = div.south();
201         }
202         while(div.east() != null) {
203             div.east().yo(div);
204             div = div.east();
205         }
206         // assumption that we wind up in the lower-right-hand corner
207
208         return rsize;
209     }
210
211     //////////////////////////////////////////////////////////////////////////////
212
213     /** create a pipeline starting at cell "c", with predecessor "prev", and move in the directions
214      *  specified by "dirs" */
215     private FpslicDevice.Cell pipe(FpslicDevice.Cell c, FpslicDevice.Cell prev, int[] dirs) {
216         for(int i=0; i<dirs.length; i++) {
217             FpslicDevice.Cell next = c.dir(dirs[i]);
218             micropipelineStage(c, prev, next);
219             prev = c;
220             c = next;
221         }
222         return c;
223     }
224
225     /** this is really ugly and I no longer understand it */
226     private int createPipeline(FpslicDevice.Cell c, boolean downward, int length, boolean start) {
227         boolean stop = false;
228         do {
229             if (downward) {
230                 if (c.row < 6) {
231                     if (length < 8+4) { stop = true; break; }
232                     length -= 8;
233                     c = pipe(c, c.north(), new int[] { SW, EAST, SW, WEST, NW, NORTH });
234                     c = c.se();
235                     c = pipe(c, c.north(), new int[] { NE, NORTH });
236                     c = c.sw().west();
237                     downward = false;
238                 } else {
239                     if (length < 8+4) { stop = true; break; }
240                     length -= 8;
241                     c = micropipelineStage(c, c.north(), c.sw());
242                     c = micropipelineStage(c, c.ne(),    c.south());
243                     c = micropipelineStage(c, c.north(), c.se());
244                     c = micropipelineStage(c, c.nw(),    c.south());
245                     c = c.nw();
246                     c = micropipelineStage(c, c.south(), c.ne());
247                     c = micropipelineStage(c, c.sw(),    c.north());
248                     c = micropipelineStage(c, c.south(), c.nw());
249                     micropipelineStage(c, c.se(),    c.north());
250                     c = c.south().south().south().south().east();
251                 }
252             } else {
253                 if (c.row > c.fpslic().getHeight()-7) {
254                     if (length < 8+4) { stop = true; break; }
255                     length -= 8;
256                     c = pipe(c, c.south(), new int[] { NW, SOUTH });
257                     c = c.nw();
258                     c = pipe(c, c.south(), new int[] { NE, EAST, SE, WEST, SE, SOUTH });
259                     c = c.nw().west();
260                     downward = true;
261                 } else {
262                     if (length < 8+4) { stop = true; break; }
263                     length -= 8;
264                     FpslicDevice.Cell ret = c = pipe(c, c.south(), new int[] { NE, NORTH, NW, NORTH });
265                     c = c.se();
266                     c = pipe(c, c.north(), new int[] { SW, SOUTH, SE, SOUTH });
267                     c = ret;
268                 }
269             }
270         } while(false);
271         if (stop) {
272             length -= 4;
273             if (downward) {
274                 c = micropipelineStage(c, c.north(), c.sw());
275                 c = micropipelineStage(c, c.ne(), c.west());
276                 c = micropipelineStage(c, c.east(), c.ne());
277                 c = micropipelineStage(c, c.sw(), c.north());
278             } else {
279                 c = pipe(c, c.south(), new int[] { NW, EAST, SE, SOUTH });
280             }
281             return length;
282         } else {
283             return createPipeline(c, downward, length, false);
284         }
285     }
286
287     private FpslicDevice.Cell micropipelineStage(FpslicDevice.Cell c,
288                                                  FpslicDevice.Cell prev,
289                                                  FpslicDevice.Cell next) {
290         boolean polarity = false;
291         switch(c.dir(next)) {
292             case NORTH: case SOUTH: case EAST: case WEST:
293                 switch (c.dir(prev)) {
294                     case NORTH: case SOUTH: case EAST: case WEST: throw new Error("cannot have prev&next both use y");
295                 }
296                 polarity = false;
297                 break;
298             case NW: case SE: case SW: case NE:
299                 switch (c.dir(prev)) {
300                     case NW: case SE: case SW: case NE: throw new Error("cannot have prev&next both use x");
301                 }
302                 polarity = true;
303                 break;
304             default: throw new Error();
305         }
306
307         c.yi(polarity ? prev : next);
308         c.xi(polarity ? next : prev);
309
310         c.b(false);
311         c.f(false);
312         c.yo(true);
313         c.xo(true);
314         c.c(ZMUX);
315
316         c.wi(PLANE_RESET_ALL_WHEN_LOW);
317         c.t(TMUX_W_AND_FB);
318
319         for(int i=L0; i<=L3; i++) c.h(i, true);
320
321         if (!polarity) {
322             if (c.row==masterCell().row && c.col==masterCell().col) {
323                 c.zi(PLANE_PAUSE_MASTER_WHEN_HIGH);
324             } else {
325                 c.zi(PLANE_PAUSE_SLAVES_WHEN_HIGH);
326             }
327             c.ylut((LUT_SELF & ~LUT_OTHER) |
328                    (LUT_Z & ~LUT_OTHER) |
329                    (LUT_Z & LUT_SELF));
330             c.xlut(LUT_Z);
331         } else {
332             /*
333             // internally asymmetric
334             c.zi(PLANE_PAUSE_SLAVES_WHEN_LOW);
335             c.xlut((LUT_SELF & ~LUT_OTHER) |
336                    (LUT_Z & ~LUT_OTHER) |
337                    (LUT_Z & LUT_SELF));
338             c.ylut(LUT_Z);
339             */
340
341             // internally symmetric
342             c.zi(PLANE_PAUSE_SLAVES_WHEN_HIGH);
343             c.ylut((~LUT_SELF & LUT_OTHER) |
344                    (LUT_Z & ~LUT_SELF) |
345                    (LUT_Z & LUT_OTHER));
346             c.xlut(LUT_Z);
347         }
348         return next;
349     }
350
351
352
353 }