updates that were lying around but never got checked in; includes reorg of gui
authormegacz <adam@megacz.com>
Thu, 1 Jan 2009 06:25:24 +0000 (22:25 -0800)
committermegacz <adam@megacz.com>
Thu, 1 Jan 2009 06:25:24 +0000 (22:25 -0800)
32 files changed:
Makefile
src/com/atmel/fpslic/FpslicBoard.java [new file with mode: 0644]
src/com/atmel/fpslic/FpslicDevice.java [new file with mode: 0644]
src/edu/berkeley/abits/Board.java [new file with mode: 0644]
src/edu/berkeley/abits/Device.java [new file with mode: 0644]
src/edu/berkeley/slipway/SlipwayBoard.java [new file with mode: 0644]
src/edu/berkeley/slipway/SlipwaySlave.c [new file with mode: 0644]
src/edu/berkeley/slipway/demos/Demo.java [new file with mode: 0644]
src/edu/berkeley/slipway/demos/Demo2.java [new file with mode: 0644]
src/edu/berkeley/slipway/demos/FastestMicropipelineFifoDemo.java [new file with mode: 0644]
src/edu/berkeley/slipway/demos/MicropipelineFifoDemo.java [new file with mode: 0644]
src/edu/berkeley/slipway/gui/G.java
src/edu/berkeley/slipway/gui/Gui.java
src/edu/berkeley/slipway/gui/Gui2.java
src/edu/berkeley/slipway/gui/Gui3.java
src/edu/berkeley/slipway/gui/GuiCell.java
src/edu/berkeley/slipway/gui/GuiConstants.java
src/edu/berkeley/slipway/gui/Inspector.java [new file with mode: 0644]
src/edu/berkeley/slipway/gui/Keyboard.java [new file with mode: 0644]
src/edu/berkeley/slipway/gui/P.java
src/edu/berkeley/slipway/gui/ZoomingPanel.java
src/edu/berkeley/slipway/gui/ZoomingPanel2.java
src/edu/berkeley/slipway/mpar/HashMapBag.java [new file with mode: 0644]
src/edu/berkeley/slipway/mpar/MPARDemo.java
src/edu/berkeley/slipway/mpar/MapBag.java [new file with mode: 0644]
src/edu/berkeley/slipway/mpar/NetList.java
src/edu/berkeley/slipway/mpar/PhysicalDevice.java
src/edu/berkeley/slipway/mpar/PhysicalFpslic.java
src/edu/berkeley/slipway/mpar/Placement.java [new file with mode: 0644]
src/edu/berkeley/slipway/mpar/Routing.java [new file with mode: 0644]
src/edu/berkeley/slipway/mpar/Visualization.java [new file with mode: 0644]
src/edu/berkeley/slipway/util/ExperimentUtils.java [new file with mode: 0644]

index 8245190..615e63b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,13 +6,23 @@ linkerflags =
 jnilib      = libFtdiUartNative.so
 endif
 
-## slipway ############################################################################
-
-run: slipway.jar 
-       java -cp slipway.jar edu.berkeley.slipway.Demo 30
+## demos ############################################################################
 
 demo: slipway.jar 
-       java -cp slipway.jar edu.berkeley.slipway.Demo2 30
+       java -cp slipway.jar edu.berkeley.slipway.demos.Demo 30
+
+demo2: slipway.jar 
+       java -cp slipway.jar edu.berkeley.slipway.demos.Demo2 30
+
+asyncdemo: slipway.jar 
+       java -cp slipway.jar edu.berkeley.slipway.demos.FastestMicropipelineFifoDemo misc/data/async/
+
+mpardemo: upstream/jhdl-edifparser.jar slipway.jar
+       iverilog  -t fpga -s main -o out.edf misc/mpardemo.v
+       java -cp slipway.jar:upstream/jhdl-edifparser.jar edu.berkeley.slipway.mpar.MPARDemo out.edf
+
+
+## slipway ############################################################################
 
 build/src/com/ftdi/usb/FtdiUart.c: src/com/ftdi/usb/FtdiUart.i
        mkdir -p `dirname $@`
@@ -56,7 +66,7 @@ javac = javac -cp upstream/jhdl-edifparser.jar
 
 ## for rebuilding usbdrone.hex ###########################################################
 
-build/slipway_drone.hex: src/edu/berkeley/slipway/FtdiBoardSlave.c  upstream/avr-libc/.built
+build/slipway_drone.hex: src/edu/berkeley/slipway/SlipwaySlave.c  upstream/avr-libc/.built
        upstream/prefix/bin/avr-gcc -O3 -mmcu=at94k $< -o $@.o
        upstream/prefix/bin/avr-objcopy -O ihex $@.o $@
 
@@ -115,10 +125,6 @@ upstream/avr-libc/.built: upstream/avr-libc upstream/gcc/.built
                PATH=$$PATH:$(shell pwd)/upstream/prefix/bin make install
        touch $@
 
-mpardemo: upstream/jhdl-edifparser.jar slipway.jar
-       iverilog  -t fpga -s main -o out.edf misc/mpardemo.v
-       java -cp slipway.jar:upstream/jhdl-edifparser.jar edu.berkeley.slipway.mpar.MPARDemo out.edf
-
 
 ## edif parser ##########################################################################
 
