updates that were lying around but never got checked in; includes reorg of gui
[slipway.git] / src / edu / berkeley / slipway / demos / FastestMicropipelineFifoDemo.java
diff --git a/src/edu/berkeley/slipway/demos/FastestMicropipelineFifoDemo.java b/src/edu/berkeley/slipway/demos/FastestMicropipelineFifoDemo.java
new file mode 100644 (file)
index 0000000..509160d
--- /dev/null
@@ -0,0 +1,354 @@
+package edu.berkeley.slipway.demos;
+
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+import com.atmel.fpslic.*;
+import edu.berkeley.slipway.*;
+import edu.berkeley.slipway.gui.*;
+import edu.berkeley.slipway.util.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+
+public class FastestMicropipelineFifoDemo extends MicropipelineFifoDemo {
+
+    public static void main(String[] s) throws Exception {
+        new FastestMicropipelineFifoDemo().mainx(s);
+    }
+
+    //////////////////////////////////////////////////////////////////////////////
+
+    public FpslicDevice.Cell start;
+    public FastestMicropipelineFifoDemo() throws Exception {
+        start = fpslic.cell(21, 21);
+    }
+
+    protected FpslicDevice.Cell masterCell() { return start.north().north(); }
+
+    private int dividers = 0;
+    protected int numDivisors() { return dividers; }
+
+    /** drive this plane high to cause the "master" fifo stage to pause (hold current value) */
+    public static final int PLANE_PAUSE_MASTER_WHEN_HIGH  = L0;
+
+    /** drive this plane high to cause the "slave" fifo stages to pause (hold current value) */
+    public static final int PLANE_PAUSE_SLAVES_WHEN_HIGH  = L1;
+
+    /** drive this plane low to cause the "slave" fifo stages to pause (hold current value) */
+    public static final int PLANE_PAUSE_SLAVES_WHEN_LOW   = L2;
+
+    /** drive this plane low to cause all fifo stages to reset (set current value to 0) */
+    public static final int PLANE_RESET_ALL_WHEN_LOW      = L3;
+
+    /** unpauses the master stage */
+    public void unPauseMaster() {
+        fpslic.cell(0,PLANE_PAUSE_MASTER_WHEN_HIGH).ylut(0x00);
+        fpslic.flush();
+    }
+
+    /** unpauses the slave stages */
+    public void unPauseSlaves() {
+        fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_HIGH).ylut(0x00);
+        fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_LOW).ylut(0xff);
+        fpslic.flush();
+    }
+
+    /** pauses the master stage */
+    public void pauseMaster() {
+        fpslic.cell(0,PLANE_PAUSE_MASTER_WHEN_HIGH).ylut(0xff);
+        fpslic.flush();
+    }
+
+    /** pauses the slave stages */
+    public void pauseSlaves() {
+        fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_HIGH).ylut(0xff);
+        fpslic.cell(0,PLANE_PAUSE_SLAVES_WHEN_LOW).ylut(0x00);
+        fpslic.flush();
+    }
+
+    /** reset all stages (should be paused before doing this) */
+    public void resetAll() {
+        fpslic.cell(0,PLANE_RESET_ALL_WHEN_LOW).ylut(0x00);
+        fpslic.flush();
+        fpslic.cell(0,PLANE_RESET_ALL_WHEN_LOW).ylut(0xff);
+        fpslic.flush();
+    }
+
+    /** configures the ylut of the cell at (0,plane) to drive plane "plane" across the entire chip */
+    private void drivePlane(int plane) {
+        for(int i=0; i<=23; i++){
+            FpslicDevice.Cell c = fpslic.cell(0, i);
+            c.h(plane, true);
+            c.v(plane, true);
+            if (c.vwire(plane).south() != null)
+                c.vwire(plane).south().drives(c.vwire(plane), true);
+            for(FpslicDevice.SectorWire sw = c.hwire(plane).east();
+                sw!=null;
+                sw=sw.east())
+                sw.west().drives(sw, true);
+        }
+        fpslic.cell(0, plane-L0).c(YLUT);
+        fpslic.cell(0, plane-L0).b(false);
+        fpslic.cell(0, plane-L0).f(false);
+        fpslic.cell(0, plane-L0).out(plane, true);
+    }
+
+    /** causes the master cell's successor output to be set to the given value */
+    protected void forceMasterSuccessor(boolean high) {
+        masterCell().ylut(0xff);
+        masterCell().xo(false);
+        masterCell().yo(false);
+        masterCell().xlut(high ? 0xff : 0x00);
+        fpslic.flush();
+    }
+
+    /** causes the master cell's successor output to resume normal functionality, leaving it in state "state" */
+    protected void unForceMasterSuccessor(boolean state) {
+        pauseSlaves();
+        masterCell().xo(true);
+        masterCell().yo(true);
+        masterCell().xlut(LUT_Z);
+        fpslic.flush();
+        masterCell().ylut(!state ? 0x00 : 0xff);
+        fpslic.flush();
+        pauseMaster();
+        masterCell().ylut((LUT_SELF & ~LUT_OTHER) |
+                       (LUT_Z & ~LUT_OTHER) |
+                       (LUT_Z & LUT_SELF));
+        fpslic.flush();
+        unPauseMaster();
+        unPauseSlaves();
+    }
+
+
+    protected int init(int size) {
+        return init(size, this.start);
+    }
+    protected int init(int size, FpslicDevice.Cell start) {
+        for(int x=1; x<24; x++)
+            for(int y=0; y<24; y++) {
+                FpslicDevice.Cell c = fpslic.cell(x, y);
+                c.xlut(0x00);
+                c.ylut(0x00);
+                c.b(false);
+                c.f(false);
+                c.c(YLUT);
+            }
+        ExperimentUtils.setupScanCell(fpslic);
+        fpslic.flush();
+
+        this.start = start;
+        drivePlane(L0);
+        drivePlane(L1);
+        drivePlane(L2);
+        drivePlane(L3);
+
+        int rsize = 0;
+
+        // create a column of dividers
+        FpslicDevice.Cell div;
+
+        if (size == 4) {
+            rsize = 4;
+            pipe(start.west().north(), start.west().north().north(), new int[] { NE, SOUTH, NW, SOUTH });
+            div = start.east();
+            // annoying "bridge cell", because dividers must take input from the north
+            div.north().yo(start.north());
+            div.north().xo(start.north());
+        } else {
+            rsize = size-createPipeline(start, true, size-4, false);
+            unPauseMaster();
+            unPauseSlaves();
+            pipe(start.west().north(), start.west(), new int[] { NE, EAST, SW, SOUTH });
+            div = start.east();
+            // annoying "bridge cell", because dividers must take input from the north
+            div.north().yo(start.north());
+            div.north().xo(start.north());
+        }
+
+        dividers = 0;
+        while(div != null) {
+            FpslicDevice.Cell xdiv = ExperimentUtils.divider(div);
+            dividers++;
+            if (xdiv==null) break;
+            div = xdiv;
+        }
+        div = div.south().east();  // lower-right hand corner of the last divider placed
+        if (dividers < 10) {
+        div.east().yo(div);
+        div = div.east();
+        while(div.north() != null) {
+            div.north().yo(div);
+            div = div.north();
+        }
+        div.xo(div.south());
+        div.east().yo(div);
+        div.east().xo(div);
+        div = div.east();
+        div.east().xo(div);
+        div.east().yo(div);
+        div.south().yo(div);
+        div = div.south();
+        while(div != null && dividers < 10) {
+            FpslicDevice.Cell xdiv = ExperimentUtils.divider(div);
+            dividers++;
+            if (xdiv==null) { div = div.south().east(); break; }
+            if (dividers >= 10)  { div = div.south().east(); break; }
+            div = xdiv;
+        }
+        }
+        while(div.south() != null) {
+            div.south().yo(div);
+            div = div.south();
+        }
+        while(div.east() != null) {
+            div.east().yo(div);
+            div = div.east();
+        }
+        // assumption that we wind up in the lower-right-hand corner
+
+        return rsize;
+    }
+
+    //////////////////////////////////////////////////////////////////////////////
+
+    /** create a pipeline starting at cell "c", with predecessor "prev", and move in the directions
+     *  specified by "dirs" */
+    private FpslicDevice.Cell pipe(FpslicDevice.Cell c, FpslicDevice.Cell prev, int[] dirs) {
+        for(int i=0; i<dirs.length; i++) {
+            FpslicDevice.Cell next = c.dir(dirs[i]);
+            micropipelineStage(c, prev, next);
+            prev = c;
+            c = next;
+        }
+        return c;
+    }
+
+    /** this is really ugly and I no longer understand it */
+    private int createPipeline(FpslicDevice.Cell c, boolean downward, int length, boolean start) {
+        boolean stop = false;
+        do {
+            if (downward) {
+                if (c.row < 6) {
+                    if (length < 8+4) { stop = true; break; }
+                    length -= 8;
+                    c = pipe(c, c.north(), new int[] { SW, EAST, SW, WEST, NW, NORTH });
+                    c = c.se();
+                    c = pipe(c, c.north(), new int[] { NE, NORTH });
+                    c = c.sw().west();
+                    downward = false;
+                } else {
+                    if (length < 8+4) { stop = true; break; }
+                    length -= 8;
+                    c = micropipelineStage(c, c.north(), c.sw());
+                    c = micropipelineStage(c, c.ne(),    c.south());
+                    c = micropipelineStage(c, c.north(), c.se());
+                    c = micropipelineStage(c, c.nw(),    c.south());
+                    c = c.nw();
+                    c = micropipelineStage(c, c.south(), c.ne());
+                    c = micropipelineStage(c, c.sw(),    c.north());
+                    c = micropipelineStage(c, c.south(), c.nw());
+                    micropipelineStage(c, c.se(),    c.north());
+                    c = c.south().south().south().south().east();
+                }
+            } else {
+                if (c.row > c.fpslic().getHeight()-7) {
+                    if (length < 8+4) { stop = true; break; }
+                    length -= 8;
+                    c = pipe(c, c.south(), new int[] { NW, SOUTH });
+                    c = c.nw();
+                    c = pipe(c, c.south(), new int[] { NE, EAST, SE, WEST, SE, SOUTH });
+                    c = c.nw().west();
+                    downward = true;
+                } else {
+                    if (length < 8+4) { stop = true; break; }
+                    length -= 8;
+                    FpslicDevice.Cell ret = c = pipe(c, c.south(), new int[] { NE, NORTH, NW, NORTH });
+                    c = c.se();
+                    c = pipe(c, c.north(), new int[] { SW, SOUTH, SE, SOUTH });
+                    c = ret;
+                }
+            }
+        } while(false);
+        if (stop) {
+            length -= 4;
+            if (downward) {
+                c = micropipelineStage(c, c.north(), c.sw());
+                c = micropipelineStage(c, c.ne(), c.west());
+                c = micropipelineStage(c, c.east(), c.ne());
+                c = micropipelineStage(c, c.sw(), c.north());
+            } else {
+                c = pipe(c, c.south(), new int[] { NW, EAST, SE, SOUTH });
+            }
+            return length;
+        } else {
+            return createPipeline(c, downward, length, false);
+        }
+    }
+
+    private FpslicDevice.Cell micropipelineStage(FpslicDevice.Cell c,
+                                                 FpslicDevice.Cell prev,
+                                                 FpslicDevice.Cell next) {
+        boolean polarity = false;
+        switch(c.dir(next)) {
+            case NORTH: case SOUTH: case EAST: case WEST:
+                switch (c.dir(prev)) {
+                    case NORTH: case SOUTH: case EAST: case WEST: throw new Error("cannot have prev&next both use y");
+                }
+                polarity = false;
+                break;
+            case NW: case SE: case SW: case NE:
+                switch (c.dir(prev)) {
+                    case NW: case SE: case SW: case NE: throw new Error("cannot have prev&next both use x");
+                }
+                polarity = true;
+                break;
+            default: throw new Error();
+        }
+
+        c.yi(polarity ? prev : next);
+        c.xi(polarity ? next : prev);
+
+        c.b(false);
+        c.f(false);
+        c.yo(true);
+        c.xo(true);
+        c.c(ZMUX);
+
+        c.wi(PLANE_RESET_ALL_WHEN_LOW);
+        c.t(TMUX_W_AND_FB);
+
+        for(int i=L0; i<=L3; i++) c.h(i, true);
+
+        if (!polarity) {
+            if (c.row==masterCell().row && c.col==masterCell().col) {
+                c.zi(PLANE_PAUSE_MASTER_WHEN_HIGH);
+            } else {
+                c.zi(PLANE_PAUSE_SLAVES_WHEN_HIGH);
+            }
+            c.ylut((LUT_SELF & ~LUT_OTHER) |
+                   (LUT_Z & ~LUT_OTHER) |
+                   (LUT_Z & LUT_SELF));
+            c.xlut(LUT_Z);
+        } else {
+            /*
+            // internally asymmetric
+            c.zi(PLANE_PAUSE_SLAVES_WHEN_LOW);
+            c.xlut((LUT_SELF & ~LUT_OTHER) |
+                   (LUT_Z & ~LUT_OTHER) |
+                   (LUT_Z & LUT_SELF));
+            c.ylut(LUT_Z);
+            */
+
+            // internally symmetric
+            c.zi(PLANE_PAUSE_SLAVES_WHEN_HIGH);
+            c.ylut((~LUT_SELF & LUT_OTHER) |
+                   (LUT_Z & ~LUT_SELF) |
+                   (LUT_Z & LUT_OTHER));
+            c.xlut(LUT_Z);
+        }
+        return next;
+    }
+
+
+
+}