diff --git a/src/com/atmel/fpslic/FpslicBoard.java b/src/com/atmel/fpslic/FpslicBoard.java
new file mode 100644 (file)
index 0000000..4016b60
--- /dev/null
@@ -0,0 +1,139 @@
+package com.atmel.fpslic;
+
+import edu.berkeley.abits.*;
+import java.io.*;
+
+/**
+ * Implementation of <tt>Board</tt> for Fpslic devices; subclass must
+ * implement methods to wiggle pins on the chip.
+ */
+public abstract class FpslicBoard implements Board {
+
+    public FpslicBoard() throws IOException { }
+
+    public void reset() throws IOException {
+        avrrstPin(false);
+        configDataPin(false);
+        resetPin(false);
+        cclkPin(false);
+        
+        conPin(false);
+        flush();
+
+        resetPin(false);
+        try { Thread.sleep(500); } catch (Exception e) { }
+        if (initPin()) throw new IOException("INIT was still high after pulling RESET low");
+
+        resetPin(true);
+        try { Thread.sleep(500); } catch (Exception e) { }
+        if (!initPin()) throw new IOException("INIT was still low after releasing RESET");
+
+        sendConfigBits(0,2);
+        flush();
+    }
+
+    public OutputStream getConfigStream() throws IOException {
+        reset();
+        return new OutputStream() {
+                int bytes = 0;
+                int bits = 0;
+                public void write(int in) throws IOException {
+                    for(int i=7; i>=0; i--) {
+                        bits++;
+                        sendConfigBits((((in & 0xff) & (1<<i))!=0)?1:0, 1);
+                    }
+                }
+                public void write(byte[] b, int off, int len) throws IOException {
+                    for(int i=off; i<off+len; i++)
+                        write(b[i]);
+                }
+                public void flush() throws IOException {
+                    FpslicBoard.this.flush();
+                }
+                public void close() throws IOException {
+                    flush();
+                    releaseConPin();
+                    if (!initPin())
+                        throw new IOException("initialization failed at " + bytes);
+                    for(int i=0; i<100; i++) {
+                        flush();
+                        if (!initPin())
+                            throw new IOException("initialization failed at " + bytes);
+                        try { Thread.sleep(20); } catch (Exception e) { }
+                        sendConfigBits(0,1);
+                    }
+                    FpslicBoard.this.close();
+                }
+            };
+    }
+
+    public void selfTest(SelfTestResultListener resultListener) throws IOException {
+        boolean pin;
+
+        // correct preamble
+        getConfigStream();
+        sendConfigBits(Integer.parseInt("00000000", 2), 8);
+        sendConfigBits(Integer.parseInt("10110111", 2), 8);
+        sendConfigBits(0,1);
+        flush();
+        try { Thread.sleep(100); } catch (Exception e) { }
+        pin = initPin();
+        resultListener.reportTestResult(0, 4, pin);
+
+        // preamble shifted one bit earlier than it should be
+        getConfigStream();
+        sendConfigBits(Integer.parseInt("0000000",  2), 7);
+        sendConfigBits(Integer.parseInt("10110111", 2), 8);
+        sendConfigBits(0, 2);
+        flush();
+        try { Thread.sleep(100); } catch (Exception e) { }
+        pin = initPin();
+        resultListener.reportTestResult(1, 4, !pin);
+
+        // preamble shifted one bit later than it should be
+        getConfigStream();
+        sendConfigBits(Integer.parseInt("000000000", 2), 9);
+        sendConfigBits(Integer.parseInt("10110111",  2), 8);
+        //sendConfigBits(0, 1);
+        flush();
+        try { Thread.sleep(100); } catch (Exception e) { }
+        pin = initPin();
+        resultListener.reportTestResult(2, 4, !pin);
+
+        // plain 'ol bogus preamble
+        getConfigStream();
+        sendConfigBits(Integer.parseInt("00000000", 2), 8);
+        sendConfigBits(Integer.parseInt("11110111", 2), 8);
+        sendConfigBits(0, 1);
+        flush();
+        try { Thread.sleep(100); } catch (Exception e) { }
+        pin = initPin();
+        resultListener.reportTestResult(3, 4, !pin);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////
+
+    private void sendConfigBits(int bits, int numbits) throws IOException {
+        for(int i=(numbits-1); i>=0; i--) {
+            boolean bit = (bits & (1<<i)) != 0;
+            configDataPin(bit);
+            cclkPin(true);
+            cclkPin(false);
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////
+
+    protected abstract void    avrrstPin(boolean on)      throws IOException;
+    protected abstract void    cclkPin(boolean on)        throws IOException;
+    protected abstract void    configDataPin(boolean on)  throws IOException;
+    protected abstract void    resetPin(boolean on)       throws IOException;
+    protected abstract boolean initPin()                  throws IOException;
+    protected abstract void    releaseConPin()            throws IOException;
+    protected abstract void    conPin(boolean on)         throws IOException;
+
+    protected abstract void    purge()                    throws IOException;
+    protected abstract void    flush()                    throws IOException;
+    protected abstract void    close()                    throws IOException;
+
+}
diff --git a/src/com/atmel/fpslic/FpslicDevice.java b/src/com/atmel/fpslic/FpslicDevice.java
new file mode 100644 (file)
index 0000000..b2df55d
--- /dev/null
@@ -0,0 +1,966 @@
+package com.atmel.fpslic;
+
+import java.util.*;
+import java.io.*;
+import org.ibex.util.Log;
+import edu.berkeley.abits.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+
+public abstract class FpslicDevice implements Device {
+
+    private final int width;
+    private final int height;
+
+    public FpslicDevice(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    public int getWidth() { return width; }
+    public int getHeight() { return height; }
+
+    public abstract void flush();
+    public abstract void mode4(int z, int y, int x, int d);
+    public abstract byte mode4(int z, int y, int x);
+
+    public          byte mode4zyx(int zyx) { return mode4(zyx>>24, (zyx>>16)&0xff, (zyx>>8)&0xff); }
+    public          void mode4zyx(int zyx, int d, int invmask) { mode4(zyx>>24, (zyx>>16)&0xff, (zyx>>8)&0xff, d, invmask); }
+    public          void mode4(int z, int y, int x, int d, int invmask) {
+        int old = mode4(z, y, x);
+        old &= ~invmask;
+        old |= d;
+        mode4(z, y, x, old);
+    }
+    public          void mode4zyx(int zyx, int bit, boolean set) { mode4(zyx>>24, (zyx>>16)&0xff, (zyx>>8)&0xff, bit, set); }
+    public          void mode4(int z, int y, int x, int bit, boolean set) {
+        int old = mode4(z, y, x);
+        old &= ~(1 << bit);
+        old |= set ? (1 << bit) : 0;
+        mode4(z, y, x, old);
+    }
+
+    // Inner Classes ///////////////////////////////////////////////////////////////////////////////
+
+    public final class Sector {
+        public final int col;
+        public final int row;
+        public Sector(Cell c) { this((c.col/4)*4, (c.row/4)*4); }
+        private Sector(int col, int row) {
+            if (row % 4 != 0) throw new Error("Sector must be created with a multiple-of-4 row");
+            if (col % 4 != 0) throw new Error("Sector must be created with a multiple-of-4 col");
+            this.row = row;
+            this.col = col;
+        }
+        public Sector north() { return row+4>=getHeight() ? null : new Sector(col, row+4); }
+        public Sector south() { return row==0 ?             null : new Sector(col, row-4); }
+        public Sector east()  { return col+4>=getWidth() ?  null : new Sector(col+4, row); }
+        public Sector west()  { return col==0 ?             null : new Sector(col-4, row); }
+        public Cell cell()    { return FpslicDevice.this.cell(col, row); }
+    }
+
+    public final class SectorWire {
+        public final boolean global;
+        public final boolean horizontal;
+        public final int     plane;
+        public final int     row;
+        public final int     col;
+        public SectorWire(boolean horizontal, int plane, int col, int row) {
+            this(horizontal, plane, col, row, false);
+        }
+
+        public void useColumnClock() {
+            // this is very poorly understood
+            if (horizontal) throw new RuntimeException();
+            mode4(0x25, (row>>2)+1, col, 0x80);
+            mode4(0x29, (row>>2),   col, 0x40);
+        }
+
+        public SectorWire(boolean horizontal, int plane, int col, int row, boolean global) {
+            this.horizontal=horizontal;
+            this.global=global;
+            this.plane=plane;
+            this.col= horizontal ? (col & ~0x3) : col;
+            this.row=!horizontal ? (row & ~0x3) : row;
+        }
+        public SectorWire global() {
+            return new SectorWire(horizontal, plane, col, row, true);
+        }
+        public boolean isDriven() {
+            // FIXME: bridging connections (horiz-to-vert)
+            for(int i=0; i<4; i++)
+                if (cell(horizontal ? col+i : col,
+                         horizontal ? row   : row+i).out(plane)) return true;
+            // FIXME: sector switchbox drivers
+            return false;
+        }
+        private int z(int z)       { return (horizontal ? 0x30 : 0x20) | z; }
+        public int code(boolean topleft) {
+            switch(plane) {
+                case 0: return z(8)+(topleft?0:1);
+                case 1: return z(6)+(topleft?0:1);
+                case 2: return z(2*(4-plane))+(topleft?0:1);
+                case 3: return z(2*(4-plane))+(topleft?0:1);
+                case 4: return z(2*(4-plane))+(topleft?0:1);
+            }
+            throw new Error();
+        }
+
+        private final int fine()   { return horizontal ? row : col; }
+        public  final int coarse() { return horizontal ? col : row; }
+        private int _row()  { return horizontal ? row          : ((row)>>2); }
+        private int _col()  { return horizontal ? ((col)>>2) : col;          }
+
+        public SectorWire west()  { return !horizontal ? null : col-4<0       ? null : new SectorWire(horizontal, plane, col-4, row); }
+        public SectorWire east()  { return !horizontal ? null : col+4>=getWidth()  ? null : new SectorWire(horizontal, plane, col+4, row); }
+        public SectorWire north() { return  horizontal ? null : row+4>=getHeight() ? null : new SectorWire(horizontal, plane, col,   row+4); }
+        public SectorWire south() { return  horizontal ? null : row-4<0       ? null : new SectorWire(horizontal, plane, col,   row-4); }
+
+        public String toString() {
+            return
+                (horizontal?(col+":"+(col+3)):(""+col))+","+
+                (horizontal?(row+"")         :(row+":"+(row+3)))+
+                "x"+plane;
+        }
+
+        /** returns the ZYX0 coordinate of the byte controlling the switchbox that allows <tt>w</tt> to drive this wire */
+        public int switchbox(SectorWire w) {
+            if (w.horizontal==horizontal) {
+                if (w.plane!=plane) throw new Error();
+                if (Math.abs(w.coarse()-coarse())!=4) throw new Error(w.coarse() + " -- " + coarse());
+                boolean topleft = horizontal ? (w.coarse() < coarse()) : (w.coarse() > coarse());
+                int col = _col() + (( horizontal && !topleft) ? 1 : 0);
+                int row = _row() + ((!horizontal &&  topleft) ? 1 : 0);
+                return (code(topleft) << 24) | (row<<16) | (col<<8);
+            }
+            throw new Error("not implemented");
+        }
+
+        public void dork() {
+            mode4zyx(switchbox(north()), (1<<6), (1<<6));
+        }
+
+        public void drives(SectorWire w, boolean enable) {
+            // FIXME: better error checks?
+            int val = 0;
+            if (enable) {
+                if (!global) val = 0x02;
+                else         val = 0x04;      
+            }
+            int mask = 0x07;
+            if (w.global) { mask = mask << 3; val = val << 3; }
+            mode4zyx(switchbox(w), val, mask);
+        }
+
+        public boolean drives(SectorWire w) {
+            // FIXME: better error checks?
+            int connect = (mode4zyx(switchbox(w)) >> (global?3:0)) & 0x7;
+            return (connect & 0x2)!=0;
+        }
+        public SectorWire driverRight() {
+            //System.out.println("checking " + Integer.toString(code(true), 16) + " " +
+            //Integer.toString(_row(), 16) + " " + Integer.toString(_col(), 16));
+            int ret = mode4(z(code(true)), _row(), _col());
+            ret = (ret >> (global?3:0)) & 0x7;
+            switch(ret) {
+                case 0: return null;
+                case 1: return null;  /* global wire on same side */
+                case 2: return new SectorWire(horizontal, plane, horizontal?(col+4):col, horizontal?row:(row+4));
+                case 4: return null;  /* global wire on other side */
+                default: throw new Error("multiple drivers on " + this + "!");
+            }
+        }
+
+        public boolean touches(Cell c) {
+            return
+                horizontal
+                ? (c.row==_row() && (_col()/4 == c.col/4))
+                : (c.col==_col() && (_row()/4 == c.row/4));
+        }
+    }
+    /*    
+    public final class SwitchBox {
+        public final boolean h;
+        public final int col;
+        public final int row;
+        public final int plane;
+        public SwitchBox(boolean h, int col, int row, int plane) { this.h = h; this.col = col; this.row = row; this.plane = plane; }
+        public SectorWire west(boolean global)  { return !h ? null : global ? null : new SectorWire(h, col-4, row,   plane); }
+        public SectorWire east(boolean global)  { return !h ? null : global ? null : new SectorWire(h, col+4, row,   plane); }
+        public SectorWire north(boolean global) { return !h ? null : global ? null : new SectorWire(h, col,   row-4, plane); }
+        public SectorWire south(boolean global) { return !h ? null : global ? null : new SectorWire(h, col,   row+4, plane); }
+    }
+    */
+
+    public Cell cell(int col, int row) {
+        if (col<0) return null;
+        if (row<0) return null;
+        if (col>=getWidth()) return null;
+        if (row>=getHeight()) return null;
+        return new Cell(col, row);
+    }
+
+    public final class Cell {
+        public final int col;
+        public final int row;
+
+        public void setColumnClock(int where) {
+            mode4(0x50, 0x00, col, where);
+        }
+
+        public String toString() { return "cell@("+col+","+row+")"; }
+
+        public Cell(int col, int row) {
+            this.row = row;
+            this.col = col;
+        }
+        
+        public FpslicDevice fpslic() { return FpslicDevice.this; }
+        public int hashCode() { return col ^ row ^ FpslicDevice.this.hashCode(); }
+        public boolean equals(Object o) {
+            if (o==null || (!(o instanceof Cell))) return false;
+            Cell c = (Cell)o;
+            return c.col == col && c.row == row && c.fpslic()==fpslic();
+        }
+
+        // Accessors for Neighbors //////////////////////////////////////////////////////////////////////////////
+
+        public SectorWire hwire(int plane)  { return new SectorWire(true, plane, col, row); }
+        public SectorWire vwire(int plane)  { return new SectorWire(false, plane, col, row); }
+        public Cell east() { return cell(col+1, row); }
+        public Cell west() { return cell(col-1, row); }
+        public Cell north() { return cell(col,   row+1); }
+        public Cell south() { return cell(col,   row-1); }
+        public Cell ne() { return cell(col+1, row+1); }
+        public Cell nw() { return cell(col-1, row+1); }
+        public Cell se() { return cell(col+1, row-1); }
+        public Cell sw() { return cell(col-1, row-1); }
+        public Sector sector() { return new Sector(this); }
+
+        /* bit positions mean:  [MSB] zxy z_y zx_ z__ _xy __y _x_ ___ [LSB] */
+        public void lut(int xlut, int ylut) { xlut(xlut); ylut(ylut); }
+        public void xlut(int table)    { mode4(7, row, col, (byte)(table & 0xff)); }
+        public byte xlut()             { return (byte)(mode4(7, row, col) & 0xff); }
+
+        public String str(int x, String def) {
+            switch(x) {
+                case NORTH: return "n";
+                case SOUTH: return "s";
+                case EAST:  return "e";
+                case WEST:  return "w";
+                case NW:    return "nw";
+                case SE:    return "se";
+                case NE:    return "ne";
+                case SW:    return "sw";
+                case FB:    return "fb";
+                case L0:    return (hx(0)&&vx(0))?"HV0":hx(0)?"H0":vx(0)?"V0":"L0";
+                case L1:    return (hx(1)&&vx(1))?"HV1":hx(1)?"H1":vx(1)?"V1":"L1";
+                case L2:    return (hx(2)&&vx(2))?"HV2":hx(2)?"H2":vx(2)?"V2":"L2";
+                case L3:    return (hx(3)&&vx(3))?"HV3":hx(3)?"H3":vx(3)?"V3":"L3";
+                case L4:    return (hx(4)&&vx(4))?"HV4":hx(4)?"H4":vx(4)?"V4":"L4";
+                default: return def;
+            }
+        }
+
+        /* bit positions mean:  [MSB] zxy zx_ z_y z__ _xy _x_ __y ___ [LSB] */
+        public void ylut(int table)    { mode4(6, row, col, (byte)(table & 0xff)); }
+        public byte ylut()             { return (byte)(mode4(6, row, col) & 0xff); }
+
+        public void ff_reset_value(boolean value) {
+            //mode4( /* FIXME WRONG!!! */, row, col, 3, !value); return;
+        }
+        /** FIXME!!! */
+        public boolean ff_reset_value() { return false; }
+        public boolean columnClocked() {
+            return false;
+        }
+
+        public void out(int plane, boolean enable) {
+            switch(plane) {
+                case L0: mode4(0x00, row, col, 2, enable); return;
+                case L1: mode4(0x00, row, col, 3, enable); return;
+                case L2: mode4(0x00, row, col, 5, enable); return;
+                case L3: mode4(0x00, row, col, 4, enable); return;
+                case L4: mode4(0x00, row, col, 1, enable); return;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public boolean out(int plane) {
+            switch(plane) {
+                case L0: return (mode4(0x00, row, col) & (1<<2)) != 0;
+                case L1: return (mode4(0x00, row, col) & (1<<3)) != 0;
+                case L2: return (mode4(0x00, row, col) & (1<<5)) != 0;
+                case L3: return (mode4(0x00, row, col) & (1<<4)) != 0;
+                case L4: return (mode4(0x00, row, col) & (1<<1)) != 0;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public void h(int plane, boolean enable) {
+            switch(plane) {
+                case 0: mode4(0x08, row, col, 0, enable); return;
+                case 1: mode4(0x08, row, col, 2, enable); return;
+                case 2: mode4(0x08, row, col, 5, enable); return;
+                case 3: mode4(0x08, row, col, 6, enable); return;
+                case 4: mode4(0x00, row, col, 6, enable); return;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+        
+        public boolean hx(int plane) {
+            switch(plane) {
+                case 0: return (mode4(0x08, row, col) & (1<<0)) != 0;
+                case 1: return (mode4(0x08, row, col) & (1<<2)) != 0;
+                case 2: return (mode4(0x08, row, col) & (1<<5)) != 0;
+                case 3: return (mode4(0x08, row, col) & (1<<6)) != 0;
+                case 4: return (mode4(0x00, row, col) & (1<<6)) != 0;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+        
+        public void v(int plane, boolean enable) {
+            switch(plane) {
+                case 0: mode4(0x08, row, col, 1, enable); return;
+                case 1: mode4(0x08, row, col, 3, enable); return;
+                case 2: mode4(0x08, row, col, 4, enable); return;
+                case 3: mode4(0x08, row, col, 7, enable); return;
+                case 4: mode4(0x00, row, col, 7, enable); return;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+        
+        public boolean vx(int plane) {
+            switch(plane) {
+                case 0: return (mode4(0x08, row, col) & (1<<1)) != 0;
+                case 1: return (mode4(0x08, row, col) & (1<<3)) != 0;
+                case 2: return (mode4(0x08, row, col) & (1<<4)) != 0;
+                case 3: return (mode4(0x08, row, col) & (1<<7)) != 0;
+                case 4: return (mode4(0x00, row, col) & (1<<7)) != 0;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+        
+
+        public int ti_source() {
+            switch(mode4(1, row, col) & 0x30) {
+                case 0x20: return zi();
+                case 0x10: return FB;
+                case 0x00: return wi();
+                default: throw new Error("ack!");
+            }
+        }
+
+        public int t() {
+            switch(mode4(1, row, col) & 0x30) {
+                case 0x00: return TMUX_W;
+                case 0x10: return wi()==NONE ? TMUX_FB : TMUX_W_AND_FB;
+                case 0x20: return wi()==NONE ? TMUX_Z  : TMUX_W_AND_Z;
+                case 0x30: throw new RuntimeException("illegal!");
+                default: return TMUX_W; 
+            }
+        }
+
+        public void t(int code) {
+            int result = 0;
+            switch(code) {
+                case TMUX_W:        result = 0x00; break;
+                case TMUX_Z:        result = 0x20; break;
+                case TMUX_W_AND_Z:  result = 0x20; break;
+                case TMUX_FB:       result = 0x10; break;
+                case TMUX_W_AND_FB: result = 0x10; break;
+                default: result = 0x00; break;
+            }
+            mode4(1, row, col, result, 0x30);
+        }
+        /*
+        private void fmux(int source) {
+            switch(source) {
+                case ZMUX:      
+                case FB:        
+                case ALWAYS_ON: 
+                default: throw new Error("unknown argument to fmux()");
+            }
+        }
+
+        public boolean win_easable() {
+        }
+        */
+
+        public int ti() {
+            return mode4(1, row, col) & 0x34;
+        }
+
+        public void t(boolean ignore_z_and_fb, boolean zm_drives_fb, boolean fb_drives_wm) {
+            // still not totally satisfied...
+            //     need to find the bit that sets the w-mux off
+            //     what does it mean for both bits (0x30) to be set to 1?
+            //if (fb && z) throw new RuntimeException("invalid combination");
+            int result = 0;
+            // ZM->FB = 0x04
+            // FB->WM = 0x10
+            // WZ->WM = 0x20
+
+            // tff => w&z      [0x20]
+            // fff => w        [0x00]
+            // ttt => fb&w     [0x34]
+            // ftt => fb&w     [0x14]
+            // fft => fb&w     [0x10]
+
+            // ttf => w&z      [0x24]
+            // ftf => w        [0x04]
+            // tft => fb&w     [0x30]
+            if (ignore_z_and_fb) result |= 0x20;
+            if (zm_drives_fb) result |= 0x04;
+            if (fb_drives_wm) result |= 0x10;
+            mode4(1, row, col, result, 0x34);
+        }
+
+
+        public void c(int source) {
+            switch(source) {
+                case XLUT: mode4(1, row, col, 0x00, 0xc0); break;
+                case YLUT: mode4(1, row, col, 0x40, 0xc0); break;
+                case ZMUX: mode4(1, row, col, 0x80, 0xc0); break;
+                default:   throw new RuntimeException("Invalid Argument");
+            }
+        }
+        public int c() {
+            int cval = mode4(1, row, col) & 0xc0;
+            switch (cval) {
+                case 0x00: return XLUT;
+                case 0x40: return YLUT;
+                case 0x80: return ZMUX;
+            }
+            throw new Error("c() => " + cval);
+        }
+        public void b(boolean registered) { mode4(1, row, col, 3, !registered); }
+        public void f(boolean registered) { mode4(1, row, col, 2, !registered); }
+        public boolean xo()               { return (mode4(1, row, col) & 0x01) != 0; }
+        public boolean yo()               { return (mode4(1, row, col) & 0x02) != 0; }
+        public void xo(boolean center)    { mode4(1, row, col, 0, center); }
+        public void yo(boolean center)    { mode4(1, row, col, 1, center); }
+
+        public void xo(Cell c) {
+            if (c.row==row || c.col==col) {   // use the y-input
+                xlut(LUT_OTHER);
+                yi(c);
+            } else {
+                xlut(LUT_SELF);
+                xi(c);
+            }
+            xo(false);
+        }
+
+        public void yo(Cell c) {
+            if (!(c.row==row || c.col==col)) {   // use the x-input
+                ylut(LUT_OTHER);
+                xi(c);
+            } else {
+                ylut(LUT_SELF);
+                yi(c);
+            }
+            yo(false);
+        }
+
+        public boolean b() { return (mode4(1, row, col) & (1 << 3)) == 0; }
+        public boolean f() { return (mode4(1, row, col) & (1 << 2)) == 0; }
+        public boolean x() { return (mode4(1, row, col) & (1 << 1)) != 0; }
+        public boolean y() { return (mode4(1, row, col) & (1 << 0)) != 0; }
+
+        public int oe() {
+            switch (mode4(0x02, row, col) & 0x3) {
+                case 0: return NONE;
+                case 1: return H4;
+                case 2: return V4;
+                default: throw new RuntimeException("invalid argument");                    
+            }
+        }
+        public void oe(int source) {
+            switch(source) {
+                case NONE: mode4(0x02, row, col, 0, 0x3); break;
+                case H4:   mode4(0x02, row, col, 1, 0x3); break;
+                case V4:   mode4(0x02, row, col, 2, 0x3); break;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public int xi() {
+            // FIXME: can be multiple
+            if ((mode4(0x03, row, col) & (1<<4))!=0) return L4;
+            switch(mode4(0x05, row, col) & 0xff) {
+                case 0x80: return SW;
+                case (1<<6): return NE;
+                case (1<<5): return SE;
+                case (1<<4): return NW;
+                case (1<<3): return L0;
+                case (1<<2): return L1;
+                case (1<<1): return L2;
+                case (1<<0): return L3;
+                case 0: return NONE;
+                default: throw new Error();
+            }
+        }
+
+        public void xi(int source) {
+            switch(source) {
+                case SW: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<7); break;
+                case NE: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<6); break;
+                case SE: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<5); break;
+                case NW: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<4); break;
+
+                case L0: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<3); break;
+                case L1: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<2); break;
+                case L2: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<1); break;
+                case L3: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 1<<0); break;
+                case L4: mode4(0x03, row, col, 4, true);  mode4(0x05, row, col,    0); break;
+
+                case NONE: mode4(0x03, row, col, 4, false); mode4(0x05, row, col, 0); break;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public void xi(SectorWire sw) {
+            if (!sw.touches(this)) throw new RuntimeException("invalid argument");
+            xi(sw.plane);
+        }
+
+        public void xi(Cell c) {
+            if      (c.row==row-1 && c.col==col-1) xi(SW);
+            else if (c.row==row+1 && c.col==col-1) xi(NW);
+            else if (c.row==row-1 && c.col==col+1) xi(SE);
+            else if (c.row==row+1 && c.col==col+1) xi(NE);
+            else throw new RuntimeException("invalid argument");
+        }
+
+        public int yi() {
+            if ((mode4(0x02, row, col) & (1<<6))!=0) return L4;
+            switch(mode4(0x04, row, col) & 0xff) {
+                case (1<<7): return NORTH;
+                case (1<<5): return SOUTH;
+                case (1<<6): return WEST;
+                case (1<<4): return EAST;
+                case (1<<3): return L0;
+                case (1<<2): return L1;
+                case (1<<1): return L2;
+                case (1<<0): return L3;
+                case 0: return NONE;
+                default: throw new Error();
+            }
+        }
+
+        public void yi(int source) {
+            switch(source) {
+                case NORTH: mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<7); break;
+                case SOUTH: mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<5); break;
+                case WEST:  mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<6); break;
+                case EAST:  mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<4); break;
+                case L4:    mode4(0x02, row, col, 6, true);  mode4(0x04, row, col,    0); break;
+                case L3:    mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<0); break;
+                case L2:    mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<1); break;
+                case L1:    mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<2); break;
+                case L0:    mode4(0x02, row, col, 6, false); mode4(0x04, row, col, 1<<3); break;
+                case NONE:  mode4(0x02, row, col, 6, false); mode4(0x04, row, col,    0); break;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public void yi(SectorWire sw) {
+            if (!sw.touches(this)) throw new RuntimeException("invalid argument");
+            yi(sw.plane);
+        }
+
+        public void yi(Cell c) {
+            if      (c.row==row-1 && c.col==col)   yi(SOUTH);
+            else if (c.row==row+1 && c.col==col)   yi(NORTH);
+            else if (c.row==row   && c.col==col-1) yi(WEST);
+            else if (c.row==row   && c.col==col+1) yi(EAST);
+            else throw new RuntimeException("invalid argument");
+        }
+
+        public void wi(SectorWire sw) {
+            if (!sw.touches(this)) throw new RuntimeException("invalid argument");
+            wi(sw.plane);
+        }
+
+        public void wi(int source) {
+            switch(source) {
+                case L4:    mode4(0x03, row, col, 1<<5, 0xEC); break;
+                case L3:    mode4(0x03, row, col, 1<<6, 0xEC); break;
+                case L2:    mode4(0x03, row, col, 1<<7, 0xEC); break;
+                case L1:    mode4(0x03, row, col, 1<<3, 0xEC); break;
+                case L0:    mode4(0x03, row, col, 1<<2, 0xEC); break;
+                case NONE:  mode4(0x03, row, col,    0, 0xEC); break;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public int wi() {
+            int who = mode4(0x03, row, col) & 0xEC;
+            switch(who) {
+                case (1<<5): return L4;
+                case (1<<6): return L3;
+                case (1<<7): return L2;
+                case (1<<3): return L1;
+                case (1<<2): return L0;
+                case (1<<0): return NONE;  /* huh? */
+                case (0):    return NONE;
+                default: throw new RuntimeException("invalid argument: " + who);
+            }
+        }
+
+       
+        public void zi(SectorWire sw) {
+            if (!sw.touches(this)) throw new RuntimeException("invalid argument");
+            zi(sw.plane);
+        }
+
+        public void zi(int source) {
+            switch(source) {
+                case L4:    mode4(0x02, row, col, 1<<7, 0xDB); break;
+                case L3:    mode4(0x02, row, col, 1<<5, 0xDB); break;
+                case L2:    mode4(0x02, row, col, 1<<4, 0xDB); break;
+                case L1:    mode4(0x02, row, col, 1<<3, 0xDB); break;
+                case L0:    mode4(0x02, row, col, 1<<2, 0xDB); break;
+                case NONE:  mode4(0x02, row, col,    0, 0xDB); break;
+                default: throw new RuntimeException("invalid argument");
+            }
+        }
+
+        public int zi() {
+            switch(mode4(0x02, row, col) & 0x9B) {
+                case (1<<7): return L4;
+                case (1<<5): return L3;
+                case (1<<4): return L2;
+                case (1<<3): return L1;
+                case (1<<2): return L0;
+                case (1<<1): return NONE;  /* huh? */
+                case (1<<0): return NONE;  /* huh? */
+                case 0:      return NONE;
+                default: throw new RuntimeException("invalid argument: zi=="+(mode4(0x02, row, col) & 0x9B));
+            }
+        }
+
+        public Cell dir(int i) {
+            switch(i) {
+                case NORTH: return north();
+                case SOUTH: return south();
+                case EAST: return east();
+                case WEST: return west();
+                case NW: return nw();
+                case SW: return sw();
+                case SE: return se();
+                case NE: return ne();
+            }
+            return null;
+        }
+        public int dir(Cell c) {
+            if      (c.row==row-1 && c.col==col-1) return SW;
+            else if (c.row==row+1 && c.col==col-1) return NW;
+            else if (c.row==row-1 && c.col==col+1) return SE;
+            else if (c.row==row+1 && c.col==col+1) return NE;
+            else if (c.row==row-1 && c.col==col)   return SOUTH;
+            else if (c.row==row+1 && c.col==col)   return NORTH;
+            else if (c.row==row   && c.col==col-1) return WEST;
+            else if (c.row==row   && c.col==col+1) return EAST;
+            return -1;
+        }
+
+        public void generalized_c_element() {
+
+            /*
+            ylut(LUT_SELF & (~LUT_OTHER));
+            xlut((~LUT_SELF) | LUT_OTHER);
+            c(ZMUX);
+            zi(L2);
+            //h(L2, true);
+            out(L2, true);
+            xo(true);
+            yo(true);
+            */
+
+            //ylut(0xB2);
+            ylut((LUT_SELF & ~LUT_OTHER) | (LUT_Z & ~LUT_OTHER) | (LUT_Z & LUT_SELF & LUT_OTHER));
+            xlut(LUT_Z);
+            c(YLUT);
+            f(false);
+            b(false);
+            t(false, false, true);
+            yo(false);
+            xo(false);
+        }
+
+
+        // Relevance //////////////////////////////////////////////////////////////////////////////
+        public boolean relevant() {
+            return xo_relevant() || yo_relevant() || out_relevant();
+        }
+
+        public boolean xo_relevant() { return xo_relevant(NE) || xo_relevant(SE) || xo_relevant(NW) || xo_relevant(SW); }
+        public boolean xo_relevant(int direction) {
+            switch(direction) {
+                case NE: return ne() != null && ne().xi()==SW;
+                case NW: return nw() != null && nw().xi()==SE;
+                case SE: return se() != null && se().xi()==NW;
+                case SW: return sw() != null && sw().xi()==NE;
+                default: return false;
+            }
+        }
+        public boolean yo_relevant() { return yo_relevant(NORTH) || yo_relevant(SOUTH) || yo_relevant(EAST) || yo_relevant(WEST); }
+        public boolean yo_relevant(int direction) {
+            switch(direction) {
+                case NORTH: return north() != null && north().yi()==SOUTH  /*&& north().yi_relevant()*/;
+                case EAST: return east() != null  && east().yi()==WEST     /*&& east().yi_relevant()*/;
+                case SOUTH: return south() != null && south().yi()==NORTH  /*&& south().yi_relevant()*/;
+                case WEST: return west() != null  && west().yi()==EAST     /*&& west().yi_relevant()*/;
+                default: return false;
+            }
+        }
+        public boolean xi_relevant() { return xi_to_xlut_relevant() || xi_to_ylut_relevant(); }
+        public boolean yi_relevant() { return yi_to_xlut_relevant() || yi_to_ylut_relevant(); }
+        public boolean xi_to_ylut_relevant() { return (((ylut() & 0xcc) >> 2) != (ylut() & 0x33)); }
+        public boolean yi_to_xlut_relevant() { return (((xlut() & 0xcc) >> 2) != (xlut() & 0x33)); }
+        public boolean zi_to_xlut_relevant() { return (((xlut() & LUT_Z) >> 4) != (xlut() & LUT_Z)); }
+        public boolean zi_to_ylut_relevant() { return (((ylut() & LUT_Z) >> 4) != (ylut() & LUT_Z)); }
+        public boolean xi_to_xlut_relevant() { return (((xlut() & LUT_SELF) >> 1) != (xlut() & (LUT_SELF >> 1))); }
+        public boolean yi_to_ylut_relevant() { return (((ylut() & LUT_SELF) >> 1) != (ylut() & (LUT_SELF >> 1))); }
+        public boolean xlut_relevant() {
+            if ((c()==XLUT || c()==ZMUX) && c_relevant()) return true;
+            if (xo()) return false;
+            return xo_relevant();
+        }
+        public boolean ylut_relevant() {
+            if ((c()==YLUT || c()==ZMUX) && c_relevant()) return true;
+            if (yo()) return false;
+            return yo_relevant();
+        }
+        public boolean c_relevant() {
+            switch(ti()) {
+                case 0x34: return true;
+                case 0x14: return true;
+                case 0x10: return true;
+                case 0x30: return true;
+            }
+            for(int i=0; i<5; i++)
+                if (out(i))
+                    return true;
+            if (xo() || yo()) return true;
+            return false;
+        }
+
+        public boolean register_relevant() {
+            if (!c_relevant()) return false;
+            if (f() && out_relevant()) return true;
+            if (f() && fb_relevant()) return true;
+            if (b() && xo()) return true;
+            if (b() && yo()) return true;
+            return false;
+        }
+        public boolean out_relevant() {
+            boolean out = false;
+            boolean connect = false;
+            for(int i=0; i<4; i++) {
+
+                // FIXME FIXME FIXME
+                if (i==3) continue;
+
+                if (out(L0+i)) out = true;
+                if (hx(L0+i)) connect = true;
+                if (vx(L0+i)) connect = true;
+            }
+            return out && connect;
+        }
+
+        public boolean fb_relevant() {
+            /*
+            if (!(zi_to_xlut_relevant()) ||
+                !(zi_to_ylut_relevant())) return false;
+            switch(ti()) {
+                case 0x34: return true;
+                case 0x14: return true;
+                case 0x10: return true;
+                case 0x30: return true;
+            }
+            return false;
+            */
+            return true;
+        }
+
+
+    }
+
+    public IOB iob_bot(int col, boolean primary)   { return new IOB(col, 0, primary, true); }
+    public IOB iob_top(int col, boolean primary)   { return new IOB(col, 1, primary, true); }
+    public IOB iob_left(int row, boolean primary)  { return new IOB(0, row, primary, false); }
+    public IOB iob_right(int row, boolean primary) { return new IOB(1, row, primary, false); }
+    /*
+    public IOB fromPin(int pin) {
+        if (pin >=  4 && pin <= 11) return io(pin-3);
+        if (pin >= 15 && pin <= 18) return io(pin-2);
+        if (pin >= 19 && pin <= 24) return io(pin);
+        if (pin >= 27 && pin <= 30) return io(pin-2);
+        if (pin >= 33 && pin <= 36) return io(pin);
+        if (pin >= 38 && pin <= 47) return io(pin+1);
+
+
+        if (pin >= 33 && pin <= 36) return io(pin+36);
+        if (pin >= 38 && pin <= 41) return io(pin+43);
+        if (pin >= 42 && pin <= 43) return io(pin+47);
+        if (pin >= 44 && pin <= 47) return io(pin+49);
+        if (pin >= 57 && pin <= 62) return io(pin+40);
+        if (pin >= 63 && pin <= 66) return io(pin+46);
+        if (pin >= 68 && pin <= 71) return io(pin+53);
+        if (pin >= 72 && pin <= 73) return io(pin+53);
+        if (pin >= 74 && pin <= 75) return io(pin+63);
+        if (pin >= 76 && pin <= 77) return io(143+(pin-76));
+        if (pin >= 80 && pin <= 81) return io(145+(pin-80));
+        if (pin >= 82 && pin <= 85) return io(151+(pin-82));
+        if (pin >= 86 && pin <= 89) return io(165+(pin-86));
+        if (pin >= 91 && pin <= 94) return io(177+(pin-91));
+        if (pin >= 95 && pin <= 96) return io(183+(pin-95));
+        if (pin >= 97 && pin <= 100) return io(189+(pin-97));
+        if (pin >= 161 && pin <= 164) return io(289+(pin-161));
+        if (pin >= 165 && pin <= 166) return io(297+(pin-165));
+        if (pin >= 167 && pin <= 168) return io(303+(pin-167));
+        if (pin >= 169 && pin <= 170) return io(309+(pin-169));
+        if (pin >= 172 && pin <= 173) return io(313+(pin-172));
+        if (pin >= 174 && pin <= 175) return io(325+(pin-174));
+        if (pin >= 176 && pin <= 179) return io(327+(pin-176));
+        if (pin >= 180 && pin <= 181) return io(335+(pin-180));
+        if (pin >= 184 && pin <= 185) return io(337+(pin-184));
+        if (pin >= 186 && pin <= 191) return io(343+(pin-186));
+        if (pin >= 192 && pin <= 193) return io(359+(pin-192));
+        if (pin >= 195 && pin <= 196) return io(363+(pin-195));
+        if (pin >= 197 && pin <= 200) return io(369+(pin-197));
+        if (pin >= 201 && pin <= 204) return io(381+(pin-201));
+    }
+    public io(int ionum) {
+        if (ionum <= 94) {
+            int cell = (94 - pin) / 2;
+            boolean primary = cell * 2 == (94-pin);
+        }
+    }
+    */
+    public final class IOB {
+        public final int col;
+        public final int row;
+        public final boolean primary;
+        public final boolean northsouth;
+        public IOB(int col, int row, boolean primary, boolean northsouth) {
+            this.col = col;
+            this.row = row;
+            this.northsouth = northsouth;
+            this.primary = primary;
+        }
+        /*
+        public String dump() {
+            System.out.println("[ "+
+                               (schmitt()?"schmitt ":"")+
+                               (slew()==3?"fast ":slew()==2?"med ":slew()==1?"slow ":"slew-unknown ")+
+                               (cr()?"cr ":"")+
+                               (reg()?"reg ":"")+
+                               
+        }
+        */
+        public void enableOutput(int direction) {
+            useoem(true);
+            output(direction);
+            pullnone();
+            useoem(true);
+            oem(ALWAYS_ON);
+            oe(true);
+            // note: east-side IOBs should have slew=med, others slew=fast
+            slew((!northsouth && col==1) ? MEDIUM : FAST);
+        }
+        public void enableInput() {
+            schmitt(true);
+            pullnone();
+        }
+
+        public void    useoem(boolean use)  { mode4(z(3), row, col, 6, use); }
+        public boolean useoem()             { return (mode4(z(3), row, col) & (1<<6))!=0; }
+        public void    schmitt(boolean use) { mode4(z(0), row, col, 7, use); }
+        public boolean schmitt()            { return (mode4(z(0), row, col) & (1<<7))!=0; }
+
+        public void    slew(int slew) {
+            switch(slew) {
+                case FAST:   mode4(z(0), row, col, 3<<5, 0x60); return;
+                case MEDIUM: mode4(z(0), row, col, 2<<5, 0x60); return;
+                case SLOW:   mode4(z(0), row, col, 1<<5, 0x60); return;
+                default: throw new Error();
+            }
+        }
+
+        public void    oem(int source) {
+            switch(source) {
+                case ALWAYS_ON:  mode4(z(3), row, col, 1<<5, 0x3f); return;
+                case ALWAYS_OFF: mode4(z(3), row, col,    0, 0x3f); return;
+                default: throw new Error();
+            }
+        }
+
+        private int z(int code) { return (northsouth ? 0x70 : 0x60) | (primary ? 0x00 : 0x04) | (code & 0x7); }
+        public void pullup()   { mode4(z(0), row, col, 0x00<<1, 0x06); }
+        public void pulldown() { mode4(z(0), row, col, 0x03<<1, 0x06); }
+        public void pullnone() { mode4(z(0), row, col, 0x01<<1, 0x06); }
+        public void oe(boolean oe) {
+            int old =  mode4(z(1), row, col) & (~(1<<5));
+            old     |= oe ? 0 : (1<<5);
+            mode4(z(1), row, col, old & 0xff);
+        }
+
+        public void output(int which) {
+            switch(which) {
+                case NONE:
+                    mode4(z(1), row, col, 0, 0x1f); return;
+                case WEST: case EAST: case NORTH: case SOUTH:
+                    mode4(z(1), row, col, 1<<0, 0x1f); return;
+                case NW: case SW: case NE: case SE:
+                    mode4(z(1), row, col, 1<<1, 0x1f); return;
+                default: throw new Error();
+            }
+        }
+
+    }
+
+    public void readMode4(Reader r) throws IOException {
+        int count = 0;
+        BufferedReader br = new BufferedReader(r);
+        for(String str = br.readLine(); str != null; str = br.readLine()) {
+            long foo = Long.parseLong(str, 16);
+            mode4((int)(foo >> 24), (int)(foo >> 16), (int)(foo >>  8), (int)(foo >>  0));
+            count++;
+        }
+        flush();
+        r.close();
+    }
+
+    public void writeMode4(Writer w) throws IOException {
+        // FIXME: there are resources "above" the top of the device
+        for(int x=0; x<getWidth(); x++)
+            for(int y=0; y<getWidth(); y++)
+                for(int z=0; z<255; z++) {
+                    if ((z > 0x09 && z < 0x10) ||
+                        (z > 0x11 && z < 0x20) ||
+                        (z > 0x29 && z < 0x30) ||
+                        (z > 0x39 && z < 0x40) ||
+                        (z > 0x41 && z < 0x60) ||
+                        (z > 0x67 && z < 0x70) ||
+                        (z > 0x77 && z < 0xD0) ||
+                        (z > 0xD3))
+                        continue;
+                    w.write(hex2(z));
+                    w.write(hex2(y));
+                    w.write(hex2(x));
+                    w.write(hex2(mode4(z, y, x) & 0xff));
+                    w.write('\n');
+                }
+        w.flush();
+    }
+
+    private static String hex2(int i) {
+        String ret = Integer.toString(i, 16);
+        while(ret.length() < 2) ret = "0"+ret;
+        return ret.toUpperCase();
+    }
+
+}
diff --git a/src/edu/berkeley/abits/Board.java b/src/edu/berkeley/abits/Board.java
new file mode 100644 (file)
index 0000000..318b095
--- /dev/null
@@ -0,0 +1,30 @@
+package edu.berkeley.abits;
+
+import edu.berkeley.abits.*;
+import java.io.*;
+
+/** interface for controlling an FPGA on a development board */
+public interface Board {
+
+    /** "deepest" possible reset of the FPGA */
+    public void reset() throws IOException;
+
+    /** return an OutputStream to which a configuration bitstream may be written */
+    public OutputStream getConfigStream() throws IOException;
+
+    /** InputStream for communicating with the device after configuration */
+    public InputStream  getInputStream() throws IOException;
+
+    /** OutputStream for communicating with the device after configuration */
+    public OutputStream getOutputStream() throws IOException;
+
+    /** causes the device to perform a self-test */
+    public void selfTest(SelfTestResultListener resultListener) throws Exception;
+
+    /** returns the actual device on the board */
+    public Device getDevice();
+
+    public static interface SelfTestResultListener {
+        public void reportTestResult(int testNumber, int totalNumberOfTests, boolean didPass);
+    }
+}
diff --git a/src/edu/berkeley/abits/Device.java b/src/edu/berkeley/abits/Device.java
new file mode 100644 (file)
index 0000000..7bf6639
--- /dev/null
@@ -0,0 +1,8 @@
+package edu.berkeley.abits;
+
+public interface Device {
+
+    public int getWidth();
+    public int getHeight();
+
+}
diff --git a/src/edu/berkeley/slipway/SlipwayBoard.java b/src/edu/berkeley/slipway/SlipwayBoard.java
new file mode 100644 (file)
index 0000000..2c30035
--- /dev/null
@@ -0,0 +1,324 @@
+package edu.berkeley.slipway;
+
+import java.io.*;
+import java.util.*;
+import com.ftdi.usb.*;
+import com.atmel.fpslic.*;
+import edu.berkeley.abits.*;
+import org.ibex.util.*;
+
+// FEATURE: more state checking (ie must have reset high before uart-mode, etc)
+
+/**
+ * Slipway board (Fpslic via FTDI USB-UART, running <tt>SlipwaySlave.c</tt>)
+ */
+public class SlipwayBoard extends FpslicBoard {
+
+    // Private Variables //////////////////////////////////////////////////////////////////////////////
+
+    private final DataInputStream in;
+    private final DataOutputStream out;
+    private final FpslicDevice device;
+    private final FtdiUart ftdiuart;
+    private       boolean initialized = false;
+
+
+    // Accessors //////////////////////////////////////////////////////////////////////////////////////
+
+    public InputStream getInputStream() { return in; }
+    public OutputStream getOutputStream() { return out; }
+
+    /** just a different return type for <tt>getDevice()</tt> */
+    public FpslicDevice getFpslicDevice() { return (FpslicDevice)getDevice(); }
+    public Device getDevice() { return device; }
+
+
+    // Methods //////////////////////////////////////////////////////////////////////////////////////
+
+    /** initialize assuming default USB settings and only one board connected to the system, perform self-test */
+    public SlipwayBoard() throws Exception { this(true); }
+
+    /** initialize assuming default USB settings and only one board connected to the system */
+    public SlipwayBoard(boolean selfTest) throws Exception {
+        this(new FtdiUart(0x6666, 0x3133, 1500 * 1000/2), selfTest);
+    }
+
+    /** initialize with a custom USB interface */
+    public SlipwayBoard(FtdiUart ftdiuart, boolean selfTest) throws Exception {
+        this.ftdiuart = ftdiuart;
+        device = new SlipwayFpslicDevice(24, 24);
+        String bstFile = this.getClass().getName();
+        bstFile = bstFile.substring(0, bstFile.lastIndexOf('.'));
+        bstFile = bstFile.replace('.', '/')+"/slipway_drone.bst";
+        if (selfTest) selfTest();
+        boot(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream(bstFile)));
+        in = new DataInputStream(ftdiuart.getInputStream());
+        out = new DataOutputStream(ftdiuart.getOutputStream());
+        for(int i=0; i<255; i++) out.write(0);
+        out.flush();
+        init(selfTest);
+    }
+
+    private void selfTest() throws IOException {
+        System.err.print("smoke check: ");
+        selfTest(new edu.berkeley.abits.Board.SelfTestResultListener() {
+                public void reportTestResult(int testNumber, int totalNumberOfTests, boolean didPass) {
+                    System.err.print(didPass ? " \033[32m[pass]\033[0m " : " \033[31m[FAIL]\033[0m ");
+                }
+            });
+        System.err.println();
+    }
+    
+    private void boot(Reader r) throws IOException {
+        int total = 75090/9;
+        OutputStream os = new ProgressOutputStream("bootstrap bitstream:", getConfigStream(), total);
+        BufferedReader br = new BufferedReader(r);
+        int bytes = 0;
+        while(true) {
+            String s = br.readLine();
+            if (s==null) break;
+            bytes++;
+            os.write((byte)Integer.parseInt(s, 2));
+            if ((bytes % 1000)==0) os.flush();
+        }
+        os.close();
+    }
+
+    private void init(boolean verbose) throws IOException {
+        if (initialized) throw new Error("cannot initialize twice");
+        initialized = true;
+        byte[] bytes = new byte[6];
+        int i=0;
+
+        out.write(0);
+        out.flush();
+
+        // read any garbage that might be left in the buffer
+        while(true) {
+            System.arraycopy(bytes, 1, bytes, 0, 5);
+            bytes[5] = in.readByte();
+            i++;
+            if (verbose) System.err.print("\rsignature: read \"" + new String(bytes) + "\"                   ");
+            if (bytes[0] == (byte)'O' &&
+                bytes[1] == (byte)'B' &&
+                bytes[2] == (byte)'I' &&
+                bytes[3] == (byte)'T' &&
+                bytes[4] == (byte)'S') {
+                if (verbose) System.err.println("\rsignature: got proper signature                  ");
+                purge();
+                break;
+            }
+        }
+
+        new Thread() {
+            public void run() {
+                while(true) {
+                    try {
+                        while(callbacks.size() == 0) Thread.sleep(50);
+                        byte b = in.readByte();
+                        ByteCallback bc = (ByteCallback)callbacks.remove(0);
+                        bc.call(b);
+                        synchronized(lock) {
+                            lock.notifyAll();
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }.start();
+    }
+
+
+    // Device //////////////////////////////////////////////////////////////////////////////
+
+    public class SlipwayFpslicDevice extends FpslicDevice {
+        private final byte[][][] cache = new byte[24][][];
+
+        // FEATURE: autodetect width/height by querying device id from the chip
+        public SlipwayFpslicDevice(int width, int height) {
+            super(width, height);
+        }
+
+        public synchronized byte mode4(int z, int y, int x) {
+            if (cache[x]==null) return 0;
+            if (cache[x][y]==null) return 0;
+            return cache[x][y][z];
+        }
+        public synchronized void mode4(int z, int y, int x, int d) {
+            try {
+                if (cache[x & 0xff]==null) cache[x & 0xff] = new byte[24][];
+                if (cache[x & 0xff][y & 0xff]==null) cache[x & 0xff][y & 0xff] = new byte[256];
+                cache[x & 0xff][y & 0xff][z & 0xff] = (byte)(d & 0xff);
+                
+                out.writeByte(1);
+                out.writeByte(z);
+                out.writeByte(y);
+                out.writeByte(x);
+                out.writeByte(d);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        public synchronized void flush() {
+            try {
+                SlipwayBoard.this.flush();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+
+    // Callbacks //////////////////////////////////////////////////////////////////////////////
+
+    private static final int CALLBACK_LIMIT = 40;
+    private Vector callbacks = new Vector();
+    private Object lock = new Object();
+    private int timer = 0;
+
+    private void enqueue(ByteCallback bcb) {
+        synchronized(lock) {
+            try {
+                while (callbacks.size() >= CALLBACK_LIMIT) {
+                    lock.wait(100);
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        callbacks.add(bcb);
+    }
+
+    public static abstract class ByteCallback {
+        public int result;
+        public abstract void call(byte b) throws Exception;
+    }
+
+    /** synchronously returns the number of interrupts triggered since the last call to <tt>readInterruptCount()</tt> */
+    public synchronized int readInterruptCount() {
+        try {
+            ByteCallback bc = new ByteCallback() {
+                    public synchronized void call(byte b) throws Exception {
+                        result =
+                            ((b & 0xff) << 24) |
+                            ((in.read() & 0xff) << 16) |
+                            ((in.read() & 0xff) << 8) |
+                            ((in.read() & 0xff) << 0);
+                        timer =
+                            ((in.read() & 0xff) << 24) |
+                            ((in.read() & 0xff) << 16) |
+                            ((in.read() & 0xff) << 8) |
+                            ((in.read() & 0xff) << 0);
+                        this.notify();
+                    }
+                };
+            synchronized(bc) {
+                enqueue(bc);
+                out.writeByte(3);
+                out.flush();
+                bc.wait();
+            }
+            return bc.result;
+        } catch (Exception e) { throw new RuntimeException(e); }
+    }
+
+    /** returns the number of milliseconds elapsed between the previous call to readInterruptCount() and the one before it */
+    public synchronized int readInterruptCountTime() {
+        return timer;
+    }
+
+    /** reads the values on the 8-bit bus connecting the fpga to the AVR */
+    public synchronized void readFpgaData(ByteCallback bc) throws IOException {
+        enqueue(bc);
+        out.writeByte(2);
+        out.flush();
+    }
+
+
+    // Pin Implementations //////////////////////////////////////////////////////////////////////////////
+
+    private int dbits = 0;
+    private int dmask =
+        (1<<0) |
+        (1<<1) |
+        (1<<2) |
+        //(1<<3) |
+        //(1<<4) |
+        (1<<5) |
+        (1<<6) |
+        (1<<7);
+
+    protected void flush() {
+        try {
+            if (out!=null) out.flush();
+            ftdiuart.getOutputStream().flush(); 
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void avrrstPin(boolean on)     throws IOException { setDBusLine(7, on); }
+    protected void cclkPin(boolean on)       throws IOException { setDBusLine(6, on); }
+    protected void configDataPin(boolean on) throws IOException { setDBusLine(5, on); }
+    protected boolean initPin()              throws IOException { flush(); return (ftdiuart.readPins() & (1<<4))!=0; }
+
+    // tricky: RESET has a weak pull-up, and is wired to a CBUS line.  So,
+    //         we can pull it down (assert reset) from uart-mode, or we can
+    //         let it float upward from either mode.
+    protected void resetPin(boolean on) throws IOException {
+        ftdiuart.uart_and_cbus_mode(1<<1, on ? (1<<1) : 0);
+        flush();
+        if (on) {
+            ftdiuart.dbus_mode(dmask);
+            flush();
+        }
+    }
+
+    protected void setDBusLine() throws IOException {
+        OutputStream os = ftdiuart.getOutputStream();
+        os.write((byte)dbits);
+    }
+    protected void clearDBusLines() throws IOException {
+        dbits = 0;
+        setDBusLine();
+    }
+    protected void setDBusLine(int bit, boolean val) throws IOException {
+        dbits = val ? (dbits | (1 << bit)) : (dbits & (~(1 << bit)));
+        setDBusLine();
+    }
+    protected void releaseConPin() throws IOException {
+        dmask &= ~(1<<0);
+        ftdiuart.dbus_mode(dmask);
+        flush();
+    }
+    protected void conPin(boolean on) throws IOException {
+        dmask |= (1<<0);
+        ftdiuart.dbus_mode(dmask);
+        setDBusLine(0, on);
+        flush();
+    }
+    public void close() throws IOException {
+        // switching to uart mode will implicitly release AVRRST
+        avrrstPin(false);
+        ftdiuart.purge();
+        ftdiuart.uart_and_cbus_mode(1<<1, 1<<1);
+        ftdiuart.purge();
+    }
+    protected void purge() throws IOException {
+        ftdiuart.purge();
+    }
+    
+
+    // Util //////////////////////////////////////////////////////////////////////////////
+
+    private static String pad(int i, String s) {
+        if (s.length()>i) return s;
+        return "0"+pad((i-1),s);
+    }
+    private static String pad(String s, int i) {
+        if (s.length() >= i) return s;
+        return "0"+pad(s, i-1);
+    }
+}
+
diff --git a/src/edu/berkeley/slipway/SlipwaySlave.c b/src/edu/berkeley/slipway/SlipwaySlave.c
new file mode 100644 (file)
index 0000000..163e717
--- /dev/null
@@ -0,0 +1,282 @@
+//
+// YOU MUST COMPILE THIS WITH -O3 OR THE AVR WILL NOT BE ABLE TO KEEP UP!!!!
+//
+
+#define F_CPU 12000000
+
+#if !defined(__AVR_AT94K__)
+#error you forgot to put -mmcu=at94k on the command line
+#endif
+
+#include <avr/wdt.h>
+#include <util/delay.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+volatile int32_t upper = 0;
+
+int err = 0;
+
+void initUART0(unsigned int baudRate, unsigned int doubleRate) {
+  UBRRHI  = (((baudRate) >> 8) & 0x000F); 
+  UBRR0   = ((baudRate) & 0x00FF); 
+  UCSR0B |= ((1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0)); 
+
+  if (doubleRate)
+    UCSR0A |=  (1 << U2X0);
+  else
+    UCSR0A &= ~(1 << U2X0);
+}
+
+#define BUFSIZE (1024)
+
+long int numread = 0;
+inline void cts(int c) {
+  numread++;
+  if (c) {
+    PORTE &= ~(1 << 7);
+  } else {
+    PORTE |= (1 << 7);
+  }
+}
+
+
+static volatile int sending = 0;
+static volatile int32_t interrupt_count = 0;
+
+// RECV //////////////////////////////////////////////////////////////////////////////
+
+char read_buf[BUFSIZE];
+volatile int read_buf_head;
+volatile int read_buf_tail;
+char write_buf[BUFSIZE];
+volatile int write_buf_head;
+volatile int write_buf_tail;
+
+inline int inc(int x) { x++; if (x>=BUFSIZE) x=0; return x; }
+inline int read_full() { return inc(read_buf_tail)==read_buf_head; }
+inline int abs(int x) { return x<0 ? -x : x; }
+inline int read_size() { return read_buf_tail<read_buf_head ? (read_buf_head-read_buf_tail) : (read_buf_tail-read_buf_head); }
+inline int read_empty() { return read_buf_head==read_buf_tail; }
+inline int read_nearlyFull() {
+  if (read_buf_tail==read_buf_head) return 0;
+  if (read_buf_tail < read_buf_head) return (read_buf_head-read_buf_tail) < (BUFSIZE/2);
+  return (read_buf_tail-read_buf_head) > (BUFSIZE/2);
+}
+
+inline int write_full() { return inc(write_buf_tail)==write_buf_head; }
+inline int write_empty() { return write_buf_head==write_buf_tail; }
+inline int write_nearlyFull() {
+  if (write_buf_tail==write_buf_head) return 0;
+  if (write_buf_tail < write_buf_head) return (write_buf_head-write_buf_tail) < (BUFSIZE/2);
+  return (write_buf_tail-write_buf_head) > (BUFSIZE/2);
+}
+
+int32_t timer = 0;
+
+inline char recv() {
+  int q;
+  char ret;
+
+  PORTE |=  (1<<3);
+  while(read_empty()) cts(1);
+  PORTE &= ~(1<<3);
+
+  ret = read_buf[read_buf_head];
+  read_buf_head = inc(read_buf_head);
+  if (!read_nearlyFull()) cts(1);
+  return ret;
+}
+
+// Interrupt Handlers //////////////////////////////////////////////////////////////////////////////
+
+ISR(SIG_UART0_DATA) {
+  if (write_empty()) {
+    UCSR0B &= ~(1 << UDRIE0);
+    return;
+  }
+  char ret = write_buf[write_buf_head];
+  write_buf_head = inc(write_buf_head);
+  UDR0 = (int)ret;
+  sei();
+}
+
+void send(char c) {
+  PORTE |=  (1<<2);
+  while (write_full());
+  PORTE &= ~(1<<2);
+  write_buf[write_buf_tail] = c;
+  write_buf_tail = inc(write_buf_tail);
+  UCSR0B |= (1 << UDRIE0);
+}
+
+
+void fpga_interrupts(int on) {
+  if (on) {
+    //FISUA = 0x1;
+    FISCR = 0x80;
+    FISUA = 0x01;
+  } else {
+    FISUA = 0;
+    FISCR = 0;
+  }
+}
+
+inline void conf(int z, int y, int x, int d) {
+  FPGAX = x;
+  FPGAY = y;
+  FPGAZ = z;
+  FPGAD = d;
+}
+
+#define TIMERVAL 100
+
+ISR(SIG_FPGA_INTERRUPT0) { 
+  interrupt_count++;
+  sei();
+}
+
+volatile int dead = 0;
+
+ISR(SIG_OVERFLOW1) { 
+  upper = upper + 1;
+
+  if (!dead) {
+    if (PORTE & (1<<5)) PORTE &= ~(1<<5);
+    else                PORTE |=  (1<<5);
+  }
+
+  TCNT1 = 0;
+  sei();
+}
+
+//void die() { dead = 1; cli(); PORTE|=(1<<5); _delay_ms(2000); while(1) { } }
+
+void die(int two, int three, int five) {
+  dead = 1;
+  PORTE &~ ((1<<2) | (1<<3) | (1<<5));
+  if (two) PORTE |= (1<<2);
+  if (three) PORTE |= (1<<3);
+  if (five) PORTE |= (1<<5);
+  while(1) { }
+}
+
+ISR(SIG_UART0_RECV) {
+  if (UCSR0A & (1 << FE0))   die(0, 0, 1);
+  if ((UCSR0A & (1 << OR0))) die(1, 1, 1);
+  if (read_full()) die(1, 0, 1);
+
+  read_buf[read_buf_tail] = UDR0;
+  read_buf_tail = inc(read_buf_tail);
+  if (read_nearlyFull()) cts(0);
+  SREG |= 0x80;
+  sei();
+}
+
+inline int hex(char c) {
+  if (c >= '0' && c <= '9') return (c - '0');
+  if (c >= 'a' && c <= 'f') return ((c - 'a') + 0xa);
+  if (c >= 'A' && c <= 'F') return ((c - 'A') + 0xa);
+  return -1;
+}
+
+int readFPGA() {
+  fpga_interrupts(0);
+  int ret = FISUA;
+  fpga_interrupts(1);
+  return ret;
+}
+
+int main() {
+  DDRE  = (1<<7) | (1<<5) | (1<<3) | (1<<2);
+  PORTE = 0;
+
+  PORTE |=  (1<<5);
+
+  read_buf_head = 0;
+  read_buf_tail = 0;
+  write_buf_head = 0;
+  write_buf_tail = 0;
+  initUART0(1, 0);  //for slow board
+
+  EIMF = 0xFF;
+  SREG = INT0;
+  sei();
+
+  TCNT1 = 0;
+  TIFR&=~(1<<TOV1);
+  TIMSK|=(1<<TOIE1);
+  TCCR1B = 3;
+
+  cts(0);
+  cts(1);
+
+  int x=0, y=0, z=0;
+  int flag=0;
+  for(;;) {
+    int i, d=0;
+    int r = recv();
+    switch(r) {
+      case 0:
+        send('O');
+        send('B');
+        send('I');
+        send('T');
+        send('S');
+        fpga_interrupts(1);
+        if (flag) die(0, 1, 1);
+        break;
+
+      case 1:
+        z = recv();
+        y = recv();
+        x = recv();
+        d = recv();
+        conf(z, y, x, d);
+        break;
+
+      case 2:
+        flag=1;
+        send(readFPGA());
+        break;
+
+      case 3: {
+        int32_t local_interrupt_count = interrupt_count;
+        interrupt_count = 0;
+        send((local_interrupt_count >> 24) & 0xff);
+        send((local_interrupt_count >> 16) & 0xff);
+        send((local_interrupt_count >>  8) & 0xff);
+        send((local_interrupt_count >>  0) & 0xff);
+        int32_t local_timer = TCNT1;
+        int32_t local_upper = upper;
+        TCCR1B = 0;
+        TIFR&=~(1<<TOV1);
+        TIMSK|=(1<<TOIE1);
+        upper = 0;
+        TCNT1 = 0;
+        TCCR1B = 3;
+        send((local_upper >>  8) & 0xff);
+        send((local_upper >>  0) & 0xff);
+        send((local_timer >>  8) & 0xff);
+        send((local_timer >>  0) & 0xff);
+        break;
+      }
+
+        /*
+      case 3:
+        //init_timer();
+        break;
+      case 4:
+        sending = 1;
+        break;
+      case 5:
+        sending = 0;
+        break;
+        */
+    }
+  }
+  return 0;
+
+}  
+
diff --git a/src/edu/berkeley/slipway/demos/Demo.java b/src/edu/berkeley/slipway/demos/Demo.java
new file mode 100644 (file)
index 0000000..08f9ca6
--- /dev/null
@@ -0,0 +1,1096 @@
+package edu.berkeley.slipway.demos;
+
+import edu.berkeley.slipway.*;
+import com.atmel.fpslic.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+import edu.berkeley.slipway.gui.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.color.*;
+import org.ibex.util.*;
+import java.io.*;
+import java.util.*;
+import gnu.io.*;
+
+public class Demo {
+
+    public static boolean mullers = true;
+    public static int masterx = 1;
+
+    public static int PIPELEN=20;
+
+    public static void main(String[] s) throws Exception {
+        SlipwayBoard slipway = new SlipwayBoard();
+        FpslicDevice device = slipway.getFpslicDevice();
+        FpslicDevice at40k = device;
+        try {
+            Log.info(Demo.class, "issuing command");
+
+            //at40k.iob_top(2, true).oe(false);
+            //at40k.iob_top(2, false).oe(false);
+            //at40k.iob_top(1, true).oe(false);
+
+            // this command confirmed to turn *on* led0
+            //at40k.iob_top(1, false).output(0);
+            /*
+              for(int i=0; i<20; i++) {
+              at40k.iob_bot(i, false).output(0);
+              at40k.iob_bot(i, true).output(0);
+              }
+            */
+
+            //System.out.println("tick");
+            //Thread.sleep(3000);
+            //System.out.println("tick");
+            //at40k.cell(0x01, 0x17).xlut((byte)0x);
+
+            /*
+              System.out.println(Integer.toString(0xff & at40k.cell(0x01, 0x17).xlut(), 16));
+              System.out.println(Integer.toString(0xff & at40k.cell(0x01, 0x17).ylut(), 16));
+              at40k.cell(0x01, 0x17).ylut((byte)0xff);
+            */
+
+            //at40k.cell(0x01, 0x17).wi(L1);
+            /*
+              System.out.println("a: " + at40k.new SectorWire(true, 0, 4, 0x17).driverRight());
+              System.out.println("b: " + at40k.new SectorWire(true, 1, 4, 0x17).driverRight());
+              FpslicDevice.SectorWire h0p0 = at40k.new SectorWire(true, 0, 0, 0x17);
+              FpslicDevice.SectorWire h0p1 = at40k.new SectorWire(true, 1, 0, 0x17);
+              FpslicDevice.SectorWire h0p2 = at40k.new SectorWire(true, 2, 0, 0x17);
+              FpslicDevice.SectorWire h4p0 = at40k.new SectorWire(true, 0, 4, 0x17);
+              FpslicDevice.SectorWire h4p1 = at40k.new SectorWire(true, 1, 4, 0x17);
+              FpslicDevice.SectorWire h4p2 = at40k.new SectorWire(true, 2, 4, 0x17);
+
+              //h4p1.drives(h0p1, false);
+              //at40k.cell(0x04, 0x17).out(L1, false);
+              //at40k.cell(0x04, 0x17).h(L0, false);
+
+              for(int plane=0; plane<5; plane++) {
+              at40k.new SectorWire(true, plane,     4, 0x17).drives(at40k.new SectorWire(true, plane,     0, 0x17), false);
+              at40k.cell(0x04, 0x17).out(plane, false);
+              at40k.cell(0x04, 0x17).h(plane, false);
+              at40k.cell(0x01, 0x17).h(plane, false);
+              }
+              try { Thread.sleep(2000); } catch (Exception e) { }
+
+              int plane=0;
+              at40k.new SectorWire(true, plane, 4, 0x17).drives(at40k.new SectorWire(true, plane, 0, 0x17), true);
+              at40k.cell(0x04, 0x17).out(plane, true);
+              at40k.cell(0x04, 0x17).h(plane, true);
+              at40k.cell(0x01, 0x17).h(plane, true);
+              at40k.cell(0x01, 0x17).wi(plane);
+
+            */
+
+            /*
+              System.out.println("xlut is " + hex(at40k.cell(0x04, 0x17).xlut()));
+              System.out.println("ylut is " + hex(at40k.cell(0x04, 0x17).ylut()));
+              FpslicDevice.Cell cell = at40k.cell(0x04, 0x17);
+              //cell.xlut(0xff);
+              //cell.f(false);
+              System.out.println(cell.c());
+              cell.c(YLUT);
+              cell.ylut(0x4D);
+              cell.xlut(0x00);
+
+              cell.b(false);
+              cell.f(false);
+              //cell.t(false, false, true);
+              cell.t(false, true, false);
+              cell.out(L3, true);
+              cell.wi(L3);
+
+              cell.yo(false);
+              cell.h(L0, false);
+              cell.h(L1, false);
+              cell.h(L2, false);
+              cell.h(L3, false);
+              cell.h(L4, false);
+
+              for(int i=3; i>=1; i--) {
+              at40k.cell(i, 0x17).yi(EAST);
+              at40k.cell(i, 0x17).ylut(0x55);
+              at40k.cell(i, 0x17).yo(false);
+              }
+            */
+
+            //System.out.println("reading port status: " + Integer.toString(device.readFpgaData() & 0xff, 16));
+
+
+            // blank these out
+            /*
+              at40k.cell(23, 8).ylut(0xff);
+              at40k.cell(23, 11).ylut(0xff);
+              at40k.iob_right(8, true).enableOutput();
+              at40k.iob_right(11, true).enableOutput();
+            */
+            //for(int x=4;  x<=22; x++) swap(at40k.cell(x, 22), NW, NORTH);
+
+
+            // entry cell: just copy X->X Y->Y
+            //at40k.cell(4,23).b(false);
+            //at40k.cell(4,23).yo(false);
+            //at40k.cell(4,23).ylut(at40k.cell(4,23).xlut());
+            //at40k.cell(4,23).xo(false);
+            /*
+              at40k.cell(4,23).xlut(0x55);
+              at40k.cell(4,23).ylut(0x55);
+            */
+            /*
+              at40k.cell(4,23).xlut(0x71);
+              at40k.cell(4,23).ylut(0x44);
+              at40k.cell(4,23).c(YLUT);
+              at40k.cell(4,23).f(false);
+              at40k.cell(4,23).t(false, false, true);
+            */
+
+            //for(int x=6;  x<=23; x++) copy(at40k.cell(x, 23), NW, WEST);  // top row copies to the right
+            /*
+              copy(at40k.cell(5, 22), NW, NORTH);
+              for(int x=6;  x<=22; x++) copy(at40k.cell(x, 22), NW, WEST);  // second top row copies to the right
+              //for(int y=22; y>=10; y--) copy(at40k.cell(23, y), NW, NORTH); // right edge copies down
+              for(int y=21; y>=9;  y--) copy(at40k.cell(22, y), NW, NORTH); // second right edge copies down
+              copy(at40k.cell(23, 9), NW, WEST);                            // second output
+            */
+            /*
+              handshaker(at40k.cell(4,23));
+              at40k.cell(4,23).xi(NW);
+              at40k.cell(4,23).yi(SOUTH);
+
+              //handshaker(at40k.cell(5,23));
+              //at40k.cell(5,23).yi(NORTH);
+
+              at40k.cell(5,23).yi(NORTH);
+              at40k.cell(5,23).xlut(0x55);
+              at40k.cell(5,23).xi(SW);
+              at40k.cell(5,23).ylut(0x55);
+              at40k.cell(5,22).yi(NORTH);
+              at40k.cell(5,22).xlut(0x55);
+
+              bounce(at40k.cell(4,22));
+
+              // cell southeast of entry cell
+              at40k.cell(3,22).xi(NE);      // NW->xin
+              at40k.cell(3,22).ylut(0x33);  // xin->y
+              at40k.cell(3,22).yo(false);   // y->yout
+              copy(at40k.cell(3, 21), NW, NORTH);  // second top row copies to the right
+              copy(at40k.cell(4, 21), NW, EAST);  // second top row copies to the right
+              copy(at40k.cell(5, 21), NW, EAST);  // second top row copies to the right
+              copy(at40k.cell(6, 21), NW, EAST);  // second top row copies to the right
+              copy(at40k.cell(6, 22), NW, SOUTH);  // second top row copies to the right
+            */
+            /*
+              at40k.cell(05,22).xlut(0xff);
+              at40k.cell(05,22).ylut(0xff);
+              at40k.cell(05,22).c(XLUT);
+              at40k.cell(05,22).f(false);
+              at40k.cell(05,22).b(false);
+              at40k.cell(05,22).oe(NONE);
+              at40k.cell(05,22).v(L3, true);
+              at40k.cell(05,22).out(L3, true);
+            */
+            /*
+              at40k.cell(4,23).ylut(~0xCC);
+              at40k.cell(4,23).xlut(~0xAA);
+              at40k.cell(5,23).ylut(~0xAA);
+              at40k.cell(5,23).xlut(~0xAA);
+              for(int i=6; i<PIPELEN+2; i++) {
+              at40k.cell(i, 23).ylut(0xAA);
+              at40k.cell(i, 23).xlut(0xCC);
+              at40k.cell(i, 23).yi(WEST);
+              }
+            */
+
+            doitx(at40k, slipway);
+            Gui vis = new Gui(device, slipway);
+            Frame fr = new Frame();
+            fr.addKeyListener(vis);
+            fr.setLayout(new BorderLayout());
+            fr.add(vis, BorderLayout.CENTER);
+            fr.pack();
+            fr.setSize(900, 900);
+            vis.repaint();
+            fr.repaint();
+            fr.show();
+            synchronized(Demo.class) { Demo.class.wait(); }
+            /* LAST
+               System.out.println("doit");
+               if (mullers) doitx(at40k, device);
+               //System.out.println("counter");
+               //counter(at40k, device);
+
+               at40k.cell(21,15).yi(WEST);
+               at40k.cell(21,15).ylut(0xAA);
+
+               at40k.cell(22,15).yi(WEST);
+               at40k.cell(22,15).ylut(0xAA);
+            */
+
+            FpslicDevice.Cell root = at40k.cell(10,20);
+            
+            root.yo(root.north());
+            root.ylut(~LUT_SELF);
+            root.c(YLUT);
+            root = root.north();
+
+            root.yo(root.east());
+            root.ylut(~LUT_SELF);
+            root.c(YLUT);
+            root = root.east();
+
+            root.yo(root.south());
+            root.ylut(~LUT_SELF);
+            root.c(YLUT);
+            root = root.south();
+
+            root.yo(root.west());
+            root.c(YLUT);
+            root = root.west();
+
+            //////////////////////////////////////////////////////////////////////////////
+
+            at40k.cell(23,15).h(3, true);
+            at40k.cell(23,15).yi(L3);
+            at40k.cell(23,15).ylut(0xAA);
+            at40k.iob_right(15, true).enableOutput(WEST);
+
+
+            FpslicDevice.Cell c = at40k.cell(10,10);
+            c.ylut(~LUT_SELF);
+            c.xlut(LUT_Z);
+            c.yi(WEST);
+            c.c(YLUT);
+            c.f(false);
+            c.t(TMUX_FB);
+            copy(c.west(), EAST, NW);
+            copy(c.west().north().west(), SE, SE);
+
+            c = c.east();
+            c.ylut(~LUT_SELF);
+            c.xlut(LUT_Z);
+            c.yi(EAST);
+            c.c(YLUT);
+            c.f(false);
+            c.t(TMUX_FB);
+            copy(c.east(), WEST, SE);
+            copy(c.east().south().east(), NW, NW);
+
+            c = c.north();
+            copy(c.north(), SOUTH, SOUTH);
+            c.xlut((LUT_SELF & ~LUT_OTHER) | LUT_Z);
+            c.ylut(LUT_Z);
+            c.yi(SOUTH);
+            c.c(XLUT);
+            c.xi(SW);
+            c.wi(L4);
+            c.f(false);
+            c.t(TMUX_W_AND_FB);
+            c.v(L4, false);
+            c.h(L4, true);
+            c.v(L2, false);
+            c.h(L2, true);
+
+            c = c.west();
+            copy(c.north(), SOUTH, SOUTH);
+            c.xlut((LUT_SELF & ~LUT_OTHER) | LUT_Z);
+            c.ylut(~LUT_Z);
+            c.yi(SOUTH);
+            c.xi(SE);
+            c.c(XLUT);
+            c.wi(L4);
+            c.f(false);
+            c.t(TMUX_W_AND_FB);
+            c.v(L4, false);
+            c.h(L4, true);
+            c.v(L2, false);
+            c.h(L2, true);
+
+            c = c.west();
+            c.v(L4, false);
+            c.h(L4, true);
+            c.out(L4, true);
+            c.f(false);
+            c.b(false);
+            c.oe(NONE);
+            c.c(YLUT);
+            c.hwire(L4).west().drives(c.hwire(L4), false);
+            c.hwire(L4).east().drives(c.hwire(L4), false);
+
+            c = c.south();
+            c = c.south();
+            c.v(L4, false);
+            c.h(L4, true);
+            c.out(L4, true);
+            c.f(false);
+            c.b(false);
+            c.oe(NONE);
+            c.c(YLUT);
+            c.hwire(L4).west().drives(c.hwire(L4), false);
+            c.hwire(L4).east().drives(c.hwire(L4), false);
+
+            c = c.east();
+            c = c.east();
+            copy(c.south(), NORTH, NORTH);
+            c.xlut(((~LUT_SELF) & (~LUT_OTHER)) | LUT_Z);
+            c.ylut(LUT_Z);
+            c.yi(NORTH);
+            c.c(XLUT);
+            c.xi(NW);
+            c.wi(L4);
+            c.f(false);
+            c.t(TMUX_W_AND_FB);
+            c.v(L4, false);
+            c.h(L4, true);
+            c.v(L2, false);
+            c.h(L2, true);
+
+            c = c.west();
+            copy(c.south(), NORTH, NORTH);
+            c.xlut((LUT_SELF & LUT_OTHER) | LUT_Z);
+            c.ylut(LUT_Z);
+            c.yi(NORTH);
+            c.xi(NE);
+            c.c(XLUT);
+            c.wi(L4);
+            c.f(false);
+            c.t(TMUX_W_AND_FB);
+            c.v(L4, false);
+            c.h(L4, true);
+            c.v(L2, false);
+            c.h(L2, true);
+
+
+            // catch a rising transition
+            /*
+              c = c.west();
+              c.v(L2, false);
+              c.h(L2, true);
+              c.out(L2, true);
+              c.f(false);
+              c.b(false);
+              c.oe(NONE);
+              c.c(YLUT);
+            */
+            c.hwire(L2).west().drives(c.hwire(L2), false);
+            c.hwire(L2).east().drives(c.hwire(L2), false);
+
+
+
+            //////
+
+            c = at40k.cell(20,20);
+            c.yi(WEST);
+            c.ylut(LUT_SELF);
+            c.c(YLUT);
+            c.oe(H4);
+            c.h(L4, true);
+            c.b(false);
+            c.f(false);
+            c.out(L4);
+
+            c = at40k.cell(21,20);
+            c.c(YLUT);
+            c.oe(NONE);
+            c.h(L4, true);
+            c.b(false);
+            c.f(false);
+
+
+            c = at40k.cell(8,8);
+            c.f(true);
+            c.b(true);
+            c.xo(true);
+            c.xi(NE);
+            c.zi(L3);
+            c.wi(L0);
+            c.yi(NORTH);
+            c.oe(H4);
+            c.h(L0, true);
+            c.h(L2, true);
+            c.h(L4, true);
+            c.v(L1, true);
+            c.v(L3, true);
+            c.out(L0, true);
+            c.out(L1, true);
+            c.out(L2, true);
+            c.out(L3, true);
+            c.out(L4, true);
+            c.xo(true);
+            c.yo(true);
+            c.c(ZMUX);
+
+            at40k.cell(9,10).xo(true);
+            at40k.cell(9,10).yo(true);
+            at40k.cell(9,10).c(YLUT);
+            at40k.cell(9,10).b(false);
+
+            //for(int x=5; x<PIPELEN; x++) {
+            //at40k.cell(x,23).hwire(L0).drives(at40k.cell(x,23).hwire(L0).east());
+            //}
+
+            /*
+              at40k.cell(22,11).ylut(0xff);
+              at40k.cell(23,11).yi(L3);
+              //at40k.cell(23,11).yi(WEST);
+              //at40k.cell(23,11).xi(L1);
+              at40k.cell(23,11).ylut(0xAA);
+              at40k.iob_right(11, true).enableOutput(WEST);
+              at40k.cell(23,11).v(L3, true);
+              at40k.cell(23,11).yo(false);
+              //at40k.flush();
+              */
+            int vx=04;
+            int vv=23;
+            /*
+              System.out.println("correct: " + at40k.cell(19,15).hwire(L3) + " drives " + at40k.cell(20,15).hwire(L3));
+              System.out.println("correct: " + at40k.cell(15,15).hwire(L3) + " drives " + at40k.cell(19,15).hwire(L3));
+              System.out.println("correct: " + at40k.cell(11,15).hwire(L3) + " drives " + at40k.cell(15,15).hwire(L3));
+              System.out.println("correct: " + at40k.cell(07,15).hwire(L3) + " drives " + at40k.cell(11,15).hwire(L3));
+
+              at40k.cell(19,15).hwire(L3).drives(at40k.cell(20,15).hwire(L3), true);
+              at40k.cell(15,15).hwire(L3).drives(at40k.cell(19,15).hwire(L3), true);
+              at40k.cell(11,15).hwire(L3).drives(at40k.cell(15,15).hwire(L3), true);
+              at40k.cell(07,15).hwire(L3).drives(at40k.cell(11,15).hwire(L3), true);
+            */
+            //at40k.cell(05,vv).xlut(0xff);
+            //at40k.cell(05,vv).ylut(0xff);
+            /*
+              at40k.cell(vx,vv).c(YLUT);
+              at40k.cell(vx,vv).f(false);
+              at40k.cell(vx,vv).b(false);
+              at40k.cell(vx,vv).oe(NONE);
+              at40k.cell(vx,vv).v(L3, true);
+              at40k.cell(vx,vv).out(L3, true);
+            */
+            /*
+              at40k.cell(vx,15).v(L3, true);
+              at40k.cell(vx,15).h(L3, true);
+              at40k.cell(vx,19).vwire(L3).drives(at40k.cell(vx,15).vwire(L3), true);
+              at40k.cell(vx,23).vwire(L3).drives(at40k.cell(vx,19).vwire(L3), true);
+            */
+
+            //at40k.cell(5,23).ylut(0x00);
+            //at40k.cell(6,22).ylut(0xff);
+            //at40k.cell(22,11).ylut(0xff);
+            /*
+              FpslicDevice.Cell cell = at40k.cell(4, 16);
+              cell.xlut(0xff);
+              cell.ylut(0xff);
+              cell.b(false);
+              cell.f(false);
+              cell.c(XLUT);
+              cell.h(L3, true);
+              cell.v(L3, true);
+              cell.out(L3, true);
+              cell.oe(NONE);
+            */
+            //scan(at40k, cell, YLUT, true);
+            //scan(at40k, cell, YLUT, false);
+
+            //device.scanFPGA(true);
+
+            at40k.cell(10,10).f(true);
+            at40k.cell(10,10).c(ZMUX);
+
+            at40k.cell(8,7).xlut(LUT_SELF);
+            at40k.cell(8,7).xi(NW);
+
+            at40k.cell(7,8).xlut(LUT_SELF & LUT_Z);
+            at40k.cell(7,8).xi(SE);
+            at40k.cell(7,8).c(XLUT);
+            at40k.cell(7,8).f(false);
+            at40k.cell(7,8).b(false);
+            at40k.cell(7,8).t(TMUX_FB);
+            at40k.cell(7,8).xo(false);
+            System.out.println(at40k.cell(7,8).fb_relevant());
+
+            at40k.cell(6,13).xi(SE);
+            at40k.cell(6,13).c(ZMUX);
+            at40k.cell(6,13).xlut(LUT_SELF);
+            at40k.cell(6,13).ylut(LUT_OTHER);
+            at40k.cell(6,13).xo(false);
+            at40k.cell(6,13).yo(false);
+            at40k.cell(7,12).xi(SE);
+
+            for(int i=0; i<24; i++) {
+                at40k.iob_bot(i, true).enableOutput(NORTH);
+                at40k.iob_bot(i, false).enableOutput(NW);
+                at40k.cell(i, 0).xlut(0xff);
+                at40k.cell(i, 0).ylut(0xff);
+            }
+
+            device.flush();
+
+            fr.addKeyListener(vis);
+            fr.setLayout(new BorderLayout());
+            fr.add(vis, BorderLayout.CENTER);
+            fr.pack();
+            fr.setSize(900, 900);
+            vis.repaint();
+            fr.repaint();
+            fr.show();
+            synchronized(Demo.class) { Demo.class.wait(); }
+
+
+
+            /*
+              Visualizer v = new Visualizer(at40k, device);
+              v.show();
+              v.setSize(1380, 1080);
+              FpslicDevice.Cell cell = at40k.cell(4, 23);
+            */
+            //Image img = v.createImage(v.getWidth(), v.getHeight());
+            /*
+              int x = 1;
+              int y = 14;
+              cell = at40k.cell(x,y);
+              scan(at40k, cell, YLUT, true);
+              cell.c(YLUT);
+              cell.b(false);
+              cell.f(false);
+              cell.oe(NONE);
+              cell.ylut(0xff);
+            */
+            //int x = 5;
+            //int y = 11;
+
+            //selfTest(device, at40k, v);
+            //System.out.println("save: " + SlipwayBoard.save + " of " + (SlipwayBoard.saveof*5));
+
+            at40k.iob_top(0, true).enableInput();
+            copy(at40k.cell(0, 23), NORTH, NORTH);
+            at40k.iob_bot(0, true).enableOutput(NORTH);
+
+            for(int i=0; i<10000; i++) {
+                //v.refresh();
+                try { Thread.sleep(100); } catch (Exception e) { }
+            }
+            //cell.ylut(0x09);
+
+            //at40k.cell(0x01, 0x17).h(0, false);
+            //at40k.cell(0x01, 0x17).xi(NE);
+            //at40k.cell(0x01, 0x17).ylut((byte)0x55);
+
+            //at40k.cell(0x04, 0x17).xlut((byte)0x10);
+            //at40k.cell(0x04, 0x17).ylut((byte)0x10);
+            //at40k.cell(0x04, 0x17).yo(false);
+            //at40k.cell(0x04, 0x17).xo();
+
+            /*
+              at40k.cell(0x01, 0x17).xi(L0);
+              at40k.cell(0x01, 0x17).h(L0, true);
+            */
+            /*
+              at40k.cell(0x03, 0x17).xlut((byte)0x55);
+              at40k.cell(0x03, 0x17).ylut((byte)0x55);
+              at40k.cell(0x03, 0x17).yi(EAST);
+              at40k.cell(0x03, 0x17).ylut((byte)0x55);
+              at40k.cell(0x03, 0x17).yo(true);
+
+              at40k.cell(0x03, 0x17).f(false);
+              at40k.cell(0x03, 0x17).c(XLUT);
+              at40k.cell(0x03, 0x17).oe(NONE);
+              at40k.cell(0x03, 0x17).out(L0, true);
+
+              at40k.cell(0x02, 0x17).yi(EAST);
+              at40k.cell(0x02, 0x17).ylut((byte)0x55);
+              at40k.cell(0x02, 0x17).yo(false);
+
+              at40k.cell(0x01, 0x17).yi(EAST);
+              at40k.cell(0x01, 0x17).ylut((byte)0x55);
+              at40k.cell(0x01, 0x17).yo(false);
+
+              at40k.cell(0x01, 0x17).h(L0, true);
+              at40k.cell(0x01, 0x17).v(L0, false);
+            */
+            //at40k.cell(0x01, 0x17).yi(L0);
+            //at40k.cell(0x01, 0x17).xi(L0);
+            //at40k.cell(0x01, 0x17).ylut((byte)0x33);
+
+            /*
+              at40k.cell(0x03, 0x17).h(L0, true);
+              at40k.cell(0x03, 0x17).out(L0, true);
+              at40k.cell(0x03, 0x17).c(XLUT);
+              at40k.cell(0x03, 0x17).f(false);
+            */
+            /*
+              at40k.cell(0x01, 0x17).xin(4);
+              at40k.cell(0x01, 0x17).yin(4);
+              at40k.cell(0x01, 0x16).ylut((byte)0x00);
+              device.mode4(2, 0x17, 0x01, 0);
+
+              for(int i=0; i<10; i++) {
+              Thread.sleep(3000);
+              System.out.println("tick");
+              //at40k.cell(0x01, 0x17).xlut((byte)0xFF);
+              at40k.cell(0x00, 0x17).ylut((byte)0x00);
+              device.getFpslicDevice().flush();
+              Thread.sleep(3000);
+              System.out.println("tick");
+              //at40k.cell(0x01, 0x17).xlut((byte)0x00);
+              at40k.cell(0x00, 0x17).ylut((byte)0xFF);
+              device.getFpslicDevice().flush();
+              }
+            */
+
+
+            /*
+              at40k.iob_top(0, true).output(0);
+              at40k.iob_top(0, true).oe(false);
+              at40k.iob_top(0, true).pullup();
+              device.getFpslicDevice().flush();
+              Thread.sleep(3000);
+
+              Log.info(Demo.class, "issuing command");
+              at40k.iob_top(1, true).pulldown();
+              device.getFpslicDevice().flush();
+            */
+            Log.info(Demo.class, "done");
+            System.exit(0);
+        } catch (Exception e) { e.printStackTrace(); }
+    }
+
+
+    public static void copy(FpslicDevice.Cell c, int xdir, int ydir) {
+        switch(xdir) {
+            case NW: case NE: case SW: case SE: {
+                c.xi(xdir);
+                c.xlut(LUT_SELF);
+                break;
+            }
+            case NORTH: case SOUTH: case EAST: case WEST: {
+                c.yi(xdir);
+                c.xlut(LUT_OTHER);
+                break;
+            }
+            case NONE: break;
+            default: throw new Error();
+        }
+        switch(ydir) {
+            case NW: case NE: case SW: case SE: {
+                c.xi(ydir);
+                c.ylut(LUT_OTHER);
+                break;
+            }
+            case NORTH: case SOUTH: case EAST: case WEST: {
+                c.yi(ydir);
+                c.ylut(LUT_SELF);
+                break;
+            }
+            case NONE: break;
+            default: throw new Error();
+        }
+        c.xo(false);
+        c.yo(false);
+    }
+    public static String hex(int x) {
+        return Long.toString(x & 0xffffffffL, 16);
+    }
+
+    public static void handshaker(FpslicDevice.Cell cell) {
+        cell.xlut(0x22);
+        cell.ylut(0x71);
+        cell.c(XLUT);
+        cell.f(false);
+        cell.t(false, false, true);
+    }
+
+
+    private static String pad(int i, String s) { if (s.length()>i) return s; return "0"+pad((i-1),s); }
+    public static String bin8(byte b) {
+        int n = b & 0xff;
+        String ret = "";
+        for(int i=7; i>=0; i--)
+            ret += (n & (1<<i))==0 ? "0" : "1";
+        return ret;
+    }
+
+    public static void bounce(FpslicDevice.Cell cell, int xi, int yi) {
+        cell.xlut((byte)0xCC);
+        cell.ylut((byte)0xCC);
+        cell.xi(xi);
+        cell.yi(yi);
+        cell.xo(false);
+        cell.yo(false);
+    }
+    public static void muller(FpslicDevice.Cell cell, int xi, int yi) {
+        cell.ylut(0xB2);
+        cell.c(YLUT);
+        cell.f(false);
+        cell.t(false, false, true);
+        cell.xi(xi);
+        cell.yi(yi);
+        cell.yo(false);
+        cell.xo(false);
+    }
+
+    public static int lutSwap(int x) {
+        return
+            (x & 0x80)        |
+            ((x & 0x20) << 1) |
+            ((x & 0x40) >> 1) |
+            (x & 0x10) |
+            (x & 0x08)        |
+            ((x & 0x02) << 1) |
+            ((x & 0x04) >> 1) |
+            (x & 0x01);
+    }
+
+    /** watches for a rising/falling edge on Yin, emits a pulse on Xout */
+    public static void pulse_detect(FpslicDevice.Cell c, int in, boolean falling) {
+        c.ylut(0x00);
+        c.xlut(0x00);
+        switch(in) {
+            case NW: case NE: case SW: case SE: {
+                c.xi(in);
+                loopback(c, XLUT);
+                if (!falling) c.ylut(lutSwap(0x0C)); /* x & !z */
+                else          c.ylut(lutSwap(0x30)); /* !x & z */
+                c.xlut(LUT_SELF);
+                break;
+            }
+            case NORTH: case SOUTH: case EAST: case WEST: {
+                c.yi(in);
+                loopback(c, YLUT);
+                if (!falling) c.xlut(0x0C); /* y & !z */
+                else          c.xlut(0x30); /* !y & z */
+                c.ylut(LUT_SELF);
+                break;
+            }
+            default: throw new Error();
+        }
+    }
+
+    /** watches for a pulse on Xin, copies value of Yin */
+    public static void pulse_copy(FpslicDevice.Cell cell, int xi, int yi, boolean invert) {
+        loopback(cell, YLUT);
+        if (!invert) cell.ylut(0xB8);   /* yo = x ?  yi : z => 1011 1000 */
+        else         cell.ylut(0x74);   /* yo = x ? !yi : z => 0111 0100 */
+        if (!invert) cell.xlut(lutSwap(0xB8));   /* yo = x ?  yi : z => 1011 1000 */
+        else         cell.xlut(lutSwap(0x74));   /* yo = x ? !yi : z => 0111 0100 */
+        cell.xi(xi);
+        cell.yi(yi);
+    }
+
+    public static void loopback(FpslicDevice.Cell cell, int cin) {
+        cell.f(false);
+        cell.b(false);
+        cell.t(false, false, true);
+        cell.yo(false);
+        cell.xo(false);
+        cell.c(cin);
+    }
+
+    public static void doit(FpslicDevice at40k, SlipwayBoard device) throws Exception {
+
+        FpslicDevice.Cell led = at40k.cell(1, 23);
+        led.v(L2, true);
+        led.h(L2, false);
+        led.yi(L2);
+        led.ylut(~LUT_SELF);
+        led.xlut(LUT_SELF);
+        led.yo(false);
+
+        FpslicDevice.Cell c = at40k.cell(1, 22);
+        c.out(L1, true);
+        c.out(L0, true);
+        c.oe(V4);
+        c.ylut(0xff);
+        c.h(L1, true);
+        c.h(L0, false);
+
+        c.v(L0, /*false*/true);
+
+        c.v(L1, true);
+        c.f(false);
+        c.b(false);
+        c.c(YLUT);
+
+        for(int i=0; i<4; i++) at40k.cell(i, 20).h(L0, false);
+        FpslicDevice.Cell z = at40k.cell(1, 20);
+        z.out(L0, true);
+        z.xlut(0xff);
+        z.c(XLUT);
+        z.yi(L0);
+        z.ylut(~LUT_SELF);
+        z.v(L0, true);
+        //z.h(L0, true);
+        z.h(L0, false);
+        z.f(false);
+        z.b(false);
+        z.hwire(L0).east().drives(z.hwire(L0), false);
+        z.hwire(L1).east().drives(z.hwire(L1), false);
+        z.vwire(L0).south().drives(z.vwire(L0), false);
+        z.vwire(L1).south().drives(z.vwire(L1), false);
+        z.oe(H4);
+
+        z = at40k.cell(0, 20);
+        z.oe(NONE);
+        z.out(L0, true);
+        z.out(L1, true);
+        z.out(L2, true);
+        //z.out(L3, true);
+        z.out(L4, true);
+        z.h(L0, true);
+        z.h(L1, true);
+        z.h(L2, true);
+        //z.h(L3, true);
+        z.h(L4, true);
+        z.f(false);
+        z.b(false);
+        z.yi(EAST);
+        z.ylut(LUT_SELF);
+        z.c(YLUT);
+
+        for(int y=20; y<=22; y++)
+            for(int x=2; x<=5; x++) {
+                c = at40k.cell(x, y);
+                copy(c, NW, WEST);
+            }
+
+        //c = at40k.cell(2, 22);
+        //c.h(L0, true);
+        //c.yi(L0);
+
+        c = at40k.cell(1, 21);
+        c.v(L0, true);
+        c.v(L2, true);
+        c.yi(L0);
+        c.out(L2, true);
+        c.ylut(LUT_SELF);
+        c.c(YLUT);
+        c.b(false);
+        c.f(false);
+        c.oe(NONE);
+        c.yo(false);
+
+        
+
+        c = at40k.cell(13, 22);
+        c.xlut(LUT_OTHER | 0xF0);
+        c.c(XLUT);
+        c.t(false, false, true);
+        c.b(false);
+        c.f(false);
+        c.ylut(0xF0);
+        c.yi(EAST);
+        c.yo(false);
+        /*
+        // this gate detects a rising edge on its Xin (delayed copy on Yin); when viewed, it inverts its state
+        c = at40k.cell(14, 22);
+        c.ylut(0x00);
+        c.c(XLUT);
+        c.f(false);
+        c.b(false);
+        c.t(false, false, true);
+        c.xi(SE);
+        c.yi(SOUTH);
+        c.yo(false);
+        c.xo(false);
+        c.ylut(0xA6); // (x & !z) ? ~y : y
+        c.xlut(LUT_SELF); 
+
+        c = at40k.cell(14, 20);
+        c.ylut(LUT_OTHER);
+        c.xi(NE);
+        c = at40k.cell(14, 21);
+        c.ylut(LUT_SELF);
+        c.xi(SOUTH);
+
+        c = at40k.cell(13, 22);
+        c.xlut(0x00);
+        c.xlut(LUT_OTHER);// | 0xF0);
+        */
+        //c = at40k.cell(13, 22);
+        //copy(c, NW, EAST);
+        /*
+          c.ylut(0x00);
+          c.c(YLUT);
+          c.f(false);
+          c.b(false);
+          c.t(false, false, true);
+          c.xi(SE);
+          c.yi(NORTH);
+          c.yo(false);
+          c.xo(false);
+          c.ylut(0x54);  // (x || z) & !y
+        */
+
+        /*        
+                  c = at40k.cell(2, 21);
+                  c.ylut(0x00);
+                  c.c(YLUT);
+                  c.f(false);
+                  c.b(false);
+                  c.t(false, false, true);
+                  c.xi(SE);
+                  c.yi(WEST);
+                  c.yo(false);
+                  c.xo(false);
+                  c.ylut(0xE8);
+                  //at40k.cell(2, 21).xlut(0xF0);
+
+                  at40k.cell(3, 22).ylut(LUT_OTHER);
+                  at40k.cell(3, 22).xi(SW);
+        */
+        //at40k.iob_top(5, true).enableOutput(SOUTH);
+        //at40k.iob_top(5, false).enableOutput(SE);
+    }
+
+    public static int yofs = mullers ? 19 : 22;
+    public static void counter(FpslicDevice at40k, SlipwayBoard device) throws Exception {
+        // watch for rising edge from south, emit pulse on Xout (to NE)
+        //copy(at40k.cell(16,23), SW, WEST);
+        
+        for(int x=22; x>=1; x-=2) {
+            pulse_detect(at40k.cell(x, yofs), SE,      false);
+            pulse_detect(at40k.cell(x, yofs-1), EAST,    true);
+            pulse_copy(at40k.cell(x-1, yofs), SE, SOUTH, false);
+            pulse_copy(at40k.cell(x-1, yofs-1), NE, NORTH, true);
+
+            //pulse_detect(at40k.cell(15, 22), NORTH, false);
+            //pulse_detect(at40k.cell(16, 22), NW,    true);
+            //pulse_copy(at40k.cell(16, 21), NW, WEST, false);
+            //pulse_copy(at40k.cell(15, 21), NE, EAST, true);
+        }
+        for(int x=23; x>1; x-=2) {
+            pulse_detect(at40k.cell(x-1, yofs-2), SW,    false);
+            pulse_detect(at40k.cell(x-1, yofs-3), WEST,  true);
+            pulse_copy(at40k.cell(x, yofs-2), SW, SOUTH, false);
+            pulse_copy(at40k.cell(x, yofs-3), NW, NORTH, true);
+
+            //pulse_detect(at40k.cell(15, 22), NORTH, false);
+            //pulse_detect(at40k.cell(16, 22), NW,    true);
+            //pulse_copy(at40k.cell(16, 21), NW, WEST, false);
+            //pulse_copy(at40k.cell(15, 21), NE, EAST, true);
+        }
+        copy(at40k.cell(1, yofs-2), SOUTH, SOUTH);
+        copy(at40k.cell(1, yofs-3), NORTH, NORTH);
+        at40k.cell(1, yofs-3).ylut(~at40k.cell(1, yofs-3).ylut());
+        at40k.cell(1, yofs-3).xlut(~at40k.cell(1, yofs-3).xlut());
+
+        copy(at40k.cell(23, yofs), SOUTH, SOUTH);
+        copy(at40k.cell(23, yofs-1), SOUTH, SOUTH);
+
+        for(int i=23; i>yofs; i--) copy(at40k.cell(1, i), SOUTH, SOUTH);
+
+        //at40k.iob_top(1, true).slew(SLOW);
+        //at40k.iob_top(1, false).slew(SLOW);
+
+    }
+
+    public static void fill(FpslicDevice at40k, SlipwayBoard device, int num) throws Exception {
+        //muller(at40k.cell(PIPELEN,22), NE, WEST);
+        FpslicDevice.Cell a = at40k.cell(10,22);
+        FpslicDevice.Cell b = at40k.cell(11,22);
+        a.ylut(0x00);
+        for(int i=0; i<num; i++) {
+            //System.out.println(i);
+            b.lut(0xff, 0xff);
+            device.getFpslicDevice().flush();
+            try { Thread.sleep(1); } catch (Exception e) { }
+            b.lut(0x00, 0x00);
+            device.getFpslicDevice().flush();
+            try { Thread.sleep(1); } catch (Exception e) { }
+        }
+        b.ylut(0xB2);
+        a.ylut(0xB2);
+    }
+
+    public static void drain(FpslicDevice at40k, SlipwayBoard device) throws Exception {
+        FpslicDevice.Cell a = at40k.cell(10,22);
+        FpslicDevice.Cell b = at40k.cell(11,22);
+        a.lut(0x00, 0x00);
+        b.lut(0x00, 0x00);
+        for(int i=0; i<30; i++) {
+            //System.out.println(i);
+            a.lut(0xff, 0xff);
+            device.getFpslicDevice().flush();
+            try { Thread.sleep(1); } catch (Exception e) { }
+            a.lut(0x00, 0x00);
+            device.getFpslicDevice().flush();
+            try { Thread.sleep(1); } catch (Exception e) { }
+        }
+        b.ylut(0xB2);
+        a.ylut(0xB2);
+    }
+
+    public static void doitx(FpslicDevice at40k, SlipwayBoard device) throws Exception {
+        for(int i=5; i<PIPELEN+1; i++) bounce(at40k.cell(i, 23), SE,                     SOUTH);
+        for(int x=5; x<PIPELEN;   x++) muller(at40k.cell(x, 22), x==PIPELEN-1 ? SE : NE, WEST);
+        
+        bounce(at40k.cell(PIPELEN,  21), NW, WEST);
+        
+        for(int x=5; x<PIPELEN;   x++) muller(at40k.cell(x, 21), SW,                     x==PIPELEN-1 ? NORTH : EAST);
+        for(int x=4; x<PIPELEN+1; x++) bounce(at40k.cell(x, 20), NW,                     NORTH);
+        
+        bounce(at40k.cell(4, 22), SE, EAST);
+        //muller(at40k.cell(4PIPELEN-1,21), SW, NORTH);
+        
+        //muller(at40k.cell(4,22), NE, WEST);
+        //at40k.cell(4,22).ylut(0xEE);
+        muller(at40k.cell(5, 22), NE, SOUTH);
+        muller(at40k.cell(5, 21), NW, EAST);
+        /*
+          for(int x=4; x>=0; x--) {
+          at40k.cell(x, 21).ylut(0xAA);
+          at40k.cell(x, 21).yi(EAST);
+          at40k.cell(x, 21).yo(false);
+          }
+
+          at40k.cell(0, 22).ylut(0xAA);
+          at40k.cell(0, 22).yi(SOUTH);
+          at40k.cell(0, 22).yo(false);
+
+          at40k.cell(0, 23).ylut(~0xAA);
+          at40k.cell(0, 23).xlut(~0xcc);
+          at40k.cell(0, 23).yi(SOUTH);
+          at40k.cell(0, 23).yo(false);
+        */
+        for(int x=3; x<=23; x+=2) {
+            pulse_detect(at40k.cell(x-1, 19), SW,    false);
+            pulse_detect(at40k.cell(x-1, 18), WEST,  true);
+            pulse_copy(at40k.cell(x, 19), SW, SOUTH, false);
+            pulse_copy(at40k.cell(x, 18), NW, NORTH, true);
+
+            if (x<17) {
+                pulse_detect(at40k.cell(x-1, 16), SW,    false);
+                pulse_detect(at40k.cell(x-1, 15), WEST,  true);
+                pulse_copy(at40k.cell(x, 16), SW, SOUTH, false);
+                pulse_copy(at40k.cell(x, 15), NW, NORTH, true);
+            }
+            //pulse_detect(at40k.cell(15, 22), NORTH, false);
+            //pulse_detect(at40k.cell(16, 22), NW,    true);
+            //pulse_copy(at40k.cell(16, 21), NW, WEST, false);
+            //pulse_copy(at40k.cell(15, 21), NE, EAST, true);
+        }
+        for(int x=14; x>=1; x--)
+            copy(at40k.cell(x, 17), EAST, EAST);
+        for(int x=4; x>=0; x--)
+            copy(at40k.cell(x, 21), EAST, EAST);
+        copy(at40k.cell(13, 17), SOUTH, SOUTH);
+
+        copy(at40k.cell(0, 20), NORTH, NORTH);
+        copy(at40k.cell(0, 19), NORTH, NORTH);
+        copy(at40k.cell(0, 18), NORTH, NORTH);
+        copy(at40k.cell(0, 17), NORTH, NORTH);
+        copy(at40k.cell(0, 16), NORTH, NORTH);
+        copy(at40k.cell(1, 16), WEST, WEST);
+        copy(at40k.cell(1, 15), NORTH, NORTH);
+
+        copy(at40k.cell(1, 20), SOUTH, SOUTH);
+        copy(at40k.cell(1, 19), SOUTH, SOUTH);
+        copy(at40k.cell(1, 18), SOUTH, SOUTH);
+
+        for(int y=20; y<=23; y++)
+            copy(at40k.cell(23, y), SOUTH, SOUTH);
+
+
+        //for(int x=19; x<=23; x++)
+        //copy(at40k.cell(x, 0), WEST, WEST);
+        //copy(at40k.cell(18, 19), NW, NW);
+        //at40k.iob_top(5, true).enableOutput(SOUTH);
+        //at40k.iob_top(5, false).enableOutput(SOUTH);
+    }
+}
diff --git a/src/edu/berkeley/slipway/demos/Demo2.java b/src/edu/berkeley/slipway/demos/Demo2.java
new file mode 100644 (file)
index 0000000..56c07b3
--- /dev/null
@@ -0,0 +1,254 @@
+package edu.berkeley.slipway.demos;
+
+import edu.berkeley.slipway.*;
+import edu.berkeley.slipway.util.*;
+import static java.awt.event.KeyEvent.*;
+import com.atmel.fpslic.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+import edu.berkeley.slipway.gui.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.color.*;
+import org.ibex.util.*;
+import java.io.*;
+import java.util.*;
+import gnu.io.*;
+
+public class Demo2 implements KeyListener {
+
+    public static void main(String[] s) throws Exception {
+        new Demo2().go(); 
+    }
+    public SlipwayBoard slipway;
+    public Demo2() throws Exception {
+        slipway = new SlipwayBoard();
+    }
+    public void go() throws Exception {
+        long begin = System.currentTimeMillis();
+        long end = System.currentTimeMillis();
+        Log.info(Demo.class, "finished in " + ((end-begin)/1000) + "s");
+        Thread.sleep(1000);
+
+
+        Log.info(Demo.class, "issuing command");
+
+        FpslicDevice device = slipway.getFpslicDevice();
+        FpslicDevice.Cell root = device.cell(5,5);
+
+        root.ylut(LUT_SELF);
+        root.yi(NORTH);
+        root.xi(NW);
+        root.wi(L0);
+        root.zi(L2);
+
+        root = root.north();
+        root.ylut(LUT_SELF);
+        root.yi(WEST);
+        root.out(1, true);
+        root.h(1, true);
+        root.wi(L1);
+        root.zi(L3);
+
+        root = root.west();
+        root.xi(SE);
+        root.ylut(LUT_SELF);
+        root.yi(SOUTH);
+        root.wi(L2);
+        root.zi(L4);
+
+        root = root.south();
+        root.ylut(LUT_SELF);
+        root.yi(EAST);
+        root.wi(L3);
+        root.zi(L0);
+        //root = root.n();
+
+        device.iob_bot(12, false).enableOutput(NW);
+        FpslicDevice.Cell c = device.cell(12, 0);
+        c.xo(c.east());
+        while(c.east() != null && c.east().east() != null) {
+            c.yo(c.east());
+            c = c.east();
+        }
+        device.flush();
+
+        FpslicDevice.Cell div = device.cell(19, 21);
+        while(div != null)
+            div = ExperimentUtils.divider(div);
+        device.flush();
+
+        int MAX=17;
+        for(int x=2; x<MAX+1; x++) {
+            c = device.cell(x, 20);
+            FpslicDevice.Cell bridge = x==2 ? c.sw()    : c.nw();
+            FpslicDevice.Cell pred   = x==MAX ? c.south() : c.east();
+            FpslicDevice.Cell next   = x==2 ? c.south() : c.west();
+            muller(c, pred, bridge, next);
+
+            c = c.south();
+            bridge = x==MAX ? c.ne()    : c.se();
+            pred   = x==2 ? c.north() : c.west();
+            next   = x==MAX ? c.north() : c.east();
+            muller(c, pred, bridge, next);
+        }
+        //device.cell(MAX+0,20).yi(WEST);
+        //device.cell(MAX+0,20).ylut(LUT_SELF);
+        //device.cell(MAX+1,20).yi(WEST);
+        //device.cell(MAX+1,20).ylut(LUT_SELF);
+        device.cell(MAX+2,20).yi(WEST);
+        device.cell(MAX+2,20).ylut(LUT_SELF);
+        device.cell(MAX+2,20).xlut(LUT_OTHER);
+        device.cell(18,20).ylut(LUT_SELF);
+        device.flush();
+        go2();
+    }
+
+    public void go2() throws Exception {
+        FpslicDevice device = slipway.getFpslicDevice();
+        setupScanCell();
+        device.flush();
+
+        vis = new Gui3(device, slipway);
+        vis.addKeyListener(this);
+        Frame fr = new Frame();
+        fr.setLayout(new BorderLayout());
+        fr.add(vis, BorderLayout.CENTER);
+        fr.pack();
+        fr.setSize(900, 900);
+        vis.repaint();
+        fr.repaint();
+        fr.show();
+        //synchronized(Demo.class) { Demo.class.wait(); }
+        while(true) {
+            try { Thread.sleep(500); } catch (Exception e) { }
+            synchronized(vis) {
+                scan();
+            }
+        }
+    }
+    Gui3 vis;
+    public void muller(FpslicDevice.Cell c, FpslicDevice.Cell pred, FpslicDevice.Cell bridge, FpslicDevice.Cell next) {
+        FpslicDevice device = slipway.getFpslicDevice();
+        bridge.yi(next);
+        bridge.xlut(LUT_OTHER);
+
+        c.yi(pred);
+        c.xi(bridge);
+        c.b(false);
+        c.f(false);
+        c.c(YLUT);
+        c.t(TMUX_FB);
+        c.ylut((LUT_SELF & ~LUT_OTHER) |
+               (LUT_Z    & ~LUT_OTHER) |
+               (LUT_Z    &   LUT_SELF));
+    }
+
+    public void setupScanCell() {
+        FpslicDevice device = slipway.getFpslicDevice();
+        FpslicDevice fpslic = (FpslicDevice)device;
+        fpslic.cell(23,15).h(3, true);
+        fpslic.cell(23,15).yi(L3);
+        fpslic.cell(23,15).ylut(0xAA);
+        fpslic.iob_right(15, true).enableOutput(WEST);
+
+        fpslic.cell(23,0).ylut(0x00);
+        fpslic.iob_right(0, true).enableOutput(WEST);
+        fpslic.flush();
+    }
+
+    public void keyTyped(KeyEvent k) { }
+    public void keyReleased(KeyEvent k) { }
+    public void keyPressed(KeyEvent k) {
+        switch(k.getKeyCode()) {
+            case VK_SPACE:
+                scan();
+                break;
+        }
+    }
+    public void scan() {
+        for(int x=0; x<4; x++)
+            for(int y=0; y<4; y++)
+                scan(vis.ca[x][y]);
+        for(int x=0; x<4; x++)
+            for(int y=0; y<4; y++)
+                scan(vis.ca[x][y]);
+    }
+    public void scan(final GuiCell c) {
+        try {
+            final FpslicDevice.Cell cell = c.fpslicCell;
+            scan(slipway, cell, YLUT, true);
+            int x = cell.col;
+            int y = cell.row;
+            slipway.readFpgaData(new BCB(c));
+            scan(slipway, cell, YLUT, false);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void scan(SlipwayBoard slipway, FpslicDevice.Cell cell, int source, boolean setup) {
+        FpslicDevice dev = slipway.getFpslicDevice();
+        if (setup) {
+            //if (source != NONE) cell.c(source);
+            if (cell.b()) cell.b(false);
+            if (cell.f()) cell.f(false);
+        }
+        if (cell.out(L3)!=setup) cell.out(L3, setup);
+        if (cell.vx(L3)!=setup) cell.v(L3, setup);
+
+        FpslicDevice.SectorWire sw = cell.vwire(L3);
+        //System.out.println("wire is: " + sw);
+
+        if (sw.row > (12 & ~0x3) && sw.north()!=null && sw.north().drives(sw))
+            sw.north().drives(sw, false);
+        while(sw.row > (12 & ~0x3) && sw.south() != null) {
+            //System.out.println(sw + " -> " + sw.south());
+            if (sw.drives(sw.south())!=setup) sw.drives(sw.south(), setup);
+            sw = sw.south();
+        }
+        if (sw.row < (12 & ~0x3) && sw.south() != null && sw.south().drives(sw))
+            sw.north().drives(sw, false);
+        while(sw.row < (12 & ~0x3) && sw.north() != null) {
+            //System.out.println(sw + " -> " + sw.north());
+            if (sw.drives(sw.north())!=setup) sw.drives(sw.north(), setup);
+            sw = sw.north();
+        }
+
+        //cell = dev.cell(19, 15);
+        cell = dev.cell(cell.col, 15);
+        /*
+        System.out.println("cell is " + cell);
+        cell.xlut(0xff);
+        cell.ylut(0xff);
+        cell.b(false);
+        cell.f(false);
+        cell.c(XLUT);
+        cell.out(L3, true);
+        cell.oe(NONE);
+        */
+        if (cell.hx(L3) != setup) cell.h(L3, setup);
+        if (cell.vx(L3) != setup) cell.v(L3, setup);
+        sw = cell.hwire(L3);
+
+        if (sw.west()!=null && sw.west().drives(sw)) { sw.west().drives(sw, false); }
+        while(sw.east() != null) {
+            //System.out.println(sw + " -> " + sw.east());
+            if (sw.drives(sw.east())!=setup) sw.drives(sw.east(), setup);
+            sw = sw.east();
+        }
+
+    }
+
+
+    private class BCB extends SlipwayBoard.ByteCallback {
+        GuiCell c;
+        public BCB(GuiCell c) {
+            this.c = c;
+        }
+        public void call(byte b) throws Exception {
+            boolean on = (b & 0x80) != 0;
+            c.val = on;
+            vis.repaint();
+        }
+    }
+}
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;
+    }
+
+
+
+}
diff --git a/src/edu/berkeley/slipway/demos/MicropipelineFifoDemo.java b/src/edu/berkeley/slipway/demos/MicropipelineFifoDemo.java
new file mode 100644 (file)
index 0000000..22d7c40
--- /dev/null
@@ -0,0 +1,183 @@
+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.*;
+
+
+/**
+ *  This demo runs the asynchronous micropipeline fifo experiment from
+ *  the FCCM paper.
+ *
+ *  Output is placed in misc/data/async/ as a collection of .csv
+ *  files.  Each file is named sizeXXX.csv, where XXX is the capacity
+ *  of the fifo.  Each line of each file is of the form
+ *  occupancy,tokenrate where occupancy is the proportion of the fifo
+ *  which is occupied (a number between 0 and 1) and tokenrate is the
+ *  number of millions of tokens per second observed at a fixed point
+ *  on the ring.  All files should be concatenated in order to
+ *  reproduce the graphs in the paper.
+ */
+public abstract class MicropipelineFifoDemo {
+
+    public SlipwayBoard slipway;
+    public FpslicDevice fpslic;
+    public FpslicDevice.Cell start;
+
+    // Abstract methods to implement //////////////////////////////////////////////////////////////////////////////
+
+    protected abstract int  numDivisors();
+    protected abstract void forceMasterSuccessor(boolean high);
+    protected abstract void unForceMasterSuccessor(boolean state);
+    protected abstract void unPauseMaster();
+    protected abstract void unPauseSlaves();
+    protected abstract void pauseMaster();
+    protected abstract void pauseSlaves();
+    protected abstract void resetAll();
+    protected abstract int  init(int size);
+    protected abstract int  init(int size, FpslicDevice.Cell start);
+
+    // Constructors //////////////////////////////////////////////////////////////////////////////
+
+    public MicropipelineFifoDemo() throws Exception {
+        System.err.println("MicropipelineFifoDemo: initializing board...");
+        slipway = new SlipwayBoard();
+        fpslic = slipway.getFpslicDevice();
+    }
+
+    public void mainx(String[] s) throws Exception {
+        System.err.println("MicropipelineFifoDemo: setting up scan cell...");
+        ExperimentUtils.setupScanCell(fpslic);
+
+        for(int i=0; i<255; i++) {
+            slipway.readInterruptCount();
+            System.err.print("\rMicropipelineFifoDemo: paranoia -- flushing interrupt count: " + i + "/254 ");
+        }
+        System.err.println();
+
+        for(int i=1; i<402; i+=2) go(i);
+        System.err.println("MicropipelineFifoDemo: experiment is finished");
+    }
+
+
+    // Experiment Logic //////////////////////////////////////////////////////////////////////////////
+
+    /** drain the fifo */
+    protected void drain() {
+        while(true){
+            pauseMaster();
+            pauseSlaves();
+            resetAll();
+            unPauseMaster();
+            unPauseSlaves();
+            slipway.readInterruptCount();
+            try { Thread.sleep(100); } catch (Exception e) { }
+            int rc = slipway.readInterruptCount();
+            if (rc!=0) {
+                System.err.println("flush() failed => " + rc);
+                try { Thread.sleep(1000); } catch (Exception e) { }
+                continue;
+            }
+            break;
+        }
+    }
+
+    /** fill the fifo with "count" tokens */
+    protected void fill(int count) {
+        boolean yes = false;
+        for(int i=0; i<count; i++) {
+            pauseSlaves();
+            forceMasterSuccessor(yes);
+            unPauseSlaves();
+            yes = !yes;
+        }
+        if (count>0)
+            unForceMasterSuccessor(!yes);
+    }
+
+    public void go(int size) throws Exception {
+        int rsize = init(size, fpslic.cell(20, 20));
+
+        String sizes = rsize+"";
+        while(sizes.length()<3) sizes = "0"+sizes;
+        String fname = "misc/data/async/size"+sizes+".csv";
+        if (!new File(fname).exists()) {
+            System.err.println();
+            System.err.println("MicropipelineFifoDemo:   fifo size is "+rsize+"...");
+            PrintWriter outfile = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fname)));
+            for(int i=rsize; i>=0; i-=2)
+                test(i, rsize, outfile);
+            outfile.flush();
+            outfile.close();
+        } else {
+            System.out.println("MicropipelineFifoDemo: file " + fname + " already exists; skipping");
+        }
+    }
+
+    public void test(int count, int size, PrintWriter outfile) throws Exception {
+        double[] results = new double[numtrials];
+
+      
+        int clockdivisor = 64;
+        double occupancy = ((double)count)/((double)size);
+        int clockrate = 24; // (in mhz)
+
+        for(int i=0; i<results.length; i++) {
+            init(size);
+            fpslic.flush();
+            drain();
+            fpslic.flush();
+            fill(count);
+            fpslic.flush();
+
+            unPauseMaster();
+            unPauseSlaves();
+            fpslic.flush();
+
+            slipway.readInterruptCount();
+            Thread.sleep(1000);
+            int tokens = slipway.readInterruptCount();
+            
+            double elapsed = (double)(slipway.readInterruptCountTime()/clockrate);
+            
+            int multiplier = 1;
+            for(int j=0; j<numDivisors(); j++) multiplier *= 2;
+            multiplier /= clockdivisor;
+
+            double result = (tokens*multiplier)/elapsed; // in millions
+            results[i] = result;
+        }
+
+        double max = 0;
+        double min = Double.MAX_VALUE;
+        double total = 0;
+        for(int i=0; i<numtrials; i++) {
+            max = Math.max(max, results[i]);
+            min = Math.min(min, results[i]);
+            total += results[i];
+        }
+        total -= max;
+        total -= min;
+        total /= (numtrials-2);
+
+        // result is transitions/sec
+        outfile.println(size + ", " + occupancy + ", " + total);
+        outfile.flush();
+        System.out.println("num_tokens/capacity: "+count+"/"+size+
+                           "  occupancy="+((int)(occupancy*100.0)) +"%"+
+                           "  tokenrate=" + total);
+    }
+    private static final int numtrials = 5;
+
+    protected FpslicDevice.Cell topLeft() { return start.north().north(); }
+
+
+
+}
+
+
index e1c5ec7..d4f7b3e 100644 (file)
@@ -1,7 +1,6 @@
 package edu.berkeley.slipway.gui;
 
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
index 5dbac20..fb2ed23 100644 (file)
@@ -3,7 +3,6 @@ package edu.berkeley.slipway.gui;
 import com.atmel.fpslic.*;
 import edu.berkeley.slipway.*;
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
@@ -20,8 +19,8 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
     Graphics2D g;
     G gg;
 
-    Fpslic at40k;
-    FtdiBoard drone;
+    FpslicDevice fpslic;
+    SlipwayBoard slipway;
 
     private Cell[][] ca = new Cell[128][];
 
@@ -34,7 +33,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
             final JFileChooser fc = new JFileChooser();
             int returnVal = fc.showSaveDialog(this);
             Writer pw = new OutputStreamWriter(new FileOutputStream(fc.getSelectedFile()));
-            FpslicUtil.writeMode4(pw, drone);
+            slipway.getFpslicDevice().writeMode4(pw);
             pw.flush();
             pw.close();
             System.err.println("done writing");
@@ -47,7 +46,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
         try {
             final JFileChooser fc = new JFileChooser();
             int returnVal = fc.showOpenDialog(this);
-            FpslicUtil.readMode4(new FileInputStream(fc.getSelectedFile()), drone);
+            slipway.getFpslicDevice().readMode4(new FileReader(fc.getSelectedFile()));
             System.err.println("done reading");
             repaint();
         } catch (Exception e) {
@@ -55,18 +54,18 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
         }
     }
 
-    public Gui(Fpslic at40k, FtdiBoard drone) {
-        this(at40k, drone, 24, 24);
+    public Gui(FpslicDevice fpslic, SlipwayBoard slipway) {
+        this(fpslic, slipway, 24, 24);
     }
-    public Gui(Fpslic at40k, FtdiBoard drone, int width, int height) {
-        super(drone);
-        this.at40k = at40k;
-        this.drone = drone;
+    public Gui(FpslicDevice fpslic, SlipwayBoard slipway, int width, int height) {
+        super(slipway);
+        this.fpslic = fpslic;
+        this.slipway = slipway;
         for(int i=0; i<ca.length; i++)
             ca[i] = new Cell[128];
         for(int x=0; x<width; x++)
             for(int y=0; y<height; y++)
-                new Cell(x,y, at40k.cell(x, y));
+                new Cell(x,y, fpslic.cell(x, y));
 
 
 
@@ -81,7 +80,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
 
 
         /*
-        Fpslic.Cell c = at40k.cell(0,0);
+        FpslicDevice.Cell c = fpslic.cell(0,0);
         for(int i=0; i<256; i++) {
             c.ylut(i);
             System.out.println(c.printYLut());
@@ -90,7 +89,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
     }
 
     public class Cell {
-        Fpslic.Cell cell;
+        FpslicDevice.Cell cell;
         boolean in = false;
         public boolean scanme = false;
         public boolean xon = false;
@@ -98,7 +97,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
         public boolean xknown = false;
         public boolean yknown = false;
         int _x, _y;
-        public Cell(int x, int y, Fpslic.Cell cell) {
+        public Cell(int x, int y, FpslicDevice.Cell cell) {
             _x = x;
             _y = y;
             ca[_x][_y] = this;
@@ -746,7 +745,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
         return null;
     }
 
-    public static boolean xlut_relevant(Fpslic.Cell c) {
+    public static boolean xlut_relevant(FpslicDevice.Cell c) {
         return c.xlut_relevant();
     }
 
@@ -757,16 +756,16 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
     }
 
     public void scan() {
-        for(int x=0; x<at40k.getWidth(); x++)
-            for(int y=0; y<at40k.getHeight(); y++)
+        for(int x=0; x<fpslic.getWidth(); x++)
+            for(int y=0; y<fpslic.getHeight(); y++)
                 if (ca[x][y] != null)
                     if (ca[x][y].scanme())
                         scan(ca[x][y]);
     }
     public void scan(final Gui.Cell c) {
         try {
-            final Fpslic.Cell cell = c.cell;
-            scan(at40k, cell, NONE, true);
+            final FpslicDevice.Cell cell = c.cell;
+            scan(fpslic, cell, NONE, true);
             boolean safe = !cell.fb_relevant();
             if (cell.xo()) safe = false;
             if (cell.yo()) safe = false;
@@ -777,13 +776,13 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
                 int oldc = cell.c();
                 if (cell.xlut_relevant()) {
                     cell.c(XLUT);
-                    drone.readBus(new BCB(c, XLUT));
+                    slipway.readFpgaData(new BCB(c, XLUT));
                 } else {
                     c.xknown = false;
                 }
                 if (cell.ylut_relevant()) {
                     cell.c(YLUT);
-                    drone.readBus(new BCB(c, YLUT));
+                    slipway.readFpgaData(new BCB(c, YLUT));
                 } else {
                     c.yknown = false;
                 }
@@ -794,18 +793,18 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
                         if (!cell.xlut_relevant()) {
                             c.xknown = false;
                         } else {
-                            drone.readBus(new BCB(c, XLUT));
+                            slipway.readFpgaData(new BCB(c, XLUT));
                         }
                         /*
                         if (!cell.yo())
-                        for(Fpslic.Cell c2 : new Fpslic.Cell[] { cell.north(), cell.south(), cell.east(), cell.west() })
+                        for(FpslicDevice.Cell c2 : new FpslicDevice.Cell[] { cell.north(), cell.south(), cell.east(), cell.west() })
                             if (c2!=null && !c2.relevant()) {
-                                scan(at40k, cell, NONE, false);
+                                scan(fpslic, cell, NONE, false);
                                 c2.yo(cell);
                                 c2.c(YLUT);
-                                scan(at40k, c2, NONE, true);
-                                drone.readBus(new BCB(c, YLUT));
-                                scan(at40k, c2, NONE, false);
+                                scan(fpslic, c2, NONE, true);
+                                slipway.readFpgaData(new BCB(c, YLUT));
+                                scan(fpslic, c2, NONE, false);
                                 c2.yi(NONE);
                                 return;
                             }
@@ -816,18 +815,18 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
                         if (!cell.ylut_relevant()) {
                             c.yknown = false;
                         } else {
-                            drone.readBus(new BCB(c, YLUT));
+                            slipway.readFpgaData(new BCB(c, YLUT));
                         }
                         /*
                         if (!cell.xo())
-                        for(Fpslic.Cell c2 : new Fpslic.Cell[] { cell.nw(), cell.sw(), cell.ne(), cell.se() })
+                        for(FpslicDevice.Cell c2 : new FpslicDevice.Cell[] { cell.nw(), cell.sw(), cell.ne(), cell.se() })
                             if (c2!=null && !c2.relevant()) {
-                                scan(at40k, cell, NONE, false);
+                                scan(fpslic, cell, NONE, false);
                                 c2.xo(cell);
-                                scan(at40k, c2, NONE, true);
+                                scan(fpslic, c2, NONE, true);
                                 c2.c(XLUT);
-                                drone.readBus(new BCB(c, XLUT));
-                                scan(at40k, c2, NONE, false);
+                                slipway.readFpgaData(new BCB(c, XLUT));
+                                scan(fpslic, c2, NONE, false);
                                 c2.xi(NONE);
                                 return;
                             }
@@ -836,29 +835,29 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
                         break;
                     case ZMUX: {
                         /*
-                        scan(at40k, cell, NONE, false);
+                        scan(fpslic, cell, NONE, false);
                         c.xknown = false;
                         c.yknown = false;
                         if (!cell.xo())
-                        for(Fpslic.Cell c2 : new Fpslic.Cell[] { cell.nw(), cell.sw(), cell.ne(), cell.se() })
+                        for(FpslicDevice.Cell c2 : new FpslicDevice.Cell[] { cell.nw(), cell.sw(), cell.ne(), cell.se() })
                             if (c2!=null && !c2.relevant()) {
-                                scan(at40k, cell, NONE, false);
+                                scan(fpslic, cell, NONE, false);
                                 c2.xo(cell);
-                                scan(at40k, c2, NONE, true);
+                                scan(fpslic, c2, NONE, true);
                                 c2.c(XLUT);
-                                drone.readBus(new BCB(c, XLUT));
-                                scan(at40k, c2, NONE, false);
+                                slipway.readFpgaData(new BCB(c, XLUT));
+                                scan(fpslic, c2, NONE, false);
                                 c2.xi(NONE);
                                 return;
                             }
                         if (!cell.yo())
-                        for(Fpslic.Cell c2 : new Fpslic.Cell[] { cell.north(), cell.south(), cell.east(), cell.west() })
+                        for(FpslicDevice.Cell c2 : new FpslicDevice.Cell[] { cell.north(), cell.south(), cell.east(), cell.west() })
                             if (c2!=null && !c2.relevant()) {
                                 c2.yo(cell);
                                 c2.c(YLUT);
-                                scan(at40k, c2, NONE, true);
-                                drone.readBus(new BCB(c, YLUT));
-                                scan(at40k, c2, NONE, false);
+                                scan(fpslic, c2, NONE, true);
+                                slipway.readFpgaData(new BCB(c, YLUT));
+                                scan(fpslic, c2, NONE, false);
                                 c2.yi(NONE);
                                 break;
                             }
@@ -868,13 +867,13 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
                 }
                 
             }
-            scan(at40k, cell, NONE, false);
+            scan(fpslic, cell, NONE, false);
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 
-    public static void scan(Fpslic dev, Fpslic.Cell cell, int source, boolean setup) {
+    public static void scan(FpslicDevice dev, FpslicDevice.Cell cell, int source, boolean setup) {
         if (setup) {
             if (source != NONE) cell.c(source);
             if (cell.b()) cell.b(false);
@@ -883,7 +882,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
         if (cell.out(L3)!=setup) cell.out(L3, setup);
         if (cell.vx(L3)!=setup) cell.v(L3, setup);
 
-        Fpslic.SectorWire sw = cell.vwire(L3);
+        FpslicDevice.SectorWire sw = cell.vwire(L3);
         //System.out.println("wire is: " + sw);
 
         if (sw.row > (12 & ~0x3) && sw.north()!=null && sw.north().drives(sw))
@@ -928,7 +927,7 @@ public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListene
 
 
     int made = 0;
-    private class BCB extends FtdiBoard.ByteCallback {
+    private class BCB extends SlipwayBoard.ByteCallback {
         Gui.Cell c;
         int who;
         public BCB(Gui.Cell c, int who) {
index efc5957..813c24e 100644 (file)
@@ -3,7 +3,6 @@ package edu.berkeley.slipway.gui;
 import com.atmel.fpslic.*;
 import edu.berkeley.slipway.*;
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
@@ -20,8 +19,8 @@ public class Gui2 extends ZoomingPanel2 implements KeyListener, MouseMotionListe
     Graphics2D g;
     G gg;
 
-    Fpslic at40k;
-    FtdiBoard drone;
+    FpslicDevice at40k;
+    SlipwayBoard drone;
 
     private Cell[][] ca = new Cell[128][];
 
@@ -29,11 +28,11 @@ public class Gui2 extends ZoomingPanel2 implements KeyListener, MouseMotionListe
     public static final Color nonselectedcell = new Color(0xee, 0xee, 0xee);
     public static final Color selectedcell    = new Color(0x00, 0x00, 0x00);
 
-    private FtdiBoard ftdiboard;
-    public Gui2(Fpslic at40k, FtdiBoard drone) {
+    private SlipwayBoard ftdiboard;
+    public Gui2(FpslicDevice at40k, SlipwayBoard drone) {
         this(at40k, drone, 24, 24);
     }
-    public Gui2(Fpslic at40k, FtdiBoard drone, int width, int height) {
+    public Gui2(FpslicDevice at40k, SlipwayBoard drone, int width, int height) {
         this.at40k = at40k;
         this.drone = drone;
         for(int i=0; i<ca.length; i++)
@@ -44,7 +43,7 @@ public class Gui2 extends ZoomingPanel2 implements KeyListener, MouseMotionListe
     }
 
     public class Cell {
-        Fpslic.Cell cell;
+        FpslicDevice.Cell cell;
         boolean in = false;
         public boolean scanme = false;
         public boolean xon = false;
@@ -52,7 +51,7 @@ public class Gui2 extends ZoomingPanel2 implements KeyListener, MouseMotionListe
         public boolean xknown = false;
         public boolean yknown = false;
         int _x, _y;
-        public Cell(int x, int y, Fpslic.Cell cell) {
+        public Cell(int x, int y, FpslicDevice.Cell cell) {
             _x = x;
             _y = y;
             ca[_x][_y] = this;
@@ -706,7 +705,7 @@ public class Gui2 extends ZoomingPanel2 implements KeyListener, MouseMotionListe
         return null;
     }
 
-    public static boolean xlut_relevant(Fpslic.Cell c) {
+    public static boolean xlut_relevant(FpslicDevice.Cell c) {
         return c.xlut_relevant();
     }
 
@@ -717,7 +716,7 @@ public class Gui2 extends ZoomingPanel2 implements KeyListener, MouseMotionListe
 
 
     int made = 0;
-    private class BCB extends FtdiBoard.ByteCallback {
+    private class BCB extends SlipwayBoard.ByteCallback {
         Gui2.Cell c;
         int who;
         public BCB(Gui2.Cell c, int who) {
index 7eb6e17..26d869f 100644 (file)
@@ -5,7 +5,6 @@ package edu.berkeley.slipway.gui;
 import com.atmel.fpslic.*;
 import edu.berkeley.slipway.*;
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import static java.awt.event.KeyEvent.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
@@ -20,20 +19,20 @@ import static edu.berkeley.slipway.gui.GuiConstants.*;
 
 public class Gui3 extends Canvas implements MouseWheelListener, MouseMotionListener, KeyListener {
 
-    Fpslic at40k;
-    FtdiBoard drone;
+    FpslicDevice at40k;
+    SlipwayBoard slipway;
 
     private int width;
     private int height;
     private int magnify = 0;
     public GuiCell[][] ca = new GuiCell[128][];
-    private FtdiBoard ftdiboard;
-    public Gui3(Fpslic at40k, FtdiBoard drone) {
-        this(at40k, drone, 24, 24);
+    private SlipwayBoard ftdiboard;
+    public Gui3(FpslicDevice at40k, SlipwayBoard slipway) {
+        this(at40k, slipway, 24, 24);
     }
-    public Gui3(Fpslic at40k, FtdiBoard drone, int width, int height) {
+    public Gui3(FpslicDevice at40k, SlipwayBoard slipway, int width, int height) {
         this.at40k = at40k;
-        this.drone = drone;
+        this.slipway = slipway;
         this.width = width;
         this.height = height;
         for(int i=0; i<ca.length; i++)
@@ -51,7 +50,7 @@ public class Gui3 extends Canvas implements MouseWheelListener, MouseMotionListe
         repaint();
     }
 
-    Fpslic.Cell selectedCell = null;
+    FpslicDevice.Cell selectedCell = null;
     public void _paint(Graphics2D g_) {
         int SIZE = 100;
         //g_.setStroke(new BasicStroke((float)1.0/SIZE));
index 3e06b7f..ea1b362 100644 (file)
@@ -16,13 +16,13 @@ public class GuiCell {
     private static final int LOCAL_ROUTING_CHANNEL_WIDTH = 7;
 
     public boolean val = false;
-    public final Fpslic.Cell fpslicCell;
+    public final FpslicDevice.Cell fpslicCell;
     private GuiGate xgate = new GuiGate(this);
     private GuiGate ygate = new GuiGate(this);
 
     R gateArea = null;
 
-    public GuiCell(Fpslic.Cell fpslicCell) {
+    public GuiCell(FpslicDevice.Cell fpslicCell) {
         this.fpslicCell = fpslicCell;
     }
 
index 574da09..f2c9e1d 100644 (file)
@@ -2,7 +2,6 @@ package edu.berkeley.slipway.gui;
 
 import com.atmel.fpslic.*;
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
diff --git a/src/edu/berkeley/slipway/gui/Inspector.java b/src/edu/berkeley/slipway/gui/Inspector.java
new file mode 100644 (file)
index 0000000..f222499
--- /dev/null
@@ -0,0 +1,96 @@
+package edu.berkeley.slipway.gui;
+
+import static com.atmel.fpslic.FpslicConstants.*;
+import static edu.berkeley.slipway.gui.GuiConstants.*;
+import com.atmel.fpslic.*;
+import edu.berkeley.slipway.*;
+import java.awt.*;
+
+public class Inspector {
+
+    private static P bump(P p, R r) {
+        p = p.translate(0, 15);
+        if (p.y + 15 > r.maxy()) {
+            p = new P(p.x + 200, r.miny() + 20);
+        }
+        return p;
+    }
+    public static void draw(G g, R r, FpslicDevice.Cell cell) {
+        g.color(0x000000);
+        r.fill(g);
+        g.color(0xffffff);
+        g.setFont(new Font("monospaced", 0, 14));
+        if (cell==null) return;
+
+        int line = (int)(r.miny() + 10);
+        P p = new P(r.minx() + 10, r.miny() + 20);
+        g.drawString("selected: " + cell.col + "," + cell.row,          p);   p = bump(p, r);
+        g.drawString("    xlut: " + XLUT_EQUATIONS[cell.xlut() & 0xff], p);   p = bump(p, r);
+        g.drawString("    ylut: " + YLUT_EQUATIONS[cell.ylut() & 0xff], p);   p = bump(p, r);
+        String xi = "??";
+        switch(cell.xi()) {
+            case NW : xi = "NW"; break;
+            case NE : xi = "NE"; break;
+            case SW : xi = "SW"; break;
+            case SE : xi = "SE"; break;
+            case NONE  : xi = "."; break;
+            default:  xi = "L"+(cell.xi()-L0); break;
+        }
+        g.drawString("x-in mux: " + xi, p);   p = bump(p, r);
+
+        String yi = "??";
+        switch(cell.yi()) {
+            case NORTH : yi = "NORTH"; break;
+            case SOUTH : yi = "SOUTH"; break;
+            case EAST  : yi = "EAST"; break;
+            case WEST  : yi = "WEST"; break;
+            case NONE  : yi = "."; break;
+            default:     yi = "L"+(cell.yi()-L0); break;
+        }
+        g.drawString("y-in mux: " + yi, p);   p = bump(p, r);
+
+        g.drawString("w-in mux: " + (cell.wi()==NONE ? "." : ("L"+(cell.wi()-L0))),
+                     p);   p = bump(p, r);
+        g.drawString("z-in mux: " + (cell.zi()==NONE ? "." : ("L"+(cell.zi()-L0))),
+                     p);   p = bump(p, r);
+
+        String tm = "??";
+        switch(cell.t()) {
+            case TMUX_FB:       tm = "fb"; break;
+            case TMUX_W_AND_FB: tm = "w&fb"; break;
+            case TMUX_Z:        tm = "z"; break;
+            case TMUX_W_AND_Z:  tm = "w&z"; break;
+            case TMUX_W:        tm = "w"; break;
+        }
+        g.drawString("t-in mux: " + tm, p);   p = bump(p, r);
+
+        g.drawString(" set/rst: " + (cell.ff_reset_value() ? "reset=SET" : "."),
+                     p);   p = bump(p, r);
+
+        String outs = "";
+        for(int i=0; i<5; i++) outs += (cell.out(L0+i) ? (i+" ") : ". ");
+        g.drawString("     out: " + outs,
+                     p);   p = bump(p, r);
+        String hs = "";
+        for(int i=0; i<5; i++) hs += (cell.hx(L0+i) ? (i+" ") : ". ");
+        g.drawString("  h conn: " + hs,
+                     p);   p = bump(p, r);
+        String vs = "";
+        for(int i=0; i<5; i++) vs += (cell.vx(L0+i) ? (i+" ") : ". ");
+        g.drawString("  v conn: " + vs,
+                     p);   p = bump(p, r);
+        g.drawString("out enab: " + (cell.oe()==H4 ? "H4" : cell.oe()==V4 ? "V4" : "."),
+                     p);   p = bump(p, r);
+        g.drawString("   c-mux: " + (cell.c()==ZMUX ? "zmux" : cell.c()==XLUT ? "x-lut" : "y-lut"),
+                     p);   p = bump(p, r);
+        g.drawString("  fb src: " + (cell.f() ? "clocked" : "."),
+                     p);   p = bump(p, r);
+        g.drawString("  bypass: " + (cell.b() ? "clocked" : "."),
+                     p);   p = bump(p, r);
+        g.drawString("   x out: " + (cell.xo() ? (cell.b() ? "register" : "center") : "."),
+                     p);   p = bump(p, r);
+        g.drawString("   y out: " + (cell.yo() ? (cell.b() ? "register" : "center") : "."),
+                     p);   p = bump(p, r);
+
+    }
+}
\ No newline at end of file
diff --git a/src/edu/berkeley/slipway/gui/Keyboard.java b/src/edu/berkeley/slipway/gui/Keyboard.java
new file mode 100644 (file)
index 0000000..e69de29
index 90ec157..338b913 100644 (file)
@@ -1,7 +1,6 @@
 package edu.berkeley.slipway.gui;
 
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
index fc51932..14e73c0 100644 (file)
@@ -2,7 +2,6 @@ package edu.berkeley.slipway.gui;
 
 import com.atmel.fpslic.*;
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
@@ -27,9 +26,9 @@ public abstract class ZoomingPanel extends JComponent implements KeyListener, Mo
     private   Point2D recenter = new Point2D.Double(-100, 2500);
     private   Point2D recenter2;
 
-    private FtdiBoard ftdiboard;
+    private SlipwayBoard ftdiboard;
 
-    public ZoomingPanel(FtdiBoard ftdiboard) {
+    public ZoomingPanel(SlipwayBoard ftdiboard) {
         this.ftdiboard = ftdiboard;
         setDoubleBuffered(true);
         addKeyListener(this);
@@ -111,7 +110,7 @@ public abstract class ZoomingPanel extends JComponent implements KeyListener, Mo
             }
         }
         Gui.Cell cell = whichCell(mousex, mousey);
-        Fpslic.Cell c = cell == null ? null : cell.cell;
+        FpslicDevice.Cell c = cell == null ? null : cell.cell;
         if ((k.getModifiers() & k.ALT_MASK) != 0 || (k.getModifiers() & k.META_MASK) != 0)
             switch(k.getKeyCode()) {
                 case VK_S:
@@ -243,7 +242,7 @@ public abstract class ZoomingPanel extends JComponent implements KeyListener, Mo
                     return;
                 }
                 case VK_I: {
-                    System.out.println("interrupt count => " + ftdiboard.readCount());
+                    System.out.println("interrupt count => " + ftdiboard.readInterruptCount());
                     repaint();
                     return;
                 }
index ee7cb97..a3dddc2 100644 (file)
@@ -2,7 +2,6 @@ package edu.berkeley.slipway.gui;
 
 import com.atmel.fpslic.*;
 import static com.atmel.fpslic.FpslicConstants.*;
-import static com.atmel.fpslic.FpslicUtil.*;
 import edu.berkeley.slipway.*;
 import java.awt.*;
 import java.awt.geom.*;
@@ -118,7 +117,7 @@ public abstract class ZoomingPanel2 extends JComponent implements KeyListener, M
             }
         }
         Gui2.Cell cell = whichCell(mousex, mousey);
-        Fpslic.Cell c = cell == null ? null : cell.cell;
+        FpslicDevice.Cell c = cell == null ? null : cell.cell;
         if ((k.getModifiers() & k.ALT_MASK) != 0 || (k.getModifiers() & k.META_MASK) != 0)
             switch(k.getKeyCode()) {
                 case VK_0: {
diff --git a/src/edu/berkeley/slipway/mpar/HashMapBag.java b/src/edu/berkeley/slipway/mpar/HashMapBag.java
new file mode 100644 (file)
index 0000000..90eb4f2
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
+
+package edu.berkeley.slipway.mpar;
+import java.util.*;
+
+/** a mapping from keys of type <tt>K</tt> to <i>sets</i> of values of type <tt>T</tt> */
+public final class HashMapBag<K,V> implements MapBag<K,V> {
+
+    private final HashMap<K,HashSet<V>> hm = new HashMap<K,HashSet<V>>();
+
+    public void add(K k, V v) {
+        HashSet<V> hs = hm.get(k);
+        if (hs==null) hm.put(k, hs = new HashSet<V>());
+        size -= hs.size();
+        hs.add(v);
+        size += hs.size();
+    }
+
+    public void addAll(K k, Iterable<V> iv) {
+        for(V v : iv) add(k, v);
+    }
+
+    public int size(K k) {
+        HashSet<V> ret = hm.get(k);
+        return ret==null ? 0 : ret.size();
+    }
+    public HashSet<V> getAll(K k) {
+        HashSet<V> ret = hm.get(k);
+        if (ret==null) return new HashSet<V>();
+        return ret;
+    }
+
+    public void remove(K k, V v) {
+        if (hm.get(k)==null) return;
+        HashSet<V> hs = hm.get(k);
+        if (hs==null) return;
+        size -= hs.size();
+        hs.remove(v);
+        size += hs.size();
+    }
+
+    public void removeAll(K k, Iterable<V> iv) {
+        for(V v : iv) remove(k, v);
+    }
+
+    public void clear() { hm.clear(); }
+
+    public boolean contains(K k, V v) {
+        return hm.get(k)!=null && hm.get(k).contains(v);
+    }
+
+    public void addAll(HashMapBag<K,V> hmb) {
+        for(K k : hmb) addAll(k, hmb.getAll(k));
+    }
+    public void removeAll(HashMapBag<K,V> hmb) {
+        for(K k : hmb) removeAll(k, hmb.getAll(k));
+    }
+
+    public Iterator<K> iterator() { return hm.keySet().iterator(); }
+    public int size() { return size; }
+    private int size = 0;
+}
index 7c19aed..6eb1bd6 100644 (file)
@@ -1,12 +1,15 @@
 package edu.berkeley.slipway.mpar;
 import com.atmel.fpslic.*;
+import java.awt.*;
 import byucc.edif.tools.merge.*;
 import byucc.edif.*;
 import java.io.*;
 import java.util.*;
 import edu.berkeley.slipway.*;
+import edu.berkeley.abits.*;
 import com.atmel.fpslic.*;
 import static com.atmel.fpslic.FpslicConstants.*;
+import static edu.berkeley.slipway.mpar.PhysicalFpslic.*;
 
 // FIXME: sometimes gets stuck in a loop routing the last few nets
 
@@ -27,145 +30,134 @@ import static com.atmel.fpslic.FpslicConstants.*;
 
 public class MPARDemo {
 
-    public static final double alphaParameter = 00.9;
-    public static final double betaParameter  = 02.5;
-    public static final double gammaParameter =  1.0;
 
-    /*
-      test code for inter-sector switchboxes
-    public static void main2() throws Exception {
-        Fpslic fpslic = new FtdiBoard();
-        // set up scan cell
-        fpslic.cell(23,15).h(3, true);
-        fpslic.cell(23,15).yi(L3);
-        fpslic.cell(23,15).ylut(0xAA);
-        fpslic.iob_right(15, true).enableOutput(WEST);
-        fpslic.cell(23,0).ylut(0x00);
-        fpslic.iob_right(0, true).enableOutput(WEST);
-        fpslic.flush();
-        for(int x=0; x<20; x++) {
-            for(int y=0; y<20; y++) {
-                for(int l=0; l<5; l++) {
-                    for(int v = 0; v <= 1; v++) {
-                        boolean vert = v==1;
-                        int newx = vert ? x   : x-1;
-                        int newy = vert ? y-1 : y;
-                        if (newx<0 || newy<0) continue;
-                        if (vert  && (y%4) != 0) continue;
-                        if (!vert && (x%4) != 0) continue;
-
-                        int layer = l;
-                        if (layer==3) continue;
-                        Fpslic.Cell c  = fpslic.cell(x, y);
-                        Fpslic.Cell c2 = fpslic.cell(newx, newy);
-                        Fpslic.SectorWire sw1 = vert ? c.vwire(layer)  : c.hwire(layer);
-                        Fpslic.SectorWire sw2 = vert ? c2.vwire(layer) : c2.hwire(layer);
-                        sw1.drives(sw2, true);
-
-                        c.c(YLUT);
-                        if (vert) c.v(L0 + layer, true);
-                        else      c.h(L0 + layer, true);
-                        c.out(L0 + layer, true);
-                        c.b(false);
-                        
-                        c2.yi(L0 + layer);
-                        if (vert) c2.v(L0 + layer, true);
-                        else      c2.h(L0 + layer, true);
-                        c2.ylut(LUT_SELF);
-                        c2.c(YLUT);
-                        c2.b(false);
-                        
-                        System.out.print(x+","+y+","+l+","+(vert?"v":"h")+": ");
-                        c.ylut(0x00);
-                        fpslic.flush();
-                        boolean good = scan(fpslic, c2)==0;
-                        if (!good) fails++;
-                        System.out.print(good ? "ok " : "bad ");
-                        c.ylut(0xff);
-                        fpslic.flush();
-                        good = scan(fpslic, c2)!=0;
-                        if (!good) fails++;
-                        System.out.print(good ? "ok " : "bad ");
-                        System.out.println();
-                        sw1.drives(sw2, false);
-                        if (vert) c.v(layer, false);
-                        else      c.h(layer, false);
-                        c.out(layer, false);
-                    }
-                }
-            }
-        }
-        System.out.println("fails = " + fails);
-        
-    }
-    public static int fails = 0;
-    */
+    public static final double alphaParameter    =   0.9;
+    public static final double betaParameter     =   0.5;
+    public static final double wireCost          =   0.005;  
+    public static final double wireCostPlacement =   0.01;   // cost of an uncongested net (cost of congested net is 1)
+    //public static final double gammaParameter  =   1.0;
+    public static final double lambda            =  0.7;
+
+    public static double temperature = 300.0;
+    public static double congestion = 0;
+    public static double timingpenalty = 0;
 
     public static void main(String[] s) throws Exception {
-        EdifEnvironment topEnv = new EdifEnvironment("top");
-        EdifLibraryManager elm = new EdifLibraryManager(topEnv);
-        EdifLibrary initLib = new EdifLibrary(elm, "initLib");
-        EdifEnvironment env = EdifMergeParser.parseAndMerge(s, initLib);
-        System.out.println("top is " + env.getTopCell());
-        NetList fnl = new NetList();
-
-        for(Iterator<EdifCellInstance> it = (Iterator<EdifCellInstance>)env.getTopCell().cellInstanceIterator();
-            it.hasNext();
-            ) {
-            NetList.Node n = fnl.createNode(it.next(), null);
-        }
 
-        Fpslic fpslic = new FtdiBoard();
-        int width = 20;
-        int height = 20;
-        PhysicalDevice pd = new PhysicalFpslic(fpslic, width, height);
+        NetList fnl = new NetList(s[0]);
+        int width = 12;
+        int height = 12;
 
-        int px = 0;
-        int py = 0;
+        //SlipwayBoard slipway = new SlipwayBoard();
+        Board slipway = new FakeBoard(24, 24);
 
-        // crude map
+        FpslicDevice fpslic = (FpslicDevice)slipway.getDevice();
+        while(true) {
+        PhysicalDevice pd = new PhysicalFpslic(fpslic, width, height);
+
+        Placement placement = new Placement(fnl, pd);
+        Routing routing = new Routing(placement);
         Random rand = new Random();
-        boolean[][] used = new boolean[width][height];
-        for(NetList.Node n : fnl.nodes) {
-            while(true) {
-                px = Math.abs(rand.nextInt()) % width;
-                py = Math.abs(rand.nextInt()) % height;
-                if (!used[px][py]) {
-                    used[px][py] = true;
-                    System.out.println("placed " + n + " at ("+px+","+py+")");
-                    pd.getCell(px, py).place(n);
-                    break;
-                }
-            }
-        }
+        placement.random(rand);
+        routing.routeAll();
 
         int trial = 0;
-        HashSet<NetList.LogicalNet> needUnroute = new HashSet<NetList.LogicalNet>();
-        while(true) {
+        int num_moves = width*height;
+
+        Visualization vis = new Visualization((PhysicalFpslic)pd);
+
+        boolean alldone = false;
+        long lastDraw = System.currentTimeMillis();
+        OUT: while(true) {
             System.out.println();
-            System.out.println("routing trial " + (++trial));
-            for(NetList.LogicalNet net : fnl.nets) {
-                if (net.getSize() <= 1) continue;
-                net.route(fpslic, pd);
-            }
-            double congestion = 0;
-            int overrouted = 0;
-            needUnroute.clear();
-            for(PhysicalDevice.PhysicalNet pn : pd) {
-                if (pn.isCongested()) {
-                    overrouted++;
-                    congestion += pn.getCongestion();
+            double max_swap_dist = 3 * Math.max(width,height) * Math.exp(-1 / temperature);
+            System.out.println("round " + (++trial) + "  (temp="+temperature+", maxdist="+max_swap_dist+")");
+            
+            if (alldone) break;
+
+            congestion = routing.measureCongestion();
+            timingpenalty = routing.measureTimingpenalty();
+            double wirecost = routing.measureWireCost();
+            int swaps = 0;
+            num_moves = 200;
+
+            for(int i=0; i<num_moves; i++) {
+                System.out.print("\r  [place: " + i + "/" + num_moves + "  congestion="+congestion+"]");
+                NetList.Node node1 = fnl.randomNode(rand);
+                PhysicalDevice.PhysicalCell cell1 = placement.nodeToCell(node1);
+                PhysicalDevice.PhysicalCell cell2 = cell1.randomCellWithin(rand, max_swap_dist);
+                NetList.Node node2 = placement.cellToNode(cell2);
+
+                // FIXME: cache and reuse "newrouting"
+                // also: fold down newrouting to collapse parentage
+                routing.checkpoint();
+                routing.unroute(node1);
+                routing.unroute(node2);
+                placement.unplace(cell1);
+                placement.unplace(cell2);
+                placement.place(node1, cell2);
+                placement.place(node2, cell1);
+                routing.routeAll();
+
+                double newcongestion = routing.measureCongestion();
+                double newwirecost = routing.measureWireCost();
+                double newtimingpenalty = routing.measureTimingpenalty();
+                double lam = 0.1;
+                double deltaCost =
+                    lam * ((newcongestion - congestion) / Math.max(0.001, congestion))
+                    +
+                    //(1-lam) * ((newwirecost - wirecost) / wirecost)
+                    //+
+                    (1-lam) * ((newtimingpenalty - timingpenalty) / Math.max(0.001, timingpenalty))
+                    ;
+                double swapProbability = Math.exp((-1 * deltaCost) / temperature);
+                //double dist = Math.sqrt( (5-p2x)*(5-p2x) + (5-p2y)*(5-p2y) );
+                double rad = 4;
+                /*
+                if (rand2 == null)
+                    swapProbability = Math.max(0, Math.min(swapProbability, dist / Math.sqrt(rad+rad)));
+                */
+                boolean doSwap = Math.random() < swapProbability;
+                if (doSwap) {
+                    swaps++;
+                    congestion = newcongestion;
+                    wirecost = newwirecost;
+                    timingpenalty = newtimingpenalty;
+                } else {
+                    placement.unplace(cell1);
+                    placement.unplace(cell2);
+                    placement.place(node1, cell1);
+                    placement.place(node2, cell2);
+                    routing.rollback();
                 }
-                pn.updateCongestion();
-                if (pn.isCongested())
-                    for(NetList.LogicalNet n : pn.getLogicalNets())
-                        needUnroute.add(n);
             }
-            System.out.println("  overrouted="+overrouted+", congestion="+congestion +
-                               ", ripping up " + needUnroute.size() +" nets of " + fnl.nets.size());
-            if (overrouted <= 0) break;
-            for(NetList.LogicalNet net : needUnroute) net.unroute();
+            double acceptance = ((double)swaps) / num_moves;
+            double gamma = 0;
+            if (acceptance > 0.96) gamma = 0.5;
+            else if (acceptance > 0.8) gamma = 0.9;
+            else if (acceptance > 0.15) gamma = 0.95;
+            else gamma = 0.8;
+
+            System.out.println("  acceptance="+acceptance);
+            temperature = temperature * gamma;
+            int num_routes = num_moves - swaps;
+            num_routes = 2;
+            for(int i=0; i<num_routes; i++) {
+                int overrouted = routing.measureOverloaded();
+                routing.unrouteOverloaded();
+                routing.reRouteAll();
+                System.out.print("\r  [route "+i+"/"+num_routes+"] overrouted="+overrouted+" congestion="+routing.measureCongestion()+"     penalty="+timingpenalty);
+                routing.updateCongestion(alphaParameter, betaParameter);
+                if (overrouted==0 && timingpenalty < 1) alldone = true;
+            }
+            num_moves = (int)(300 * gamma * gamma);
+            vis.draw(placement, routing, false);
+            System.out.println();
         }
+        vis.draw(placement, routing, true);
+        placement.setPlacement();
+        routing.setPips(true);
+        System.out.println("wire utilization: " + Math.round(routing.measureWireUtilization()*100));
 
         // set up scan cell
         fpslic.cell(23,15).h(3, true);
@@ -175,28 +167,32 @@ public class MPARDemo {
         fpslic.cell(23,0).ylut(0x00);
         fpslic.iob_right(0, true).enableOutput(WEST);
         fpslic.flush();
-
+        /*
         int xwidth = 8;
-        while(true) {
+        temperature = 0;
+        while(temperature==0) {
             int a = Math.abs(rand.nextInt()) % (1 << xwidth);
             int b = Math.abs(rand.nextInt()) % (1 << xwidth);
-            setInput(fnl, fpslic, "a",  a);
-            setInput(fnl, fpslic, "b",  b);
-            setInput(fnl, fpslic, "ci", 0);
-            int result = getOutput(fnl, fpslic, "out");
+            setInput(fnl, fpslic, "a",  a, placement);
+            setInput(fnl, fpslic, "b",  b, placement);
+            setInput(fnl, fpslic, "ci", 0, placement);
+            int result = getOutput(fnl, fpslic, slipway, "out", placement);
+            int expect = (a+b) & ~(-1 << (xwidth+1));
             System.out.println(Integer.toString(a,16) + " + " +
                                Integer.toString(b,16) + " = " +
                                Integer.toString(result,16) +
-                               " [ " + (a+b==result ? "ok" : "bad" ) + " ] ");
+                               " [ " + (expect==result ? "ok" : "bad" ) + " ] " + (Integer.toString((result^(expect)),16)));
         }
+        */
+    }
     }
 
 
     private static int ret;
-    public static synchronized int scan(final Fpslic device, final Fpslic.Cell cell) {
+    public static synchronized int scan(final FpslicDevice device, final SlipwayBoard slipway, final FpslicDevice.Cell cell) {
         try {
-            scan(device, cell, YLUT, true);
-            ((FtdiBoard)device).readBus(new FtdiBoard.ByteCallback() {
+            scan(device, cell, XLUT, true);
+            slipway.readFpgaData(new SlipwayBoard.ByteCallback() {
                     public void call(byte b) throws Exception {
                         ret = b;
                         synchronized(device) {
@@ -209,12 +205,12 @@ public class MPARDemo {
                     device.wait();
                 } catch (Exception e) { throw new RuntimeException(e); }
             }
-            scan(device, cell, YLUT, false);
+            scan(device, cell, XLUT, false);
             return ret;
         } catch (Exception e) { throw new RuntimeException(e); }
     }
 
-    public static void scan(Fpslic dev, Fpslic.Cell cell, int source, boolean setup) {
+    public static void scan(FpslicDevice dev, FpslicDevice.Cell cell, int source, boolean setup) {
         if (setup) {
             //if (source != NONE) cell.c(source);
             if (cell.b()) cell.b(false);
@@ -223,7 +219,7 @@ public class MPARDemo {
         if (cell.out(L3)!=setup) cell.out(L3, setup);
         if (cell.vx(L3)!=setup) cell.v(L3, setup);
 
-        Fpslic.SectorWire sw = cell.vwire(L3);
+        FpslicDevice.SectorWire sw = cell.vwire(L3);
         //System.out.println("wire is: " + sw);
 
         if (sw.row > (12 & ~0x3) && sw.north()!=null && sw.north().drives(sw))
@@ -266,30 +262,30 @@ public class MPARDemo {
 
     }
 
-        public static void setInput(NetList fnl, Fpslic fpslic, String prefix, int val) {
-            for(int i=0; ; i++) {
-                NetList.Node n = fnl.top.get(prefix + "["+i+"]");
-                if (n==null && i==0) n = fnl.top.get(prefix);
-                if (n==null) return;
-                Fpslic.Cell c = n.getPlacement(fpslic);
-                c.c(XLUT);
-                c.b(false);
-                c.xlut((val & 0x1)==0 ? 0x00 : 0xff);
-                val = val >> 1;
-            }
+    public static void setInput(NetList fnl, FpslicDevice fpslic, String prefix, int val, Placement placement) {
+        for(int i=0; ; i++) {
+            NetList.Node n = fnl.top.get(prefix + "["+i+"]");
+            if (n==null && i==0) n = fnl.top.get(prefix);
+            if (n==null) return;
+            FpslicDevice.Cell c = ((PhysicalFpslic.PhysicalFpslicCell)placement.nodeToCell(n)).cell();
+            c.c(XLUT);
+            c.b(false);
+            c.xlut((val & 0x1)==0 ? 0x00 : 0xff);
+            val = val >> 1;
         }
-        public static int getOutput(NetList fnl, Fpslic fpslic, String prefix) {
+    }
+    public static int getOutput(NetList fnl, FpslicDevice fpslic, SlipwayBoard slipway, String prefix, Placement placement) {
             int val = 0;
             for(int i=0; ; i++) {
                 NetList.Node n = fnl.top.get(prefix+"["+i+"]");
                 if (n==null && i==0) n = fnl.top.get(prefix);
                 if (n==null) return val;
-                Fpslic.Cell c = n.getPlacement(fpslic);
+                FpslicDevice.Cell c = ((PhysicalFpslic.PhysicalFpslicCell)placement.nodeToCell(n)).cell();
                 c.xlut(LUT_SELF);
                 c.c(XLUT);
                 c.b(false);
                 fpslic.flush();
-                int scan = scan(fpslic, c);
+                int scan = scan(fpslic, slipway, c);
                 val |= ((scan==0 ? 0 : 1) << i);
             }
         }
diff --git a/src/edu/berkeley/slipway/mpar/MapBag.java b/src/edu/berkeley/slipway/mpar/MapBag.java
new file mode 100644 (file)
index 0000000..bb63c5a
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2006-2007 all rights reserved; see LICENSE file for BSD-style license
+
+package edu.berkeley.slipway.mpar;
+import java.util.*;
+
+/** a mapping from keys of type <tt>K</tt> to <i>sets</i> of values of type <tt>V</tt> */
+public interface MapBag<K,V> extends Iterable<K> {
+    public void add(K k, V v);
+    public void addAll(K k, Iterable<V> iv);
+    public Iterator<K> iterator();
+}
index 50f59b5..60e2d9b 100644 (file)
@@ -4,31 +4,45 @@ import byucc.edif.tools.merge.*;
 import byucc.edif.*;
 import java.io.*;
 import java.util.*;
+import java.awt.*;
 import edu.berkeley.slipway.*;
 import com.atmel.fpslic.*;
 import static com.atmel.fpslic.FpslicConstants.*;
 import static edu.berkeley.slipway.mpar.MPARDemo.*;
 
-public class NetList {
+public class NetList implements Iterable<NetList.Node> {
+
+    public NetList(String s) throws EdifNameConflictException, InvalidEdifNameException {
+        EdifEnvironment topEnv = new EdifEnvironment("top");
+        EdifLibraryManager elm = new EdifLibraryManager(topEnv);
+        EdifLibrary initLib = new EdifLibrary(elm, "initLib");
+        EdifEnvironment env = EdifMergeParser.parseAndMerge(new String[] { s }, initLib);
+        for(Iterator<EdifCellInstance> it = (Iterator<EdifCellInstance>)env.getTopCell().cellInstanceIterator();
+            it.hasNext();
+            ) {
+            createNode(it.next(), null);
+        }
+    }
 
     private HashMap<String,Integer> ids = new HashMap<String,Integer>();
 
-    public HashSet<Node>        nodes = new HashSet<Node>();
+    public HashSet<Node>        nodes  = new HashSet<Node>();
+    public ArrayList<Node>      nodes_ = new ArrayList<Node>();
+
     public HashSet<LogicalNet>  nets  = new HashSet<LogicalNet>();
+    public Iterable<NetList.LogicalNet> getLogicalNets() { return nets; }
 
     /** a node is some primitive element; a potential configuration of a CLB */
-    public class Node {
-        public PhysicalDevice.PhysicalCell physicalCell = null;
+    public class Node implements Iterable<Node.Port> {
         private final String type;
         private final int    id;
 
-        public int x = -1;
-        public int y = -1;
-
         private HashMap<String,Port> ports = new HashMap<String,Port>();
+        public Iterator<Port> iterator() { return ports.values().iterator(); }
 
         public Node(String type) {
             nodes.add(this);
+            nodes_.add(this);
             this.type = type.toLowerCase();
             Integer num = ids.get(type);
             this.id = num == null ? 0 : num.intValue();
@@ -36,9 +50,7 @@ public class NetList {
         }
         public String getType() { return type; }
         public String toString() {
-            if (x==-1 || y==-1)
-                return type + "["+id+"]";
-            return type + "@("+x+","+y+")";
+            return type;
         }
         public Port getPort(String name, boolean driver) {
             Port p = ports.get(name);
@@ -46,10 +58,7 @@ public class NetList {
             return p;
         }
 
-        public Fpslic.Cell getPlacement(Fpslic fpslic) { return fpslic.cell(x, y); }
-
         private int portIndex = 0;
-
         /** a port is an input or output to a Node */
         public class Port {
             private final String name;
@@ -76,46 +85,13 @@ public class NetList {
 
     /** a Net is a collection of ports which are wired together */
     public class LogicalNet implements Iterable<Node.Port> {
-        private Node.Port driver = null;
-        private HashSet<Node.Port> ports = new HashSet<Node.Port>();
-        private HashSet<PhysicalDevice.PhysicalPip> pips = new HashSet<PhysicalDevice.PhysicalPip>();
-        private HashSet<PhysicalDevice.PhysicalNet> pns = new HashSet<PhysicalDevice.PhysicalNet>();
-
-        public void addPhysicalNet(PhysicalDevice.PhysicalNet pn) { pns.add(pn); }
-        public void removePhysicalNet(PhysicalDevice.PhysicalNet pn) { pns.remove(pn); }
-        public void addPhysicalPip(PhysicalDevice.PhysicalPip pip) { pips.add(pip); }
+         Node.Port driver = null;
+         HashSet<Node.Port> ports = new HashSet<Node.Port>();
 
         public LogicalNet() { nets.add(this); }
         public Iterator<Node.Port> iterator() { return ports.iterator(); }
         public int getSize() { return ports.size(); }
-        public boolean routed = false;
-        public void unroute() {
-            for(PhysicalDevice.PhysicalPip pip : pips) pip.set(false);
-            while(pns.size() > 0) pns.iterator().next().removeLogicalNet(this);
-            pips.clear();
-            pns.clear();
-            routed = false;
-        }
-        public void route(Fpslic fpslic, PhysicalDevice pd) {
-            if (driver == null) return;
-            if (routed) return;
-            Node.Port[] dests = new Node.Port[ports.size() - (ports.contains(driver) ? 1 : 0)];
-            int j = 0;
-            for(Node.Port p : ports)
-                if (p != driver)
-                    dests[j++] = p;
-            PhysicalDevice.PhysicalNet[] destsp = new PhysicalDevice.PhysicalNet[dests.length];
-            for(int i=0; i<dests.length; i++) {
-                Node.Port dest = dests[i];
-                switch(dest.index) {
-                    case 0: destsp[i] = dest.getNode().physicalCell.getNet("xi"); break;
-                    case 1: destsp[i] = dest.getNode().physicalCell.getNet("yi"); break;
-                    default: throw new Error();
-                }
-            }
-            driver.getNode().physicalCell.getNet("out").route(destsp, this);
-            routed = true;
-        }
+
         public void add(Node.Port p) {
             if (p.driver) {
                 if (driver != null && driver != p)
@@ -182,4 +158,10 @@ public class NetList {
         }
         return n;
     }
+
+    public Node randomNode(Random rand) {
+        return nodes_.get(Math.abs(rand.nextInt()) % nodes_.size());
+    }
+
+    public Iterator<Node> iterator() { return nodes.iterator(); }
 }
index 70397e7..e611e7a 100644 (file)
@@ -9,6 +9,7 @@ import static edu.berkeley.slipway.mpar.MPARDemo.*;
 public abstract class PhysicalDevice implements Iterable<PhysicalDevice.PhysicalNet> {
 
     public abstract PhysicalCell getCell(int col, int row);
+    public abstract PhysicalCell randomCell(Random rand);
 
     private HashSet<PhysicalNet> allPhysicalNets = new HashSet<PhysicalNet>();
     public Iterator<PhysicalNet> iterator() { return allPhysicalNets.iterator(); }
@@ -17,54 +18,35 @@ public abstract class PhysicalDevice implements Iterable<PhysicalDevice.Physical
         public abstract PhysicalNet getNet(String name);
         public abstract void setFunction(String type);
         public abstract void place(NetList.Node n);
+        public abstract PhysicalCell randomCellWithin(Random rand, double percentOfDevice);
     }
 
+    private int master_idx = 0;
+
+    public int getNumPhysicalNets() { return master_idx; }
     public class PhysicalNet implements Iterable<PhysicalPip>, Comparable<PhysicalNet> {
 
-        // per-par-iteration variables
-        private  double      congestion = 0;
-        private  int         load = 0;
+        public final int idx = master_idx++;
 
         // temporary variables used during route searches
-        private  double      distance = Double.MAX_VALUE;
-        private  PhysicalNet backpointer = null;
+        double      distance = Double.MAX_VALUE;
+        double      delay = Double.MAX_VALUE;
+        PhysicalNet backpointer = null;
+        int iteration = 0;
+        int depth = 0;
+        boolean remaining = false;
 
         // adjacent pips
-        private final HashSet<PhysicalPip> pips = new HashSet<PhysicalPip>();
+        public final HashSet<PhysicalPip> pips = new HashSet<PhysicalPip>();
 
         private String name;
 
-        // logical nets currently mapped onto this physical net
-        private HashSet<NetList.LogicalNet> logicalNets = new HashSet<NetList.LogicalNet>();
-
-        public double getCongestion() { return congestion; }
-        public boolean isCongested() { return load >= 2; }
-        public void updateCongestion() {
-            congestion = congestion * alphaParameter;
-            if (isCongested()) congestion += betaParameter;
-        }
-
-        public Iterable<NetList.LogicalNet> getLogicalNets() { return logicalNets; }
-        public void addLogicalNet(NetList.LogicalNet net) {
-            if (logicalNets.contains(net)) return;
-            logicalNets.add(net);
-            load++;
-            if (load >= 2) congestion += betaParameter;
-            net.addPhysicalNet(this);
-        }
-        public void removeLogicalNet(NetList.LogicalNet net) {
-            if (!logicalNets.contains(net)) return;
-            logicalNets.remove(net);
-            load--;
-            net.removePhysicalNet(this);
-        }
-
         /** ordering is based on distance so we can use the Java PriorityQueue class */
         public int compareTo(PhysicalNet pn) {
             double x = distance - pn.distance;
-            return distance > pn.distance
+            return x>0
                 ? 1
-                : distance < pn.distance
+                : x<0
                 ? -1
                 : 0;
         }
@@ -83,79 +65,28 @@ public abstract class PhysicalDevice implements Iterable<PhysicalDevice.Physical
                         return pip;
             return null;
         }
-        public void route(PhysicalNet[] dests, NetList.LogicalNet logicalNet) {
-            HashSet<PhysicalNet> remainingDests = new HashSet<PhysicalNet>();
-            for(PhysicalNet dest : dests) remainingDests.add(dest);
-
-            HashSet<PhysicalNet> needsReset = new HashSet<PhysicalNet>();
-            PriorityQueue<PhysicalNet> pq = new PriorityQueue<PhysicalNet>();
-            needsReset.add(this);
-            this.distance = 0;
-            pq.add(this);
-
-            OUTER: while(true) {
-                PhysicalNet pn = pq.poll();
-                if (pn==null) throw new Error("unroutable! " + this + " -> " + dests[0]);
-                double frontier = pn.distance;
-                for(PhysicalPip pip : pn)
-                    for(PhysicalNet net : pip.getDrivenNets()) {
-                        double newfrontier = frontier + pip.getCost(pn, net) + net.getCongestion();
-
-                        // penalty for using any net already routed in this iteration (makes routing order-sensitive)
-                        if (net.load >= 1) newfrontier = newfrontier + 20;
-
-                        if (net.distance <= newfrontier) continue;
-                        pq.remove(net);  // if already in there
-                        net.distance = newfrontier;
-                        pq.add(net);
-                        needsReset.add(net);
-                        net.backpointer = pn;
-
-                        if (remainingDests.contains(net)) {
-                            remainingDests.remove(net);
-                            if (remainingDests.size()==0) break OUTER;
-                            // Vaughn Betz style multiterminal routing: once we reach one sink, make every node on the path
-                            // "distance zero" from the source.
-                            for(PhysicalNet pnx = net; pnx != null; pnx = pnx.backpointer) {
-                                pnx.distance = 0;
-                                pq.add(pnx);
-                            }
-                            break;
-                        }
-                    }
-            }
-
-            for(PhysicalNet dest : dests)
-                for(PhysicalNet pn = dest; pn != null && pn.backpointer != null; pn = pn.backpointer) {
-                    pn.addLogicalNet(logicalNet);
-                    pn.distance = Double.MAX_VALUE;
-                    PhysicalPip pip = pn.getPipFrom(pn.backpointer);
-                    pip.set(true);
-                    logicalNet.addPhysicalPip(pip);
-                }
-
-            for(PhysicalNet pn : needsReset) {
-                pn.distance    = Double.MAX_VALUE;
-                pn.backpointer = null;
-            }
-        }
     }
         
     public abstract class PhysicalPip {
-        private PhysicalNet   driver;
-        private PhysicalNet[] driven;
+        public PhysicalNet   driver;
+        public PhysicalNet[] driven;
         private String name;
-        private double defaultCost;
+        double defaultCost;
+        double defaultDelay = 1;
+        public abstract boolean prohibited();
         public String toString() { return name; }
         public PhysicalNet   getDriverNet()  { return driver; }
         public PhysicalNet[] getDrivenNets() { return driven; }
+        public double        getDelay(PhysicalNet in, PhysicalNet out) { return defaultDelay; }
         public double        getCost(PhysicalNet in, PhysicalNet out) { return defaultCost; }
-        public PhysicalPip(String name, PhysicalNet driver, PhysicalNet[] driven) { this(name, driver, driven, 0.05); }
+        public abstract int getX();
+        public abstract int getY();
+        public PhysicalPip(String name, PhysicalNet driver, PhysicalNet[] driven) { this(name, driver, driven, wireCost); }
         public PhysicalPip(String name, PhysicalNet driver, PhysicalNet[] driven, double defaultCost) {
             this.name = name;
             this.driver = driver;
             this.driven = driven;
-            this.defaultCost = defaultCost;
+            this.defaultCost = 1;
             if (driver != null) driver.addPip(this);
             for(PhysicalNet pn : driven) pn.addPip(this);
         }
index 748145f..e524c64 100644 (file)
@@ -10,7 +10,10 @@ import static com.atmel.fpslic.FpslicConstants.*;
 import static edu.berkeley.slipway.mpar.MPARDemo.*;
 
 public class PhysicalFpslic extends PhysicalDevice {
-    private final Fpslic fpslic;
+    public static int CELLSEP  = 40;
+    public static int PLANESEP = 3;
+
+    private final FpslicDevice fpslic;
         
     public final int width;
     public final int height;
@@ -25,7 +28,7 @@ public class PhysicalFpslic extends PhysicalDevice {
         return cells[col][row];
     }
 
-    public PhysicalFpslic(final Fpslic fpslic, int width, int height) {
+    public PhysicalFpslic(final FpslicDevice fpslic, int width, int height) {
         this.fpslic = fpslic;
         this.width = width;
         this.height = height;
@@ -36,12 +39,14 @@ public class PhysicalFpslic extends PhysicalDevice {
                     for(int xc=x; xc<x+4; xc++) {
                         PhysicalNet vwire = new PhysicalNet("("+xc+","+y+"-"+(y+3)+")");
                         for(int yc=y; yc<y+4; yc++)
-                            sectorWires[xc][yc][p][0] = vwire;
+                            if (xc < sectorWires.length && yc < sectorWires[xc].length)
+                                sectorWires[xc][yc][p][0] = vwire;
                     }
                     for(int yc=y; yc<y+4; yc++) {
                         PhysicalNet hwire = new PhysicalNet("("+x+"-"+(x+3)+","+yc+")");
                         for(int xc=x; xc<x+4; xc++)
-                            sectorWires[xc][yc][p][1] = hwire;
+                            if (xc < sectorWires.length && yc < sectorWires[xc].length)
+                                sectorWires[xc][yc][p][1] = hwire;
                     }
                 }
 
@@ -51,18 +56,26 @@ public class PhysicalFpslic extends PhysicalDevice {
                     final int xc = x;
                     final int yc = y;
                     final int pc = p;
-                    new PhysicalPip("xxx",
-                                    sectorWires[x-1][y][p][1],
-                                    new PhysicalNet[] { sectorWires[x][y][p][1] },
-                                    5) {
+                    new PhysicalFpslicPip(x,
+                                          y,
+                                          -1 * (4-p) * PLANESEP,
+                                          -1 * (0+p) * PLANESEP,
+                                          "xxx",
+                                          sectorWires[x-1][y][p][1],
+                                          new PhysicalNet[] { sectorWires[x][y][p][1] },
+                                          5) {
                         public void set(boolean connected) {
                             fpslic.cell(xc-1, yc).hwire(pc).drives(fpslic.cell(xc, yc).hwire(pc), connected);
                         }
                     };
-                    new PhysicalPip("xxx",
-                                    sectorWires[x][y][p][1],
-                                    new PhysicalNet[] { sectorWires[x-1][y][p][1] },
-                                    5) {
+                    new PhysicalFpslicPip(x,
+                                          y,
+                                          -1 * (4-p) * PLANESEP,
+                                          -1 * (0+p) * PLANESEP,
+                                          "xxx",
+                                          sectorWires[x][y][p][1],
+                                          new PhysicalNet[] { sectorWires[x-1][y][p][1] },
+                                          5) {
                         public void set(boolean connected) {
                             fpslic.cell(xc, yc).hwire(pc).drives(fpslic.cell(xc-1, yc).hwire(pc), connected);
                         }
@@ -77,18 +90,26 @@ public class PhysicalFpslic extends PhysicalDevice {
                     final int xc = x;
                     final int yc = y;
                     final int pc = p;
-                    new PhysicalPip("xxx",
-                                    sectorWires[x][y-1][p][0],
-                                    new PhysicalNet[] { sectorWires[x][y][p][0] },
-                                    5) {
+                    new PhysicalFpslicPip(x,
+                                          y,
+                                          -1 * (4-p) * PLANESEP,
+                                          -1 * (0+p) * PLANESEP,
+                                          "xxx",
+                                          sectorWires[x][y-1][p][0],
+                                          new PhysicalNet[] { sectorWires[x][y][p][0] },
+                                          5) {
                         public void set(boolean connected) {
                             fpslic.cell(xc, yc-1).vwire(pc).drives(fpslic.cell(xc, yc).vwire(pc), connected);
                         }
                     };
-                    new PhysicalPip("xxx",
-                                    sectorWires[x][y][p][0],
-                                    new PhysicalNet[] { sectorWires[x][y-1][p][0] },
-                                    5) {
+                    new PhysicalFpslicPip(x,
+                                          y,
+                                          -1 * (4-p) * PLANESEP,
+                                          -1 * (0+p) * PLANESEP,
+                                          "xxx",
+                                          sectorWires[x][y][p][0],
+                                          new PhysicalNet[] { sectorWires[x][y-1][p][0] },
+                                          5) {
                         public void set(boolean connected) {
                             fpslic.cell(xc, yc).vwire(pc).drives(fpslic.cell(xc, yc-1).vwire(pc), connected);
                         }
@@ -111,7 +132,15 @@ public class PhysicalFpslic extends PhysicalDevice {
         return sectorWires[col][row][plane][horizontal ? 1 : 0];
     }
 
+    public PhysicalCell randomCell(Random rand) {
+        int x = (Math.abs(rand.nextInt()) % width);
+        int y = (Math.abs(rand.nextInt()) % height);
+        return getCell(x, y);
+    }
+
     public class PhysicalFpslicCell extends PhysicalCell {
+        private int x;
+        private int y;
         private int col;
         private int row;
         private PhysicalNet   outputNet;
@@ -119,18 +148,28 @@ public class PhysicalFpslic extends PhysicalDevice {
         private PhysicalNet   yin;
         private PhysicalNet[] local = new PhysicalNet[5];
 
+        public PhysicalCell randomCellWithin(Random rand, double percentOfDevice) {
+            int distance = (int)(percentOfDevice * Math.max(width, height));
+            if (distance < 4) distance = 4;
+            // FIXME ugly
+            while(true) {
+                int dx = (Math.abs(rand.nextInt()) % (distance*2+1));
+                int dy = (Math.abs(rand.nextInt()) % (distance*2+1));
+                PhysicalCell pc = getCell(col+dx-distance, row+dy-distance);
+                if (pc != null) return pc;
+            }
+        }
         public void place(NetList.Node n) {
-            int x = col;
-            int y = row;
-            n.x = x;
-            n.y = y;
-            n.physicalCell = this;
-            Fpslic.Cell cell = fpslic.cell(x,y);
+            this.x = col;
+            this.y = row;
+            FpslicDevice.Cell cell = fpslic.cell(x,y);
             cell.c(XLUT);
             cell.b(false);
             cell.f(false);
             cell.xi(NW);
             cell.yi(EAST);
+            //cell.xo(true);
+            //cell.yo(true);
             String type = n.getType();
             if      (type.equals("and2"))    cell.xlut(LUT_SELF & LUT_OTHER);
             else if (type.equals("or2"))     cell.xlut(LUT_SELF | LUT_OTHER);
@@ -140,7 +179,7 @@ public class PhysicalFpslic extends PhysicalDevice {
             else if (type.equals("cell0"))   return;
         }
 
-        private Fpslic.Cell cell() { return fpslic.cell(col, row); }
+        public FpslicDevice.Cell cell() { return fpslic.cell(col, row); }
         public PhysicalNet getNet(String name) {
             if (name.equals("out")) return outputNet;
             if (name.equals("xi"))  return xin;
@@ -149,7 +188,7 @@ public class PhysicalFpslic extends PhysicalDevice {
         }
 
         public void setFunction(String type) {
-            Fpslic.Cell cell = cell();
+            FpslicDevice.Cell cell = cell();
             cell.c(XLUT);
             cell.xo(false);
             cell.b(false);
@@ -163,22 +202,49 @@ public class PhysicalFpslic extends PhysicalDevice {
 
         public void link() {
             // FIXME wow, this is a horrendous hack!
+
             if (getCell(col-1, row+1) != null)
-                new PhysicalPip(this+".xiNW", getCell(col-1, row+1).getNet("out"), new PhysicalNet[] { xin }, 5) {
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".xiNW", getCell(col-1, row+1).getNet("out"), new PhysicalNet[] { xin }, 5) {
                     public void set(boolean connected) { cell().xi(connected ? NW : NONE); }
                 };
             if (getCell(col-1, row-1) != null)
-                new PhysicalPip(this+".xiSW", getCell(col-1, row-1).getNet("out"), new PhysicalNet[] { xin }, 5) {
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".xiSW", getCell(col-1, row-1).getNet("out"), new PhysicalNet[] { xin }, 5) {
                     public void set(boolean connected) { cell().xi(connected ? SW : NONE); }
                 };
             if (getCell(col+1, row+1) != null)
-                new PhysicalPip(this+".xiNE", getCell(col+1, row+1).getNet("out"), new PhysicalNet[] { xin }, 5) {
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".xiNE", getCell(col+1, row+1).getNet("out"), new PhysicalNet[] { xin }, 5) {
                     public void set(boolean connected) { cell().xi(connected ? NE : NONE); }
                 };
             if (getCell(col+1, row-1) != null)
-                new PhysicalPip(this+".xiSE", getCell(col+1, row-1).getNet("out"), new PhysicalNet[] { xin }, 5) {
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".xiSE", getCell(col+1, row-1).getNet("out"), new PhysicalNet[] { xin }, 5) {
                     public void set(boolean connected) { cell().xi(connected ? SE : NONE); }
                 };
+
+            if (getCell(col-1, row) != null)
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".yiW", getCell(col-1, row).getNet("out"), new PhysicalNet[] { yin }, 5) {
+                    public void set(boolean connected) { cell().yi(connected ? WEST : NONE); }
+                };
+            if (getCell(col, row-1) != null)
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".yiN", getCell(col, row-1).getNet("out"), new PhysicalNet[] { yin }, 5) {
+                    public void set(boolean connected) { cell().yi(connected ? NORTH : NONE); }
+                };
+            if (getCell(col+1, row) != null)
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".yiE", getCell(col+1, row).getNet("out"), new PhysicalNet[] { yin }, 5) {
+                    public void set(boolean connected) { cell().yi(connected ? EAST : NONE); }
+                };
+            if (getCell(col, row+1) != null)
+                new PhysicalFpslicPip(col, row, 0, 0,
+                                      this+".yiS", getCell(col, row+1).getNet("out"), new PhysicalNet[] { yin }, 5) {
+                    public void set(boolean connected) { cell().yi(connected ? SOUTH : NONE); }
+                };
+
         }
 
         private PhysicalFpslicCell(int col, int row) {
@@ -194,19 +260,26 @@ public class PhysicalFpslic extends PhysicalDevice {
 
                 final int i = j;
                 local[i] = new PhysicalNet(this.toString()+".L"+i);
-                new PhysicalPip(this+".h"+i,  null,      new PhysicalNet[] { local[i], getSectorWire(col, row, i, true) }) {
+                new PhysicalFpslicPip(col, row, -1 * (4-j) * PLANESEP, -1 * j * PLANESEP,
+                                      this+".h"+i,  null,      new PhysicalNet[] {
+                        local[i], getSectorWire(col, row, i, true) }) {
                     public void set(boolean connected) { cell().h(i, connected); }
                 };
-                new PhysicalPip(this+".v"+i,  null,      new PhysicalNet[] { local[i], getSectorWire(col, row, i, false) }) {
+                new PhysicalFpslicPip(col, row, -1 * (4-j) * PLANESEP, -1 * j * PLANESEP,
+                                      this+".v"+i,  null,      new PhysicalNet[] {
+                        local[i], getSectorWire(col, row, i, false) }) {
                     public void set(boolean connected) { cell().v(i, connected); }
                 };
-                new PhysicalPip(this+".xi"+i, local[i],  new PhysicalNet[] { xin }) {
+                new PhysicalFpslicPip(col, row, -1 * (4-j) * PLANESEP + 15, -1 * j * PLANESEP + 15,
+                                      this+".xi"+i, local[i],  new PhysicalNet[] { xin }) {
                     public void set(boolean connected) { cell().xi(connected ? i : NONE); }
                 };
-                new PhysicalPip(this+".yi"+i, local[i],  new PhysicalNet[] { yin }) {
+                new PhysicalFpslicPip(col, row, -1 * (4-j) * PLANESEP + 15, -1 * j * PLANESEP + 15,
+                                      this+".yi"+i, local[i],  new PhysicalNet[] { yin }) {
                     public void set(boolean connected) { cell().yi(connected ? i : NONE); }
                 };
-                new PhysicalPip(this+".o"+i,  outputNet, new PhysicalNet[] { local[i] }) {
+                new PhysicalFpslicPip(col, row, -1 * (4-j) * PLANESEP + 15, -1 * j * PLANESEP + 15,
+                                      this+".o"+i,  outputNet, new PhysicalNet[] { local[i] }) {
                     public void set(boolean connected) { cell().out(i, connected); }
                 };
             }
@@ -214,4 +287,41 @@ public class PhysicalFpslic extends PhysicalDevice {
         public  String toString() { return "cell@("+col+","+row+")"; }
     }
 
+    public abstract class PhysicalFpslicPip extends PhysicalPip {
+        public PhysicalFpslicPip(int x, int y, int ox, int oy, String name, PhysicalNet driver, PhysicalNet[] driven, int q) {
+            this(x, y, ox, oy, name, driver, driven);
+        }
+        public PhysicalFpslicPip(int x, int y, int ox, int oy, String name, PhysicalNet driver, PhysicalNet[] driven) {
+            super(name, driver, driven);
+            this.x = x;
+            this.y = y;
+            this.ox = ox;
+            this.oy = oy;
+        }
+        private int ox;
+        private int oy;
+        private int x;
+        private int y;
+        public boolean prohibited() {
+            return Math.abs(x-badx) <= badr && Math.abs(y-bady) <= badr;
+        }
+        public int getX() {
+            return x * CELLSEP + ox;
+        }
+        public int getY() {
+            return ((height * CELLSEP) - (y * CELLSEP)) + oy;
+        }
+        public double        getCost(PhysicalNet in, PhysicalNet out) {
+            if (prohibited()) return 100 * ((2*badr)-(Math.abs(badx-x) + Math.abs(bady-y)));
+            return defaultCost;
+        }
+        public double        getDelay(PhysicalNet in, PhysicalNet out) {
+            if (prohibited()) return 10000 * defaultDelay;
+            return defaultDelay;
+        }
+    }
+
+    static int badx = 5;
+    static int bady = 5;
+    static int badr = 3;
 }
\ No newline at end of file
diff --git a/src/edu/berkeley/slipway/mpar/Placement.java b/src/edu/berkeley/slipway/mpar/Placement.java
new file mode 100644 (file)
index 0000000..e918d7a
--- /dev/null
@@ -0,0 +1,72 @@
+package edu.berkeley.slipway.mpar;
+import com.atmel.fpslic.*;
+import java.awt.*;
+import byucc.edif.tools.merge.*;
+import byucc.edif.*;
+import java.io.*;
+import java.util.*;
+import edu.berkeley.slipway.*;
+import edu.berkeley.abits.*;
+import com.atmel.fpslic.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+import static edu.berkeley.slipway.mpar.PhysicalDevice.*;
+import static edu.berkeley.slipway.mpar.NetList.*;
+
+public class Placement {
+
+    public final NetList netlist;
+    public final PhysicalDevice pd;
+
+    public HashMap<PhysicalDevice.PhysicalCell, NetList.Node> cellToNode =
+        new HashMap<PhysicalDevice.PhysicalCell, NetList.Node>();
+    public HashMap<NetList.Node, PhysicalDevice.PhysicalCell> nodeToCell =
+        new HashMap<NetList.Node, PhysicalDevice.PhysicalCell>();
+
+    public Placement(NetList netlist, PhysicalDevice pd) {
+        this.netlist = netlist;
+        this.pd = pd;
+    }
+
+    public void unplace(PhysicalDevice.PhysicalCell pc) {
+        NetList.Node n = cellToNode.get(pc);
+        if (n != null) unplace(n);
+    }
+    public void unplace(NetList.Node n) {
+        PhysicalDevice.PhysicalCell pc = nodeToCell.get(n);
+        cellToNode.remove(pc);
+        nodeToCell.remove(n);
+    }
+    public void place(NetList.Node n, PhysicalDevice.PhysicalCell pc) {
+        if (n==null) return;
+        if (pc==null) return;
+        unplace(n);
+        unplace(pc);
+        cellToNode.put(pc, n);
+        nodeToCell.put(n, pc);
+    }
+
+    public void setPlacement() {
+        for(PhysicalDevice.PhysicalCell pc : cellToNode.keySet()) {
+            NetList.Node node = cellToNode.get(pc);
+            pc.place(node);
+        }
+    }
+
+    public boolean isPlaced(NetList.Node n) { return nodeToCell.get(n) != null; }
+    public boolean isPlaced(PhysicalDevice.PhysicalCell pc) { return cellToNode.get(pc) != null; }
+
+    public PhysicalDevice.PhysicalCell nodeToCell(NetList.Node n) { return nodeToCell.get(n); }
+    public NetList.Node cellToNode(PhysicalDevice.PhysicalCell pc) { return cellToNode.get(pc); }
+
+    public void random(Random rand) {
+        for(NetList.Node n : netlist.nodes) {
+            while(true) {
+                PhysicalDevice.PhysicalCell pc = pd.randomCell(rand);
+                if (isPlaced(pc)) continue;
+                place(n, pc);
+                break;
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/src/edu/berkeley/slipway/mpar/Routing.java b/src/edu/berkeley/slipway/mpar/Routing.java
new file mode 100644 (file)
index 0000000..f86f912
--- /dev/null
@@ -0,0 +1,292 @@
+package edu.berkeley.slipway.mpar;
+import com.atmel.fpslic.*;
+import java.awt.*;
+import byucc.edif.tools.merge.*;
+import byucc.edif.*;
+import java.io.*;
+import java.util.*;
+import edu.berkeley.slipway.*;
+import edu.berkeley.abits.*;
+import com.atmel.fpslic.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+import static edu.berkeley.slipway.mpar.PhysicalDevice.*;
+import static edu.berkeley.slipway.mpar.NetList.*;
+
+
+// FIXME: make sure everything is O(design), not O(device)
+public class Routing {
+
+    public final Placement placement;
+    public final NetList netlist;
+    public final PhysicalDevice pd;
+
+    private HashSet<Route> removed = new HashSet<Route>();
+    private HashSet<Route> added   = new HashSet<Route>();
+    public void checkpoint() {
+        removed.clear();
+        added.clear();
+    }
+    public void rollback() {
+        for (Route r : added) r.remove(false);
+        for (Route r : removed) r.add();
+    }
+
+    public Routing(Placement p) {
+        this.placement = p;
+        this.netlist = p.netlist;
+        this.pd = p.pd;
+        congestion = new double[pd.getNumPhysicalNets()];
+        load       = new int[pd.getNumPhysicalNets()];
+    }
+
+    private double[] congestion;
+    private int[]    load;
+    public HashMap<NetList.LogicalNet, Route> routes =
+        new HashMap<NetList.LogicalNet, Route>();
+
+    private class Route {
+        private NetList.LogicalNet logicalNet;
+        private HashSet<PhysicalDevice.PhysicalNet> nets;
+        private HashSet<PhysicalDevice.PhysicalPip> pips;
+        double timingpenalty;
+        public Route(NetList.LogicalNet logicalNet,
+                     HashSet<PhysicalDevice.PhysicalNet> nets,
+                     HashSet<PhysicalDevice.PhysicalPip> pips
+                     ) {
+            this.logicalNet = logicalNet;
+            this.nets = nets;
+            this.pips = pips;
+        }
+        public void add() {
+            for(PhysicalDevice.PhysicalNet net : nets)
+                load[net.idx]++;
+            added.add(this);
+            routes.put(logicalNet, this);
+        }
+        public void remove() { remove(true); }
+        public void remove(boolean note) {
+            for(PhysicalDevice.PhysicalNet net : nets)
+                load[net.idx]--;
+            if (note) removed.add(this);
+            routes.remove(logicalNet);
+        }
+    }
+
+    public void setPips(boolean on) {
+        for (Route r : routes.values())
+            for (PhysicalDevice.PhysicalPip pip : r.pips)
+                pip.set(on);
+    }
+
+    public int getLoad(PhysicalDevice.PhysicalNet pn) { return load[pn.idx]; }
+    public double getCongestion(PhysicalDevice.PhysicalNet pn) { return congestion[pn.idx]; }
+
+    public void routeAll() throws RoutingFailedException {
+        for(NetList.LogicalNet net : netlist.nets)
+            route(net);
+    }
+    public void reRouteAll() throws RoutingFailedException {
+        for(NetList.LogicalNet net : netlist.nets) {
+            unroute(net);
+            route(net);
+        }
+    }
+    public void unRouteAll() {
+        for(NetList.LogicalNet signal : netlist.getLogicalNets())
+            unroute(signal);
+    }
+
+
+    public void unroute(NetList.Node node) {
+        if (node==null) return;
+        for(NetList.Node.Port p : node)
+            unroute(p.net);
+    }
+    /*
+    public void unroute(PhysicalDevice.PhysicalNet net) {
+        while(netToSignals.size(net) > 0)
+            unroute(netToSignals.getAll(net).iterator().next());
+    }
+    */
+    public void unroute(NetList.LogicalNet signal) {
+        if (signal==null) return;
+        Route r = routes.get(signal);
+        if (r != null) r.remove();
+    }
+
+    public void unrouteOverloaded() {
+        /*
+          FIXME
+        for(PhysicalDevice.PhysicalNet pn : pd)
+            if (getLoad(pn) > 1)
+                unroute(pn);
+        */
+    }
+
+    public void updateCongestion(double alphaParameter, double betaParameter) {
+        for(PhysicalDevice.PhysicalNet net : pd) {
+            double c = getCongestion(net);
+            c = c * alphaParameter;
+            if (getLoad(net) > 1) c += betaParameter;
+            congestion[net.idx] = c;
+        }
+    }
+
+    public static class RoutingFailedException extends Exception { }
+
+    public static int iteration = 1;
+
+    private HashSet<PhysicalDevice.PhysicalNet> remainingDests = new HashSet<PhysicalDevice.PhysicalNet>();
+    private PriorityQueue<PhysicalDevice.PhysicalNet> pq = new PriorityQueue<PhysicalDevice.PhysicalNet>();
+    public void route(NetList.LogicalNet logicalNet) throws RoutingFailedException {
+        double maxDelay = 10;
+        boolean tryHard = true;
+        double ts = 0;
+        if (logicalNet.driver == null) return;
+        if (logicalNet.getSize() <= 1) return;
+        if (isRouted(logicalNet)) return;
+
+        int remaining = 0;
+        for(NetList.Node.Port p : logicalNet.ports)
+            if (p != logicalNet.driver) {
+                PhysicalDevice.PhysicalNet dest;
+                switch(p.index) {
+                    case 0: dest = placement.nodeToCell(p.getNode()).getNet("xi"); break;
+                    case 1: dest = placement.nodeToCell(p.getNode()).getNet("yi"); break;
+                    default: throw new Error();
+                }
+                dest.remaining = true;
+                remaining++;
+            }
+        iteration++;
+
+        PhysicalDevice.PhysicalNet source = placement.nodeToCell(logicalNet.driver.getNode()).getNet("out");
+        pq.clear();
+        source.distance = -1 * maxDelay;
+        source.depth = 0;
+        source.iteration = iteration;
+        pq.add(source);
+
+        HashSet<PhysicalDevice.PhysicalNet> nets = new HashSet<PhysicalDevice.PhysicalNet>();
+        HashSet<PhysicalDevice.PhysicalPip> pips = new HashSet<PhysicalDevice.PhysicalPip>();
+        OUTER: while(true) {
+            PhysicalDevice.PhysicalNet pn = pq.poll();
+            if (pn==null) throw new RoutingFailedException();
+            double frontier = pn.distance;
+            for(PhysicalDevice.PhysicalPip pip : pn) {
+                for(PhysicalDevice.PhysicalNet net : pip.getDrivenNets()) {
+                    if (net.iteration != iteration) {
+                        net.iteration = iteration;
+                        net.distance = Double.MAX_VALUE;
+                    }
+                    double newfrontier = frontier + pip.getCost(pn, net);
+                    newfrontier += getCongestion(net);
+                    if (getLoad(net) > 0) newfrontier += 1000;
+
+                    // penalty for using any net already routed in this iteration (makes routing order-sensitive)
+                    //if (net.load >= 1) newfrontier = newfrontier + 20;
+
+                    if (net.distance <= newfrontier) continue;
+                    net.distance = newfrontier;
+                    pq.add(net);
+                    net.backpointer = pn;
+                    net.depth = pn.depth+1;
+
+                    if (!net.remaining) continue;
+                    remaining--;
+                    net.remaining = false;
+                    // Vaughn Betz style multiterminal routing: once we reach one sink, make every node on the path
+                    // "distance zero" from the source.
+                    nets.add(source);
+                    if (newfrontier > 0) ts += newfrontier;
+                    for(PhysicalDevice.PhysicalNet p = net; p != source; p = p.backpointer) {
+                        PhysicalDevice.PhysicalPip pipx = p.getPipFrom(p.backpointer);  // FIXME: this call is actually slow
+                        pips.add(pipx);
+                        if (pipx.driver != null) nets.add(pipx.driver);
+                        for(PhysicalDevice.PhysicalNet n : pipx.driven) nets.add(n);
+                        p.distance = source.distance;
+                        pq.add(p);
+                        nets.add(p);
+                    }
+                    if (remaining==0) break OUTER;
+                }
+            }
+        }
+        Route r = new Route(logicalNet, nets, pips);
+        r.add();
+        r.timingpenalty = ts;
+    }
+
+
+    public boolean isRouted(NetList.LogicalNet n) { return routes.get(n) != null; }
+    //public boolean isRouted(PhysicalDevice.PhysicalNet pn) { return netToSignal.get(pn) != null; }
+    //public PhysicalDevice.PhysicalNet signalToNet(NetList.LogicalNet n) { return signalToNets.get(n); }
+    //public NetList.LogicalNet netToSignal(PhysicalDevice.PhysicalNet pn) { return netToSignals.get(pn); }
+
+    public double measureCongestion() {
+        double congestion = 0;
+        for(PhysicalDevice.PhysicalNet pn : pd)
+            if (getLoad(pn) > 1)
+                congestion += getLoad(pn)-1;
+        for(NetList.LogicalNet ln : netlist.nets)
+            if (!isRouted(ln))
+                congestion = Double.MAX_VALUE;
+        return congestion;
+    }
+
+    public double measureWireCost() {
+        double cong = 0;
+        for(PhysicalDevice.PhysicalNet pn : pd)
+            cong += getLoad(pn);
+        return cong;
+    }
+
+    public double measureTimingpenalty() {
+        double ret = 0;
+        for(Route r : routes.values())
+            ret += r.timingpenalty;
+        return ret;
+    }
+
+    public int measureOverloaded() {
+        int ret = 0;
+        for(PhysicalDevice.PhysicalNet pn : pd)
+            if (getLoad(pn) > 1)
+                ret++;
+        return ret;
+    }
+
+    public double measureWireUtilization() {
+        int numwires = 0;
+        int used = 0;
+        for(PhysicalDevice.PhysicalNet pn : pd) {
+            numwires++;
+            used += getLoad(pn);
+        }
+        return ((double)used)/((double)numwires);
+    }
+
+    public void draw(Graphics2D g) {
+        for(NetList.LogicalNet signal : netlist.nets)
+            draw(g, signal);
+    }
+    public void draw(Graphics2D g, NetList.LogicalNet signal) {
+        g.setColor(/*getLoad(pip1.driver) >= 2 ? Color.red :*/ Color.blue);
+        for(Route r : routes.values()) {
+            for(PhysicalDevice.PhysicalNet net : r.nets) {
+                for(PhysicalDevice.PhysicalPip pip1 : net) {
+                    if (!r.pips.contains(pip1)) continue;
+                    for(PhysicalDevice.PhysicalPip pip2 : net) {
+                        if (!r.pips.contains(pip2)) continue;
+
+                        g.drawLine(pip1.getX(),
+                                   pip1.getY(),
+                                   pip2.getX(),
+                                   pip2.getY());
+
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/edu/berkeley/slipway/mpar/Visualization.java b/src/edu/berkeley/slipway/mpar/Visualization.java
new file mode 100644 (file)
index 0000000..a6e8a64
--- /dev/null
@@ -0,0 +1,85 @@
+package edu.berkeley.slipway.mpar;
+import com.atmel.fpslic.*;
+import java.awt.*;
+import java.awt.event.*;
+import byucc.edif.tools.merge.*;
+import byucc.edif.*;
+import java.io.*;
+import java.util.*;
+import edu.berkeley.slipway.*;
+import edu.berkeley.abits.*;
+import com.atmel.fpslic.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+import static edu.berkeley.slipway.mpar.PhysicalFpslic.*;
+
+public class Visualization extends Frame implements MouseMotionListener, MouseListener {
+    public void mouseEntered(MouseEvent e) { }
+    public void mouseExited(MouseEvent e) { }
+    public void mousePressed(MouseEvent e){ }
+    public void mouseReleased(MouseEvent e)  { }
+    public void mouseDragged(MouseEvent e) { }
+    public void mouseClicked(MouseEvent e) {
+        MPARDemo.temperature += 0.05;
+    }
+    public void mouseMoved(MouseEvent e) {
+        PhysicalFpslic.badx = (e.getX() / CELLSEP)-1;
+        PhysicalFpslic.bady = (getHeight()-e.getY()) / CELLSEP;
+    }
+
+    public static final Color MOVED = new Color(0x88, 0x88, 0x88);
+    public static final Color PLAIN = new Color(0xff, 0x88, 0x88);
+    public static final Color EMPTY = new Color(0x88, 0xff, 0x88);
+
+    private final PhysicalFpslic pd;
+
+    public Visualization(PhysicalFpslic pd) {
+        this.pd = pd;
+        setSize(CELLSEP*(pd.width+2), CELLSEP*(pd.height+2));
+        show();
+        setSize(CELLSEP*(pd.width+2), CELLSEP*(pd.height+2));
+        addMouseListener(this);
+        addMouseMotionListener(this);
+    }
+
+    public void draw(Placement placement, Routing routing, boolean drawRouting) {
+        Graphics2D g = (Graphics2D)getGraphics();
+        g.translate(CELLSEP,CELLSEP);
+        g.setColor(Color.white);
+        g.fillRect(-CELLSEP, -CELLSEP, getWidth(), getHeight());
+        g.setColor(Color.black);
+        g.drawString("temperature = " + MPARDemo.temperature,    10, 0);
+        g.drawString("congestion  = " + MPARDemo.congestion,     10, 15);
+        g.drawString("slack = " + (-1 * MPARDemo.timingpenalty), 10, 30);
+        for(int x=0; x<pd.width; x++)
+            for(int y=0; y<pd.height; y++) {
+                double d = Math.sqrt( (PhysicalFpslic.badx-x)*
+                                      (PhysicalFpslic.badx-x)+
+                                      (PhysicalFpslic.bady-y)*
+                                      (PhysicalFpslic.bady-y) );
+                d = (PhysicalFpslic.badr - d);
+                if (d<0) d = 0;
+                d /= PhysicalFpslic.badr;
+                int a = 255 - ((int)(255*d));
+                g.setColor(new Color(a, a, a));
+                g.fillRect((                         x*CELLSEP - (PLANESEP*3)),
+                           ((pd.height * CELLSEP) - (y*CELLSEP + (PLANESEP*3))),
+                           CELLSEP,
+                           CELLSEP);
+            }
+        if (drawRouting) {
+            routing.draw(g);
+        }
+        for(int x=0; x<pd.width; x++)
+            for(int y=0; y<pd.height; y++) {
+                if (placement.cellToNode(pd.getCell(x,y)) != null)
+                    g.setColor(PLAIN);
+                else
+                    g.setColor(EMPTY);
+                g.fillRect((                       x*CELLSEP)+2,
+                           ((pd.height * CELLSEP) - (y*CELLSEP))+2,
+                           CELLSEP-5*PLANESEP-2,
+                           CELLSEP-5*PLANESEP-2);
+            }
+    }
+
+}
\ No newline at end of file
diff --git a/src/edu/berkeley/slipway/util/ExperimentUtils.java b/src/edu/berkeley/slipway/util/ExperimentUtils.java
new file mode 100644 (file)
index 0000000..15a86f5
--- /dev/null
@@ -0,0 +1,83 @@
+package edu.berkeley.slipway.util;
+
+import java.io.*;
+import java.util.*;
+import java.awt.*;
+import com.atmel.fpslic.*;
+import edu.berkeley.slipway.*;
+import edu.berkeley.slipway.gui.*;
+import static com.atmel.fpslic.FpslicConstants.*;
+
+/** useful test structures */
+public class ExperimentUtils {
+
+    /** 
+     *  Creates a 2x2 cell frequency divider with top left corner at
+     *  c, taking input from c.north() and providing output on the
+     *  orthogonal axis at c.south().  Returns c.south().south() for
+     *  easy daisy-chaining.
+     */
+    public static FpslicDevice.Cell divider(FpslicDevice.Cell c) {
+        FpslicDevice.Cell detect1 = c;
+        FpslicDevice.Cell detect2 = c.east();
+
+        detect1.yi(NORTH);
+        detect1.ylut(LUT_SELF);
+        detect1.xlut(LUT_OTHER & (~LUT_Z));
+        detect1.c(YLUT);
+        detect1.t(TMUX_FB);
+        detect1.f(false);
+        detect1.b(false);
+
+        detect2.xi(NW);
+        detect2.ylut(LUT_OTHER);
+        detect2.xlut((~LUT_SELF) & LUT_Z);
+        detect2.c(YLUT);
+        detect2.t(TMUX_FB);
+        detect2.f(false);
+        detect2.b(false);
+
+        detect1.south().yi(EAST);
+        detect1.south().xi(NE);
+        detect1.south().c(YLUT);
+        detect1.south().t(TMUX_FB);
+        detect1.south().f(false);
+        detect1.south().b(false);
+        detect1.south().ylut( (LUT_OTHER    & (~LUT_SELF)) |
+                              ((~LUT_OTHER) &   LUT_Z)
+                              );
+        detect1.south().xlut( (LUT_SELF    & (~LUT_OTHER)) |
+                              ((~LUT_SELF) &   LUT_Z)
+                              );
+
+        detect2.south().yi(WEST);
+        detect2.south().xi(NW);
+        detect2.south().c(YLUT);
+        detect2.south().t(TMUX_FB);
+        detect2.south().f(false);
+        detect2.south().b(false);
+        detect2.south().ylut( (LUT_OTHER    & (LUT_SELF)) |
+                              ((~LUT_OTHER) &   LUT_Z)
+                              );
+        detect2.south().xlut( (LUT_SELF    & (~LUT_OTHER)) |
+                              ((~LUT_SELF) &   LUT_Z)
+                              );
+
+        if (c.south().south()==null) return null;
+        if (c.south().south().south()==null) return null;
+        return c.south().south();
+    }
+
+    /** set up the scan cell */
+    public static void setupScanCell(FpslicDevice fpslic) {
+        fpslic.cell(23,15).h(3, true);
+        fpslic.cell(23,15).yi(L3);
+        fpslic.cell(23,15).ylut(0xAA);
+        fpslic.iob_right(15, true).enableOutput(WEST);
+
+        fpslic.cell(23,0).ylut(0x00);
+        fpslic.iob_right(0, true).enableOutput(WEST);
+        fpslic.flush();
+    }
+
+}
\ No newline at end of file