major refactoring of edu.berkeley.fleet.dataflow
authormegacz <adam@megacz.com>
Mon, 6 Apr 2009 18:41:48 +0000 (11:41 -0700)
committermegacz <adam@megacz.com>
Mon, 6 Apr 2009 18:41:48 +0000 (11:41 -0700)
19 files changed:
src/edu/berkeley/fleet/dataflow/AluNode.java
src/edu/berkeley/fleet/dataflow/DataFlowGraph.java
src/edu/berkeley/fleet/dataflow/DebugNode.java
src/edu/berkeley/fleet/dataflow/DiscardNode.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/DoneNode.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/DownCounterNode.java
src/edu/berkeley/fleet/dataflow/DropNode.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/FifoNode.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/ForeverNode.java
src/edu/berkeley/fleet/dataflow/Lut3Node.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/MemoryNode.java
src/edu/berkeley/fleet/dataflow/MergeSort.java
src/edu/berkeley/fleet/dataflow/Node.java
src/edu/berkeley/fleet/dataflow/OnceNode.java
src/edu/berkeley/fleet/dataflow/ParameterNode.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/PunctuatorNode.java
src/edu/berkeley/fleet/dataflow/RandomNode.java [new file with mode: 0644]
src/edu/berkeley/fleet/dataflow/RepeatNode.java
src/edu/berkeley/fleet/dataflow/UnPunctuatorNode.java

index b5fa765..47aeae0 100644 (file)
@@ -12,4 +12,8 @@ public class AluNode extends Node {
     public final OutPort out  = new DockOutPort("out", ship.getDock("out"));
 
     public AluNode(DataFlowGraph dfg) { super(dfg); }
+    public AluNode(DataFlowGraph dfg, String opcode) {
+        super(dfg);
+        inOp.connect(new ForeverNode(dfg, ((Node.DockInPort)inOp).getConstant(opcode)).out);
+    }
 }
index 9ab17f6..7916538 100644 (file)
@@ -5,29 +5,35 @@ import edu.berkeley.fleet.api.*;
 import java.util.*;
 import java.net.*;
 
-public class DataFlowGraph {
+/**
+ *  A dataflow graph.
+ */
+public class DataFlowGraph implements Iterable<Node> {
 
     public final Fleet    fleet;
     public final ShipPool pool;
-    private HashSet<Node> nodes = new HashSet<Node>();
 
-    public DataFlowGraph(Fleet fleet) { this(fleet, new ShipPool(fleet)); }
+    /**
+     *  Use LinkedHashSet to get a predictable/repeatable iteration
+     *  order, which leads to predictable/repeatable code
+     */
+    private LinkedHashSet<Node> nodes = new LinkedHashSet<Node>();
+
     public DataFlowGraph(Fleet fleet, ShipPool pool) {
         this.fleet = fleet;
         this.pool  = pool;
     }
 
+    public Iterator<Node> iterator() { return nodes.iterator(); }
     public void addNode(Node node) { this.nodes.add(node); }
 
-    public void build(Context ctx) {
-        for(Node mod : nodes)
-            mod.build(ctx);
-    }
-    public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
-        int ret = 0;
-        for(Node mod : nodes)
-            ret += mod.reset(ctx, phase, ackDestination, sendTorpedoesTo);
-        return ret;
+    public CodeBag build(CodeBag cb) {
+        boolean oldAutoflush = cb.getAutoflush();
+        cb.setAutoflush(true);
+        for(Node mod : nodes) mod.build(cb);
+        // this breaks stuff, but it shouldn't!
+        //cb.setAutoflush(oldAutoflush);
+        return cb;
     }
 }
 
index 1c6e842..af734ea 100644 (file)
@@ -3,6 +3,7 @@ import java.util.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
 
+/** Items supplied to the "in" port will appear at the debug output of the Fleet */
 public class DebugNode extends Node {
     private final Ship ship = dfg.pool.allocateShip("Debug");
     public final InPort in = new DockInPort("in", ship.getDock("in"));
diff --git a/src/edu/berkeley/fleet/dataflow/DiscardNode.java b/src/edu/berkeley/fleet/dataflow/DiscardNode.java
new file mode 100644 (file)
index 0000000..f931e27
--- /dev/null
@@ -0,0 +1,37 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
+
+public class DiscardNode extends Node {
+
+    private final Ship    ship  = dfg.pool.allocateShip("Counter");
+    private final InPort  op    = new DockInPort("op",    ship.getDock("inOp"), "PASS_C2_V1");
+    public  final InPort  in    = new DockInPort("val",   ship.getDock("in1"));
+    public  final InPort  count = new DockInPort("count", ship.getDock("in2"));
+
+    public  final OutPort out   = new DockOutPort("out", ship.getDock("out")) {
+            protected void build(CodeBag ctx, LoopFactory lf) {
+
+                lf = lf.makeNext(0);
+
+                lf.abortLoopIfTorpedoPresent();
+                lf.collectWord();
+                lf.setFlags(FlagFunction.ZERO.add(Predicate.FlagC), FlagFunction.ZERO);
+
+                lf.setPredicate(Predicate.FlagA);
+                lf.abortLoopIfTorpedoPresent();
+                peer.recvToken(lf);
+                peer.sendWord(lf);
+                lf.setPredicate(null);
+
+            }
+        };
+
+    public DiscardNode(DataFlowGraph dfg) {
+        super(dfg);
+    }
+
+}
+
diff --git a/src/edu/berkeley/fleet/dataflow/DoneNode.java b/src/edu/berkeley/fleet/dataflow/DoneNode.java
new file mode 100644 (file)
index 0000000..7c966cf
--- /dev/null
@@ -0,0 +1,213 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
+
+/**
+ *  This class contains all of the shutdown and cleanup logic.
+ */
+public class DoneNode extends Node {
+
+    private final Ship    counter = dfg.pool.allocateShip("Counter");
+    private final Program program;
+    private       CodeBag shutdownCodeBag = null;
+
+    public  final InPort  in       = new InPort("in") {
+            private Dock dock = counter.getDock("out");
+            public void recvToken(LoopFactory lf) { }
+            public void sendWord(LoopFactory lf) { lf.sendToken(dock); }
+            public int getInflight() { return 1; }
+            public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
+            public void build(CodeBag ctx) { build(ctx, ctx.loopFactory(dock, 1)); }
+            protected void build(CodeBag ctx, LoopFactory lf) {
+                lf.recvToken();
+                lf.literal(getShutdownCodeBag());
+                lf.sendWord(program.getCBDDestination());
+            }
+        };
+
+    public DoneNode(DataFlowGraph dfg, Program program) {
+        super(dfg);
+        this.program = program;
+    }
+
+    public Destination getDestinationToSendNextCodeBagDescriptorTo() {
+        return counter.getDock("in1").getDataDestination();
+    }
+
+    private static final int PHASES = 4;
+
+    private CodeBag getShutdownCodeBag() {
+        if (shutdownCodeBag!=null) return shutdownCodeBag;
+
+        CodeBag[] cb = new CodeBag[PHASES];
+        for(int phase=0; phase<PHASES; phase++)
+            cb[phase] = new CodeBag(dfg.fleet, program);
+
+        for(int phase=0; phase<PHASES; phase++) {
+            // ctx_counter sets up the counter ship which will tally
+            // the acknowledgement tokens coming back from the
+            // torpedoed docks.
+            CodeBag ctx_counter = cb[phase];
+
+            // ctx_reset is the context holding the reset code (not including torpedoes) for this phase
+            CodeBag ctx_reset = new CodeBag(dfg.fleet, program);
+
+            int expected_tokens = 0;
+            for(Node node : dfg)
+                expected_tokens += node.reset(ctx_reset, phase, counter.getDock("in2").getDataDestination());
+            if (expected_tokens==0) throw new RuntimeException("should not happen");
+
+            // The loops below use a count of zero and an
+            // unconditional abort instead of a count of 1.  This is
+            // to ensure that the loop will not start executing until
+            // all instructions are safely in the instruction ring.
+            // That in turn ensures that the "ready" tokens are not
+            // sent until the counter is truly prepared to consume a
+            // deluge of tokens.
+
+            LoopFactory lf;
+            lf = ctx_counter.loopFactory(counter.getDock("inOp"), 0);
+            lf.sendToken(counter.getDock("out")); // ready->
+            lf.literal("DROP_C1_V2");
+            lf.deliver();
+            lf.literal("PASS_C1_V1");
+            lf.deliver();
+            lf.abort();
+
+            lf = ctx_counter.loopFactory(counter.getDock("in1"), 0);
+            lf.sendToken(counter.getDock("out")); // ready->
+            lf.literal(expected_tokens);
+            lf.deliver();
+            lf.literal(1);
+            lf.deliver();
+            if (phase<PHASES-1) lf.literal(cb[phase+1]);
+            else lf.recvWord();
+            lf.deliver();
+            lf.abort();
+
+            lf = ctx_counter.loopFactory(counter.getDock("in2"), 1);
+            lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO);
+            lf = lf.makeNext(0);
+            lf.setPredicate(Predicate.FlagD);
+            lf.sendToken(counter.getDock("out"));
+            lf.setPredicate(null);
+            lf.setPredicate(Predicate.NotFlagA);
+            lf.sendToken(counter.getDock("out")); // ready->
+            lf.setPredicate(null);
+            lf.setFlags(FlagFunction.ONE, FlagFunction.ZERO);
+            lf.abortLoopIfTorpedoPresent();
+            lf.recvWord();
+            lf.deliver();
+
+            lf = ctx_counter.loopFactory(counter.getDock("out"), 1);
+            lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO);
+            lf.literal(ctx_reset);
+            lf = lf.makeNext(0);
+            lf.setPredicate(Predicate.NotFlagA);
+            lf.recvToken();
+            lf.recvToken();
+            lf.recvToken();
+            lf.sendWord(program.getCBDDestination());
+            lf.setFlags(FlagFunction.ONE, FlagFunction.ZERO);
+            lf.setPredicate(null);
+            lf.collectWord();
+            lf.sendTorpedo(counter.getDock("in2"));
+            lf.recvToken();
+            lf.sendWord(program.getCBDDestination());
+            lf.abort();
+
+            cb[phase].seal();
+            ctx_reset.seal();
+        }
+        return (shutdownCodeBag = cb[0]);
+    }
+
+    // Reset //////////////////////////////////////////////////////////////////////////////
+
+    static int doReset(CodeBag ctx,
+                       int phase,
+                       Dock dock,
+                       Port self,
+                       Port peer,
+                       Destination ackDestination,
+                       boolean peerUsed) {
+        int ret = 0;
+
+        switch(phase) {
+
+            // Phase 0: torpedo every output dock, put it in
+            // collecting mode.  Cannot combine with phase 1,
+            // because until output docks are in vacuum mode we
+            // cannot be sure that the tokens to the input docks
+            // will eventually succeed.  This may cause the
+            // instructions sent after the tokens to back up into
+            // the switch fabric.
+            case 0: {
+                if (!dock.isInputDock()) {
+                    ctx.sendTorpedo(dock);
+                    LoopFactory lf = ctx.loopFactory(dock, 1);
+                    lf.sendToken(ackDestination);
+                    lf = lf.makeNext(0);
+                    lf.abortLoopIfTorpedoPresent();
+                    lf.collectWord();
+                    ret++;
+                }
+                break;
+            }
+
+                // [wait for all output docks to confirm that they've been torpedoed]
+                // Phase 1: torpedo every input dock (causing them to flush), put it in loopback mode
+            case 1: {
+                if (dock.isInputDock()) {
+                    ctx.sendTorpedo(dock);
+                    LoopFactory lf = ctx.loopFactory(dock, 1);
+                    lf.sendToken(ackDestination);
+
+                    // FIXME: this won't work right for ports that
+                    // get "shared" by two senders (for example,
+                    // inAddrRead1/2)
+
+                    if (peerUsed && peer!=null) {
+                        lf = lf.makeNext(0);
+                        lf.abortLoopIfTorpedoPresent();
+                        ((OutPort)peer).recvWord(lf);
+                        ((OutPort)peer).sendToken(lf);
+                    }
+                    ret++;
+                }
+                break;
+            }
+
+                // [wait for all input docks to confirm that they've been torpedoed and have flushed]
+                // Phase 2: torpedo every output dock, have it absorb tokens
+            case 2: {
+                if (!dock.isInputDock()) {
+                    ctx.sendTorpedo(dock);
+                    LoopFactory lf = ctx.loopFactory(dock, 1);
+                    for(int i=0; i<((OutPort)self).getTokensToAbsorb(); i++)
+                        lf.recvToken();
+                    lf.sendToken(ackDestination);
+                    ret++;
+                }
+                break;
+            }
+
+                // [wait for all output docks to confirm that they've absorbed enough tokens]
+                // Phase 3: torpedo every input dock, await confirmation, and we're done
+            case 3: {
+                if (dock.isInputDock()) {
+                    if (peerUsed && peer!=null) {
+                        ctx.sendTorpedo(dock);
+                    }
+                    LoopFactory lf = ctx.loopFactory(dock, 1);
+                    lf.sendToken(ackDestination);
+                    ret++;
+                }
+                break;
+            }
+        }
+        return ret;
+    }
+}
index a17daef..61efbc9 100644 (file)
@@ -3,11 +3,14 @@ import java.util.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
 
+/**
+ *  Takes a starting value at "start" and a (positive) decrement
+ *  amount at "incr" and counts down; the first value emitted will be
+ *  (start-incr).
+ */
 public class DownCounterNode extends Node {
     private final Ship    ship  = dfg.pool.allocateShip("Counter");
-    private final InPort  inOp  = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] {
-             ship.getDock("inOp").getConstant("COUNT") });
-
+    private final InPort  inOp  = new DockInPort("inOp", ship.getDock("inOp"), "COUNT");
     public  final InPort  start = new DockInPort("start", ship.getDock("in1"));
     public  final InPort  incr  = new DockInPort("incr",  ship.getDock("in2"));
     public  final OutPort out   = new DockOutPort("out",  ship.getDock("out"));
diff --git a/src/edu/berkeley/fleet/dataflow/DropNode.java b/src/edu/berkeley/fleet/dataflow/DropNode.java
new file mode 100644 (file)
index 0000000..a1da02a
--- /dev/null
@@ -0,0 +1,24 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+
+/**
+ *  Discards all items provided; does not require any ships.
+ */
+public class DropNode extends Node {
+
+    public  final InPort  in    = new InPort("in") {
+            // FIXME: I'm still not sure if this screws up the protocol somewhere
+            public void recvToken(LoopFactory loopfactory_at_output_dock) { }
+            public void sendWord(LoopFactory loopfactory_at_output_dock) { }
+            public int  reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
+            public void build(CodeBag ctx) { }
+        };
+
+    public DropNode(DataFlowGraph dfg) {
+        super(dfg);
+    }
+
+}
+
diff --git a/src/edu/berkeley/fleet/dataflow/FifoNode.java b/src/edu/berkeley/fleet/dataflow/FifoNode.java
new file mode 100644 (file)
index 0000000..7c984f8
--- /dev/null
@@ -0,0 +1,14 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+
+/** A simple FIFO */
+public class FifoNode extends Node {
+    private final Ship    ship = dfg.pool.allocateShip("Fifo");
+
+    public final InPort  in = new DockInPort("in",  ship.getDock("in"));
+    public final OutPort out  = new DockOutPort("out", ship.getDock("out"));
+
+    public FifoNode(DataFlowGraph dfg) { super(dfg); }
+}
index e801b4f..556ff5f 100644 (file)
@@ -14,8 +14,8 @@ public class ForeverNode extends Node {
     public final OutPort out = new OutPort("out") {
             public void sendToken(LoopFactory lf) { }
             public void recvWord(LoopFactory lf) { }
-            public void build(Context ctx) { }
-            public int  reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) { return 0; }
+            public void build(CodeBag ctx) { }
+            public int  reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
             public void setPeer(InPort peer) {
                 this.peer = peer;
                 DockInPort pip = ((DockInPort)peer);
diff --git a/src/edu/berkeley/fleet/dataflow/Lut3Node.java b/src/edu/berkeley/fleet/dataflow/Lut3Node.java
new file mode 100644 (file)
index 0000000..c2eb366
--- /dev/null
@@ -0,0 +1,16 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+
+public class Lut3Node extends Node {
+    private final Ship    ship = dfg.pool.allocateShip("Lut3");
+
+    public final InPort  in1   = new DockInPort("in1",  ship.getDock("in1"));
+    public final InPort  in2   = new DockInPort("in2",  ship.getDock("in2"));
+    public final InPort  in3   = new DockInPort("in3",  ship.getDock("in3"));
+    public final InPort  inLut = new DockInPort("inLut", ship.getDock("inLut"));
+    public final OutPort out   = new DockOutPort("out", ship.getDock("out"));
+
+    public Lut3Node(DataFlowGraph dfg) { super(dfg); }
+}
index f0f3cad..a892672 100644 (file)
@@ -2,6 +2,7 @@ package edu.berkeley.fleet.dataflow;
 import java.util.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.fpga.*;
 import edu.berkeley.fleet.api.Instruction.*;
 import edu.berkeley.fleet.api.Instruction.Set;
 import edu.berkeley.fleet.api.Instruction.Set.*;
@@ -21,49 +22,74 @@ public class MemoryNode extends Node {
     public MemoryNode(DataFlowGraph dfg, Ship memoryShip) {
         super(dfg);
         this.ship = memoryShip;
+
+        // ugly hack
+        if (ship.getType().equals("Dvi")) {
+            new DockInPort("inPixelX", ship.getDock("inPixelX"), 0, new BitVector[] { null });
+            new DockInPort("inPixelY", ship.getDock("inPixelY"), 0, new BitVector[] { null });
+            new DockInPort("inPixelValue", ship.getDock("inPixelValue"), 0, new BitVector[] { null });
+        }
+
         this.inCBD        = ship.getType().equals("Memory") ? new DockInPort("inCBD", ship.getDock("inCBD")) : null;
-        this.inAddrWrite  = new DockInPort("inAddrWrite", ship.getDock("inAddrWrite"));
         this.inDataWrite  = new DockInPort("inDataWrite", ship.getDock("inDataWrite"));
+        this.inAddrWrite  = new InPort("inAddrWrite") {
+                public void recvToken(LoopFactory lf) { lf.recvToken(); }
+                public void sendWord(LoopFactory lf) { lf.sendWord(ship.getDock("inAddrWrite").getDataDestination()); }
+                public void build(CodeBag ctx) {
+                    LoopFactory lf = ctx.loopFactory(ship.getDock("inAddrWrite"), 0);
+                    lf.abortLoopIfTorpedoPresent();
+                    lf.recvWord();
+                    lf.deliver();
+                }
+                public int getTokensToAbsorb() { return outWrite.peer.getTokensToAbsorb(); }
+                public int reset(CodeBag ctx, int phase, Destination ackDestination) {
+                    return DoneNode.doReset(ctx, phase, ship.getDock("inAddrWrite"), this, null, ackDestination, false);
+                }
+            };
         this.inAddrRead1  = new InPort("inAddrRead1") {
                 public void recvToken(LoopFactory lf) { lf.recvToken(); }
                 public void sendWord(LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(0)); }
-                public void build(Context ctx) { }
+                public void build(CodeBag ctx) { }
                 public int getTokensToAbsorb() { return outRead1.peer.getTokensToAbsorb(); }
-                public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
-                    return doReset(ctx, phase, ship.getDock("inAddrRead"), null, ackDestination, sendTorpedoesTo, false);
+                public int reset(CodeBag ctx, int phase, Destination ackDestination) {
+                    return DoneNode.doReset(ctx, phase, ship.getDock("inAddrRead"), this, null, ackDestination, false);
                 }
             };
         this.inAddrRead2  = new InPort("inAddrRead2") {
                 public void recvToken(LoopFactory lf) { lf.recvToken(); }
                 public void sendWord(LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(1)); }
-                public void build(Context ctx) { }
+                public void build(CodeBag ctx) { }
                 public int getTokensToAbsorb() { return outRead2.peer.getTokensToAbsorb(); }
-                public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) { return 0; }
+                public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
             };
         this.outRead1 = new OutPort("outRead1") {
                 public void sendToken(LoopFactory lf) { inAddrRead1.peer.sendToken(lf); }
                 public void recvWord(LoopFactory lf) { lf.recvWord(); }
-                public void build(Context ctx) { }
-                public int  reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) { return 0; }
+                public int getNumInitialTokens() { return Math.max(1,Node.CAPACITY/2); }
+                public void build(CodeBag ctx) { }
+                public int  reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
             };
         this.outRead2 = new OutPort("outRead2") {
                 public void sendToken(LoopFactory lf) { inAddrRead2.peer.sendToken(lf); }
                 public void recvWord(LoopFactory lf) { lf.recvWord(); }
-                public void build(Context ctx) { }
-                public int  reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) { return 0; }
+                public int getNumInitialTokens() { return Math.max(1,Node.CAPACITY/2); }
+                public void build(CodeBag ctx) { }
+                public int  reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
             };
         this.outWrite = new DockOutPort("out", ship.getDock("out")) {
-                protected void build(Context ctx, LoopFactory lf) {
+                public void sendToken(LoopFactory lf) { inAddrWrite.peer.sendToken(lf); }
+                public void recvWord(LoopFactory lf) { lf.recvWord(); }
+                public int getTokensToAbsorb() { return 0; }
+                protected void build(CodeBag ctx, LoopFactory lf) {
                     lf = lf.makeNext(0);
                     lf.abortLoopIfTorpedoPresent();
                     lf.collectWord();
                         
-                    lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO.add(FlagC));
+                    lf.setFlags(FlagFunction.ONE, FlagFunction.ZERO.add(FlagC));
                     if (this.peer != null) {
                         lf.setPredicate(Predicate.FlagB);
                         lf.literal(77);
                         lf.abortLoopIfTorpedoPresent();
-                        this.peer.recvToken(lf);
                         this.peer.sendWord(lf);
                     }
                         
@@ -83,11 +109,11 @@ public class MemoryNode extends Node {
                 }
             };
     }
-    public void build(Context ctx) {
+    public void build(CodeBag ctx) {
         super.build(ctx);
         LoopFactory lf;
 
-        lf = new LoopFactory(ctx, ship.getDock("inAddrRead"), 0);
+        lf = ctx.loopFactory(ship.getDock("inAddrRead"), 0);
         lf.abortLoopIfTorpedoPresent();
         lf.recvWord();
         lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
@@ -98,4 +124,59 @@ public class MemoryNode extends Node {
         lf.setPredicate(null);
         lf.deliver();
     }
+
+
+
+    public static void clearMem(FleetProcess fp,
+                                Ship memory,
+                                ShipPool pool,
+                                long offset,
+                                long count) throws RuntimeException {
+
+        DataFlowGraph dfg = new DataFlowGraph(fp.getFleet(), pool);
+
+        MemoryNode mem = new MemoryNode(dfg, memory);
+        UnPunctuatorNode discard = new UnPunctuatorNode(dfg, true);
+        discard.count.connect(new OnceNode(dfg, (int)(count)).out);
+        DebugNode debug = new DebugNode(dfg);
+        DownCounterNode c1 = new DownCounterNode(dfg);
+        c1.start.connect(new OnceNode(dfg, count).out);
+        c1.incr.connect(new OnceNode(dfg, 1).out);
+        mem.inAddrWrite.connect(c1.out);
+        mem.inDataWrite.connect(new ForeverNode(dfg, 0).out);
+        mem.outWrite.connect(discard.val);
+        discard.out.connect(debug.in);
+
+        CodeBag ctx = new CodeBag(fp.getFleet());
+        dfg.build(ctx);
+        ctx.dispatch(fp, true);
+        System.out.println("waiting...");
+        fp.recvWord();
+        System.out.println("... done");
+
+        // FIXME: cleanup?
+    }
+
+    public static void main(String[] s) throws Exception {
+        Fleet fleet = new Fpga();
+        FleetProcess fp;
+        ShipPool pool = new ShipPool(fleet);
+        Ship mem1 = pool.allocateShip("Memory");
+        Ship mem2 = pool.allocateShip("Memory");
+        Ship mem3 = pool.allocateShip("Memory");
+
+        fp = fleet.run(new Instruction[0]);
+        clearMem(fp, mem1, new ShipPool(fleet), 0, 16 * 1024);
+        fp.terminate();
+
+        fp = fleet.run(new Instruction[0]);
+        clearMem(fp, mem2, new ShipPool(fleet), 0, 16 * 1024);
+        fp.terminate();
+
+        fp = fleet.run(new Instruction[0]);
+        clearMem(fp, mem3, new ShipPool(fleet), 0, 16 * 1024);
+        fp.terminate();
+    }
+
+
 }
index 9a8c70e..057db66 100644 (file)
 package edu.berkeley.fleet.dataflow;
 import java.util.*;
+import java.io.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
 import edu.berkeley.fleet.fpga.*;
-import java.util.*;
+//import org.ibex.graphics.*;
 
 public class MergeSort {
-    public static long[] mergeSort(FleetProcess fp, Fleet fleet, ShipPool pool,
-                                   long[] vals, int vals_length, int stride_length,
-                                   Ship memoryShip1, Ship memoryShip2) throws Exception {
-
-        if (vals != null) {
-            BitVector[] mem = new BitVector[vals_length];
-            for(int i=0; i<mem.length; i++) mem[i] = new BitVector(fleet.getWordWidth()).set(vals[i]);
-            MemoryUtils.writeMem(fp, memoryShip1, 0, mem);
-        }
 
-        //////////////////////////////////////////////////////////////////////////////
+    private final Fleet fleet;
+    private final Ship mem1;
+    private final Ship mem2;
+    private final int arity;
+    private final ShipPool pool;
+    private final Program program;
+    private final DataFlowGraph dfg;
+
+    private ParameterNode[] pn0;
+    private ParameterNode[] pn1;
+    private ParameterNode[] pn2;
+    private ParameterNode[] pn3;
+    private ParameterNode[] pn4;
+    private ParameterNode[] pn_base1;
+    private ParameterNode   pn_base2;
+    private ParameterNode   pn5;
+    private ParameterNode   pn6;
+    private ParameterNode   pn_end;
+
+    CodeBag cb2 = null;
+    Destination next_dest = null;
+
+    public MergeSort(Fleet fleet, Program program, ShipPool pool, int arity, Ship mem1, Ship mem2) {
+        this.fleet = fleet;
+        this.mem1 = mem1;
+        this.mem2 = mem2;
+        this.arity = arity;
+        this.pool = pool;
+        this.program = program;
+        this.dfg = new DataFlowGraph(fleet, pool);
+        /*
+        pool.allocateShip(mem1);
+        if (mem2 != mem1) pool.allocateShip(mem2);
+        */
+        next_dest = makeDfgCodeBag(dfg);
+        cb2 = dfg.build(new CodeBag(dfg.fleet, program));
+        cb2.seal();
+    }
 
-        DataFlowGraph proc = new DataFlowGraph(fleet, pool);
-        DebugNode dm = new DebugNode(proc);
+    public Destination makeDfgCodeBag(DataFlowGraph dfg) {
 
-        int end_of_data = vals_length;
-        int num_strides = end_of_data / (stride_length * 2);
+        MemoryNode mem_read  = new MemoryNode(dfg, mem1);
+        MemoryNode mem_write = (mem1==mem2) ? mem_read : new MemoryNode(dfg, mem2);
 
-        MemoryNode mm  = new MemoryNode(proc, memoryShip1);
-        SortedMergeNode sm = new SortedMergeNode(proc);
+        AluNode sm = new AluNode(dfg, "MAXMERGE");
 
-        // So far: we have four spare Counter ships; one can be used for resetting
-        for(int i=0; i<2; i++) {
+        pn0 = new ParameterNode[arity];
+        pn1 = new ParameterNode[arity];
+        pn2 = new ParameterNode[arity];
+        pn3 = new ParameterNode[arity];
+        pn4 = new ParameterNode[arity];
+        pn_base1 = new ParameterNode[arity];
+        pn_base2 = new ParameterNode(dfg, true);
+        pn_end = new ParameterNode(dfg);
+        pn5 = new ParameterNode(dfg);
+        pn6 = new ParameterNode(dfg, true);
 
-            DownCounterNode c0 = new DownCounterNode(proc);
-            DownCounterNode c1 = new DownCounterNode(proc);
+        // So far: we have four spare Counter ships; one can be used for resetting
+        for(int i=0; i<arity; i++) {
 
-            c0.start.connect(new ForeverNode(proc, stride_length).out);
-            c0.incr.connect(new ForeverNode(proc, 1).out);
+            DownCounterNode c0 = new DownCounterNode(dfg);
+            DownCounterNode c1 = new DownCounterNode(dfg);
 
-            c1.start.connect(new OnceNode(proc, end_of_data + i*stride_length).out);
-            c1.incr.connect(new OnceNode(proc, stride_length*2).out);
+            c0.start.connect((pn0[i] = new ParameterNode(dfg, true)).out);
+            c0.incr.connect(new ForeverNode(dfg, 1).out);
+            c1.start.connect((pn1[i] = new ParameterNode(dfg)).out);
+            c1.incr.connect((pn2[i] = new ParameterNode(dfg)).out);
 
-            RepeatNode r1 = new RepeatNode(proc);
+            RepeatNode r1 = new RepeatNode(dfg);
             r1.val.connect(c1.out);
-            r1.count.connect(new ForeverNode(proc, stride_length).out);
-
-            AluNode alu = new AluNode(proc);
-            alu.in1.connect(r1.out);
-            alu.in2.connect(c0.out);
-            alu.inOp.connect(new ForeverNode(proc, ((Node.DockInPort)alu.inOp).getConstant("ADD")).out);
-            alu.out.connect(i==0 ? mm.inAddrRead1 : mm.inAddrRead2);
-
-            PunctuatorNode punc = new PunctuatorNode(proc, -1);
-            punc.count.connect(new ForeverNode(proc, stride_length).out);
-            punc.val.connect(i==0 ? mm.outRead1 : mm.outRead2);
+            r1.count.connect((pn3[i] = new ParameterNode(dfg, true)).out);
+
+            AluNode alu1 = new AluNode(dfg, "ADD");
+            AluNode alu2 = new AluNode(dfg, "ADD");
+            alu1.in1.connect(r1.out);
+            alu1.in2.connect(c0.out);
+            alu1.out.connect(alu2.in2);
+            alu2.in1.connect((pn_base1[i] = new ParameterNode(dfg, true)).out);
+            alu2.out.connect(i==0 ? mem_read.inAddrRead1 : mem_read.inAddrRead2);
+
+            PunctuatorNode punc = new PunctuatorNode(dfg, -1);
+            punc.count.connect((pn4[i] = new ParameterNode(dfg, true)).out);
+            punc.val.connect(i==0 ? mem_read.outRead1 : mem_read.outRead2);
             punc.out.connect(i==0 ? sm.in1 : sm.in2);
         }
 
-        UnPunctuatorNode unpunc = new UnPunctuatorNode(proc);
+        UnPunctuatorNode unpunc = new UnPunctuatorNode(dfg);
         unpunc.val.connect(sm.out);
-        unpunc.count.connect(new ForeverNode(proc, 2*stride_length).out);
-
-        DownCounterNode cw = new DownCounterNode(proc);
-        cw.start.connect(new OnceNode(proc, end_of_data).out);
-        cw.incr.connect(new OnceNode(proc, 1).out);
+        unpunc.count.connect(pn6.out);
 
-        MemoryNode mm2 = new MemoryNode(proc, memoryShip2);
-        mm2.inAddrWrite.connect(cw.out);
-        mm2.inDataWrite.connect(unpunc.out);
-        mm2.outWrite.connect(dm.in);
+        DownCounterNode cw = new DownCounterNode(dfg);
+        cw.start.connect(pn5.out);
+        cw.incr.connect(new OnceNode(dfg, 1).out);
 
-        //////////////////////////////////////////////////////////////////////////////
+        AluNode alu = new AluNode(dfg, "ADD");
+        alu.in1.connect(pn_base2.out);
+        cw.out.connect(alu.in2);
+        mem_write.inAddrWrite.connect(alu.out);
+        mem_write.inDataWrite.connect(unpunc.out);
 
-        Ship codeMemoryShip = proc.pool.allocateShip("Memory");
+        UnPunctuatorNode discard = new UnPunctuatorNode(dfg, true);
+        discard.count.connect(pn_end.out);
+        mem_write.outWrite.connect(discard.val);
+        DoneNode done = new DoneNode(dfg, program);
+        discard.out.connect(done.in);
 
-        Context ctx = new Context(fp.getFleet());
-        ctx.setAutoflush(true);
-        proc.build(ctx);
-        ctx.dispatch(fp, true);
+        return done.getDestinationToSendNextCodeBagDescriptorTo();
+    }
 
-        for(int i=0; i<vals_length; i++) {
-            System.out.print("\rreading back... " + i+"/"+vals_length+"  ");
-            BitVector rec = fp.recvWord();
-            System.out.print(" (prev result: " + rec + " = " + rec.toLong() + ")");
-        }
-        System.out.println("\rdone.                                                                    ");
-
-        Dock debugIn = fleet.getShip("Debug",0).getDock("in");
-        fp.sendToken(debugIn.getInstructionDestination());
-        fp.flush();
-
-        int count = 0;
-        Ship counter = proc.pool.allocateShip("Counter");
-
-        for(int phase=0; phase<=3; phase++) {
-            System.out.println("== phase "+phase+" ==================================================================");
-
-            LoopFactory lf;
-
-            Destination ackDestination = counter.getDock("in2").getDataDestination();
-            HashSet<Dock> sendTorpedoesTo = new HashSet<Dock>();
-            Context ctx_reset = new Context(fp.getFleet());
-            int expected_tokens = proc.reset(ctx_reset, phase, ackDestination, sendTorpedoesTo);
-
-            Context ctx_debug = new Context(fp.getFleet());
-            lf = new LoopFactory(ctx_debug, debugIn, 0);
-            lf.literal(0);
-            lf.abortLoopIfTorpedoPresent();
-            lf.recvToken();
-            lf.deliver();
-
-            Context ctx_count = new Context(fp.getFleet());
-            lf = new LoopFactory(ctx_count, counter.getDock("inOp"), 1);
-            lf.literal("DROP_C1_V2");
-            lf.deliver();
-            lf.literal(5);
-            lf.deliver();
-            lf = new LoopFactory(ctx_count, counter.getDock("in1"), 1);
-            lf.literal(expected_tokens-1);
-            lf.deliver();
-            lf.literal(1);
-            lf.deliver();
-            lf = new LoopFactory(ctx_count, counter.getDock("in2"), 0);
-            lf.abortLoopIfTorpedoPresent();
-            lf.recvWord();
-            lf.deliver();
-            lf = new LoopFactory(ctx_count, counter.getDock("out"), 1);
-            lf.collectWord();
-            lf.sendToken(counter.getDock("in2").getInstructionDestination());  // HACK: we don't check to make sure this hits
-            lf.sendToken(debugIn.getDataDestination());
-
-            Program program = new Program(codeMemoryShip);
-            CodeBag cb = program.makeCodeBag(ctx_count);
-            program.install(fp);
-            MemoryUtils.putMemoryShipInDispatchMode(fp, codeMemoryShip);
-            program.run(fp, cb);
-            fp.flush();
-
-            ctx_debug.dispatch(fp, true);
-            //ctx_count.dispatch(fp, true);  // HACK: we don't check to make sure that this is "firmly in place"
-            for(Dock dock : sendTorpedoesTo) fp.sendToken(dock.getInstructionDestination());
-            ctx_reset.dispatch(fp, true);
-            System.out.println("flushed");
-
-            fp.recvWord();
-            fp.sendToken(debugIn.getInstructionDestination());
-            System.out.println("phase done");
-
-            MemoryUtils.removeMemoryShipFromDispatchMode(fp, codeMemoryShip);
-            System.out.println();
+    public CodeBag build(DataFlowGraph dfg,
+                         CodeBag ctx,
+                         int vals_length, int stride_length,
+                         long base1,
+                         long base2,
+                         CodeBag next) throws Exception {
+       
+        for(int i=0; i<arity; i++) {
+            if (pn0[i]!=null) pn0[i].set(ctx, stride_length);
+            if (pn1[i]!=null) pn1[i].set(ctx, vals_length + i*stride_length);
+            if (pn2[i]!=null) pn2[i].set(ctx, 2*stride_length);
+            if (pn3[i]!=null) pn3[i].set(ctx, stride_length);
+            if (pn4[i]!=null) pn4[i].set(ctx, stride_length);
+            if (pn_base1[i]!=null) pn_base1[i].set(ctx, base1);
         }
+        pn5.set(ctx, vals_length);
+        pn6.set(ctx, 2*stride_length+1);
+        pn_base2.set(ctx, base2);
+        pn_end.set(ctx, vals_length);
+        ctx.sendWord(cb2.getDescriptor(), program.getCBDDestination());
+        ctx.sendWord(next.getDescriptor(), next_dest);
+        ctx.seal();
+
+        return ctx;
+    }
 
-        fp.flush();
-
-        //System.out.println("verifying cleanup:");
-        //CleanupUtils.verifyClean(fp);
+    public static void main(String[] s) throws Exception {
+        //mergeSort(1024*64, 4, "Dvi",
+        mergeSort(1024*128, 4, "Dvi",
+                  4194304
+                  );
+                  //548*478);
+    }
 
-        System.out.println("reading back:");
-        long[] ret = null;
-        if (vals != null) {
-            ret = new long[vals_length];
-            BitVector[] mem = new BitVector[vals_length];
-            MemoryUtils.readMem(fp, memoryShip2, 0, mem);
-            for(int i=0; i<ret.length; i++) ret[i] = mem[i].toLong();
+    /** demo */
+    public static void main0(String[] s) throws Exception {
+        PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream("stats.txt")));
+        //int inflight = 1;
+        for(int inflight=1; inflight <= 8; inflight++)
+        for(int count = 32; count < 2097152; count *= 2) {
+            System.out.println("==============================================================================");
+            System.out.println("count="+count);
+            System.out.println("inflight="+inflight);
+            //long time = timeit(count, inflight);
+            long time = mergeSort(count, inflight, "DDR2", 0);
+            pw.println(inflight + ", " + count + ", " + time);
+            pw.flush();
         }
-        return ret;
     }
 
-    /** demo */
-    public static void main(String[] s) throws Exception {
+    public static long timeit(int count, int inflight) throws Exception {
         Fleet fleet = new Fpga();
-        //Fleet fleet = new Interpreter(false);
+        FleetProcess fp = fleet.run(new Instruction[0]);
+        ShipPool pool = new ShipPool(fleet);
+        //Program program = new Program(pool.allocateShip("Memory"));
+        CodeBag cb = new CodeBag(fleet);
 
-        Random random = new Random(System.currentTimeMillis());
-        long[] vals = new long[256];
-        for(int i=0; i<vals.length; i++) {
-            vals[i] = Math.abs(random.nextInt());
-        }
+        Ship counter1 = pool.allocateShip("Counter");
+        Ship counter2 = pool.allocateShip("Counter");
 
-        Ship mem1 = fleet.getShip("Memory", 0);
-        Ship mem2 = fleet.getShip("Memory", 1);
-        //Ship mem2 = fleet.getShip("DDR2", 0);
+        Ship timer    = pool.allocateShip("Timer");
+        Ship debug    = pool.allocateShip("Debug");
 
-        FleetProcess fp;
-        int stride = 1;
-        fp = null;
+        LoopFactory lf;
 
-        fp = fleet.run(new Instruction[0]);
-        MemoryUtils.writeMem(fp, mem1, 0, vals);
-        int vals_length = vals.length;
+        lf = cb.loopFactory(debug.getDock("in"), 2);
+        lf.recvWord();
+        lf.deliver();
 
-        // Disable readback/writeback inside the loop
-        vals = null;
 
-        while(stride < vals_length) {
-            
-            // reset the FleetProcess
-            //fp.terminate(); fp = null;
+        // First counter //////////////////////////////////////////////////////////////////////////////
 
-            System.out.println("stride " + stride);
+        lf = cb.loopFactory(counter1.getDock("in1"), 1);
+        lf.recvToken();
+        lf.literal(count);
+        lf.deliver();
 
-            // if we reset the FleetProcess, restart it
-            if (fp==null) fp = fleet.run(new Instruction[0]);
+        lf = cb.loopFactory(counter1.getDock("in2"), 1);
+        lf.literal(1);
+        lf.deliver();
 
-            ShipPool pool = new ShipPool(fleet);
-            pool.allocateShip(mem1);
-            pool.allocateShip(mem2);
+        lf = cb.loopFactory(counter1.getDock("inOp"), 1);
+        lf.literal("COUNT");
+        lf.deliver();
 
-            // do the mergeSort
-            vals = MergeSort.mergeSort(fp, fleet, pool, vals, vals_length, stride, mem1, mem2);
+        lf = cb.loopFactory(counter1.getDock("out"), 0);
+        lf.recvToken();
+        lf.collectWord();
+        lf.sendWord(counter2.getDock("in2"));
 
-            // verify the cleanup
-            //CleanupUtils.verifyClean(fp);
 
-            Ship mem = mem1; mem1=mem2; mem2=mem;
+        // Second counter //////////////////////////////////////////////////////////////////////////////
 
-            stride = stride * 2;
-            System.out.println();
-        }
+        lf = cb.loopFactory(counter2.getDock("in1"), 1);
+        lf.literal(count);
+        lf.deliver();
+        lf.literal(1);
+        lf.deliver();
+        lf.literal(1);
+        lf.deliver();
+
+        lf = cb.loopFactory(counter2.getDock("in2"), 1);
+        for(int i=0; i<inflight; i++)
+            lf.sendToken(counter1.getDock("out"));
+        lf = lf.makeNext(0);
+        lf.recvWord();
+        lf.sendToken(counter1.getDock("out"));
+        lf.deliver();
+
+        lf = cb.loopFactory(counter2.getDock("inOp"), 1);
+        lf.literal("DROP_C1_V2");
+        lf.deliver();
+        lf.literal("PASS_C1_V1");
+        lf.deliver();
+
+        lf = cb.loopFactory(counter2.getDock("out"), 1);
+        lf.collectWord();
+        lf.sendToken(timer.getDock("out"));
+
+
+        // Timer //////////////////////////////////////////////////////////////////////////////
+
+        lf = cb.loopFactory(timer.getDock("out"), 1);
+        lf.collectWord();
+        lf.sendToken(counter1.getDock("in1"));
+        lf.sendWord(debug.getDock("in"));
+        lf.recvToken();
+        lf.collectWord();
+        lf.sendWord(debug.getDock("in"));
+
+        FpgaDock out = (FpgaDock)counter1.getDock("out");
+        FpgaDock in  = (FpgaDock)counter2.getDock("in2");
+        System.out.println("distance is " + out.getPathLength((FpgaDestination)in.getDataDestination()));
+        System.out.println("reverse distance is " + in.getPathLength((FpgaDestination)out.getDataDestination()));
+
+        for(Instruction i : cb.emit()) System.out.println(i);
+        cb.dispatch(fp, true);
+        long time1 = fp.recvWord().toLong();
+        System.out.println("got " + time1);
+        long time2 = fp.recvWord().toLong();
+        System.out.println("got " + time2);
+        System.out.println("diff=" + (time2-time1));
+
+        fp.terminate();
+
+        return (time2-time1);
+    }
+
+    public static long mergeSort(int vals_length, int inflight, String shipType, int clearAmount) throws Exception {
+        Node.CAPACITY = inflight;
+
+        Fleet fleet = new Fpga();
+        FleetProcess fp = fleet.run(new Instruction[0]);
+        ShipPool pool = new ShipPool(fleet);
+        Ship mem1 = pool.allocateShip(shipType);
+
+
+        if (clearAmount > 0)
+            randomizeMemory(fp, pool, mem1, 0, clearAmount, false);
+
+        //randomizeMemory(fp, pool, mem1, 0, vals_length, true);
 
         BitVector[] bvs = new BitVector[vals_length];
-        MemoryUtils.readMem(fp, mem1, 0, bvs);
+
+        long index = 0;
+        /*
+        Picture p = new Picture(new FileInputStream("campus.png"));
+        for(int y=0; y<(478/2); y++)
+            for(int x=0; x<544; x++) {
+                if (index >= vals_length) break;
+                int pixel = (x>=p.width) ? 0 : p.data[p.width*y+x];
+                long r = (pixel>>0)  & 0xff;
+                long g = (pixel>>8)  & 0xff;
+                long b = (pixel>>16) & 0xff;
+                r >>= 2;
+                g >>= 2;
+                b >>= 2;
+                //r = ~(-1L<<6);
+                //g = ~(-1L<<6);
+                //b = ~(-1L<<6);
+                bvs[(int)index] = new BitVector(fleet.getWordWidth()).set( r | (g<<6) | (b<<12) | (index<<18) );
+                index++;
+            }
+        */
+        for(; index<vals_length; index++) {
+            long tag = index<<18;
+            bvs[(int)index] = new BitVector(fleet.getWordWidth()).set( tag );
+        }
+
+        System.out.println("final index " + index);
+
+        Random random = new Random(System.currentTimeMillis());
+        for(int i=0; i<bvs.length*10; i++) {
+            int from = Math.abs(random.nextInt()) % bvs.length;
+            int to   = Math.abs(random.nextInt()) % bvs.length;
+            BitVector bv = bvs[from];
+            bvs[from] = bvs[to];
+            bvs[to] = bv;
+        }
+
+        MemoryUtils.writeMem(fp, pool, mem1, offset, bvs);
+
+        Program program = new Program(pool.allocateShip("Memory"));
+        long ret = new MergeSort(fleet, program, pool, 2, mem1, mem1).main(fp, vals_length);
+
+        //long ret = 0;
+        // verify the cleanup?
+        //CleanupUtils.verifyClean(fp);
+        //MemoryUtils.readMem(fp, new ShipPool(fp.getFleet()), mem1, 0, bvs);
+
+        BitVector[] bvx = new BitVector[1024];
+        MemoryUtils.readMem(fp, new ShipPool(fp.getFleet()), mem1, 0, bvx);
+        for(int i=0; i<bvx.length; i++)
+            System.out.println(bvx[i]);
+        /*
         System.out.println("results:");
-        for(int i=0; i<vals_length; i++)
-            System.out.println(bvs[i].toLong());
+        for(int i=0; i<vals_length-1; i++)
+            if ( (bvs[i].toLong() & ~(-1L<<18)) != ~(-1L<<18))
+                System.out.println(bvs[i]);
+        */
+        /*
+        for(int i=0; i<vals_length-1; i++) {
+            if (bvs[i].toLong() > bvs[i+1].toLong())
+                System.out.println("sort failure at "+i+":\n  "+bvs[i]+"\n  "+bvs[i+1]);
+        }
+        */
+        fp.terminate();
+        return ret;
     }
 
+    static int offset = 40;
+
+    //static int offset = 32;
+    //static int offset = 544*2;
+    //static int offset = 544;
+
+    public long main(FleetProcess fp, int vals_length) throws Exception {
+
+        long base_read = offset;
+        //long base_write = offset+((vals_length/544)+1)*544;
+        //long base_write = offset;
+        long base_write = vals_length + offset;
+
+        int stride = 1;
+        ArrayList<CodeBag> codeBags = new ArrayList<CodeBag>();
+        codeBags.add(new CodeBag(dfg.fleet, program));
+        for(; ;) {
+            CodeBag cb = codeBags.get(codeBags.size()-1);
+            //System.out.println("cb="+i+", stride="+stride);
+            boolean last = /*(base_write==offset) && */ (stride*2 >= vals_length);
+            CodeBag next;
+            if (last) {
+                next = program.getEndProgramCodeBag();
+            } else {
+                next = new CodeBag(dfg.fleet, program);
+                codeBags.add(codeBags.size(), next);
+            }
+            build(dfg, cb, vals_length, stride, base_read, base_write, next);
+            cb.seal();
+            long base = base_read; base_read=base_write; base_write=base;
+            //i++;
+            if (last) break;
+            if ((stride*2) < vals_length) stride *= 2;
+        }
+        System.out.println("done building codebags; installing...");
+        System.out.println("cb.length=="+codeBags.size());
+
+        Ship button = pool.allocateShip("Button");
+        CodeBag cb = new CodeBag(dfg.fleet, program);
+        LoopFactory lf = cb.loopFactory(button.getDock("out"), 1);
+        lf.collectWord();
+        lf.literal(codeBags.get(0).getDescriptor());
+        lf.sendWord(program.getCBDDestination());
+        cb.seal();
+
+        // FIXME
+        return program.run(fp, cb, new ShipPool(fp.getFleet()));
+    }
+
+    public static void randomizeMemory(FleetProcess fp, ShipPool pool_, Ship memory, long start, long length, boolean randomize) {
+        ShipPool pool = new ShipPool(pool_);
+        Ship mem = pool.allocateShip("Memory");
+        Program prog = new Program(mem);
+
+        DataFlowGraph dfg = new DataFlowGraph(fp.getFleet(), pool);
+        DownCounterNode dcn = new DownCounterNode(dfg);
+        dcn.start.connectOnce(length);
+        dcn.incr.connectOnce(1);
+
+        AluNode alu = new AluNode(dfg, "ADD");
+        alu.in1.connectForever(start);
+        alu.in2.connect(dcn.out);
+
+        MemoryNode mn = new MemoryNode(dfg, memory);
+        mn.inAddrWrite.connect(alu.out);
+
+        AluNode aluAnd = new AluNode(dfg, "AND");
+        if (randomize) {
+            aluAnd.in1.connect(new RandomNode(dfg).out);
+        } else {
+            //aluAnd.in1.connectForever( ~(-1L<<36) );
+            aluAnd.in1.connectForever( 0 );
+        }
+        aluAnd.in2.connectForever( ~(-1<<18) );
+        mn.inDataWrite.connect(aluAnd.out);
+        
+        UnPunctuatorNode discard = new UnPunctuatorNode(dfg, true);
+        discard.count.connectOnce(length);
+        discard.val.connect(mn.outWrite);
+        DoneNode done = new DoneNode(dfg, prog);
+        discard.out.connect(done.in);
+
+        CodeBag cb = new CodeBag(fp.getFleet(), prog);
+        dfg.build(cb);
+        cb.seal();
+
+        CodeBag cb2 = new CodeBag(fp.getFleet(), prog);
+        Ship button = fp.getFleet().getShip("Button",0);
+
+        LoopFactory lf = cb2.loopFactory(button.getDock("out"), 1);
+        //lf.collectWord();
+        lf.literal(prog.getEndProgramCodeBag().getDescriptor());
+        lf.sendWord(done.getDestinationToSendNextCodeBagDescriptorTo());
+        lf.literal(cb.getDescriptor());
+        lf.sendWord(prog.getCBDDestination());
+        cb2.seal();
+
+        System.out.println("dispatching randomization codebag...");
+        prog.run(fp, cb2, pool);
+        System.out.println("  randomization done.");
+        pool.releaseAll();
+    }
 }
index b4bb13a..f090050 100644 (file)
@@ -15,6 +15,8 @@ import static edu.berkeley.fleet.util.BitManipulations.*;
 
 public class Node {
 
+    public static int CAPACITY = 4;
+
     public final DataFlowGraph dfg;
     public Node(DataFlowGraph dfg) {
         this.dfg = dfg;
@@ -22,10 +24,10 @@ public class Node {
     }
 
     private HashMap<String,Port> ports = new HashMap<String,Port>();
-    public void build(Context ctx) { for(Port p : ports.values()) p.build(ctx); }
-    public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
+    public void build(CodeBag ctx) { for(Port p : ports.values()) p.build(ctx); }
+    public int reset(CodeBag ctx, int phase, Destination ackDestination) {
         int ret = 0;
-        for(Port p : ports.values()) ret += p.reset(ctx, phase, ackDestination, sendTorpedoesTo);
+        for(Port p : ports.values()) ret += p.reset(ctx, phase, ackDestination);
         return ret;
     }
 
@@ -36,8 +38,8 @@ public class Node {
             if (Node.this.ports.get(name)!=null) throw new RuntimeException();
             Node.this.ports.put(name,this);
         }
-        public abstract void build(Context ctx);
-        public abstract int  reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo);
+        public abstract void build(CodeBag ctx);
+        public abstract int  reset(CodeBag ctx, int phase, Destination ackDestination);
         public String toString() { return Node.this+"."+name; }
     }
 
@@ -48,6 +50,10 @@ public class Node {
             this.setPeer(peer);
             peer.setPeer(this);
         }
+
+        public void connectOnce(long val) { connect(new OnceNode(dfg, val).out); }
+        public void connectForever(long val) { connect(new ForeverNode(dfg, val).out); }
+
         public void setPeer(OutPort peer) {
             if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
             this.peer = peer;
@@ -59,6 +65,7 @@ public class Node {
         public abstract void sendWord(LoopFactory loopfactory_at_output_dock);
 
         public int getTokensToAbsorb() { return 0; }
+        public int getMaxInFlight() { return 0; }
     }
 
     public abstract class OutPort extends Port {
@@ -73,17 +80,29 @@ public class Node {
             this.peer = peer;
         }
 
+        public int getNumInitialTokens() {
+            return peer.getMaxInFlight();
+        }
+
         /** this port's peer (an InPort) invokes this to have "sendToken" or equivalent inserted */
         public abstract void sendToken(LoopFactory loopfactory_at_input_dock);
         /** this port's peer (an InPort) invokes this to have "recvWord" or equivalent inserted */
         public abstract void recvWord(LoopFactory loopfactory_at_input_dock);
+
+        public int getTokensToAbsorb() {
+            if (peer==null) return 0;
+            return peer.getTokensToAbsorb();
+        }
     }
 
     public final class DockInPort extends InPort {
         final Dock dock;
         int count;
         BitVector[] pattern;
+        public boolean sticky = false;
         public DockInPort(String name, Dock dock) { this(name, dock, 0); }
+        public DockInPort(String name, Dock dock, String constant) {
+            this(name, dock, 0, new BitVector[] { dock.getConstant(constant) }); }
         public DockInPort(String name, Dock dock, int count) { this(name, dock, count, new BitVector[] { null }); }
         public DockInPort(String name, Dock dock, int count, BitVector[] pattern) {
             super(name);
@@ -93,26 +112,51 @@ public class Node {
         }
         public void recvToken(LoopFactory lf) { lf.recvToken(); }
         public void sendWord(LoopFactory lf) { lf.sendWord(dock.getDataDestination()); }
-        public void build(Context ctx) { build(ctx, new LoopFactory(ctx, dock, 1)); }
-        // number-in-flight is considered a property of the input dock in a pair
-        public int getInflight() { return 4; }
-        //public int getInflight() { return 1; }
-        public int getTokensToAbsorb() { return getInflight(); }
+        public void build(CodeBag ctx) { build(ctx, ctx.loopFactory(dock, 1)); }
+
+        // this is the input dock's upper limit on how many data items
+        // may be in flight; the output dock to which it is connected
+        // also has a say
+        public int getMaxInFlight() { return CAPACITY; }
+
+        public int getTokensToAbsorb() { return sticky ? 0 : peer==null ? 0 : peer.getNumInitialTokens(); }
         private boolean peerUsed() {
+            if (sticky) return false;
             if (peer==null) return false;
             for(int i=0; i<pattern.length; i++) if (pattern[i]==null) return true;
             return false;
         }
-        public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
-            return doReset(ctx, phase, dock, peer, ackDestination, sendTorpedoesTo, peerUsed());
+        public int reset(CodeBag ctx, int phase, Destination ackDestination) {
+            return DoneNode.doReset(ctx, phase, dock, this, peer, ackDestination, peerUsed());
         }
-        protected void build(Context ctx, LoopFactory lf) {
-            int inflight = (count != 0 && count < getInflight()) ? count : getInflight();
+        protected void build(CodeBag ctx, LoopFactory lf) {
+            /*
+            if (sticky) {
+                if (count != 0) throw new RuntimeException("expected count==0, but count=="+count);
+                lf = lf.makeNext(1, true);
+                lf.recvWord();
+                }
+            */
+            if (sticky) {
+                if (count != 0) throw new RuntimeException("expected count==0, but count=="+count);
+                lf = lf.makeNext(1, true);
+                lf.setFlags(FlagFunction.ZERO,  FlagFunction.ZERO);
+            }
 
-            if (peer!=null)
+            if (peer!=null) {
+                int inflight = (count != 0 && count < peer.getNumInitialTokens()) ? count : peer.getNumInitialTokens();
                 for(int i=0; i<inflight; i++) peer.sendToken(lf);
+            }
 
             lf = lf.makeNext(count, true);
+
+            // ugly hack!
+            if (sticky) {
+                lf.setPredicate(Predicate.NotFlagB);
+                lf.recvWord();
+                lf.setPredicate(null);
+                lf.setFlags(FlagFunction.ZERO,  FlagFunction.ONE);
+            }
             for(int i=0; i<pattern.length; i++) {
                 if (pattern[i]==null) {
                     if (peer!=null) {
@@ -148,8 +192,8 @@ public class Node {
         public DockOutPort(String name, Dock dock, int count) { super(name); this.dock = dock; this.count = count; }
         public void sendToken(LoopFactory lf) { lf.sendToken(dock.getDataDestination()); }
         public void recvWord(LoopFactory lf) { lf.recvWord(); }
-        public void build(Context ctx) { build(ctx, new LoopFactory(ctx, dock, 1)); }
-        protected void build(Context ctx, LoopFactory lf) {
+        public void build(CodeBag ctx) { build(ctx, ctx.loopFactory(dock, 1)); }
+        protected void build(CodeBag ctx, LoopFactory lf) {
             if (peer==null) return;
             lf = lf.makeNext(count);
             lf.abortLoopIfTorpedoPresent();
@@ -157,8 +201,8 @@ public class Node {
             lf.collectWord();
             peer.sendWord(lf);
         }
-        public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
-            return doReset(ctx, phase, dock, peer, ackDestination, sendTorpedoesTo, true);
+        public int reset(CodeBag ctx, int phase, Destination ackDestination) {
+            return DoneNode.doReset(ctx, phase, dock, this, peer, ackDestination, true);
         }
     }
 
@@ -169,93 +213,4 @@ public class Node {
         return ret;
     }
 
-    // Reset //////////////////////////////////////////////////////////////////////////////
-
-    int doReset(Context ctx,
-                int phase,
-                Dock dock,
-                Port peer,
-                Destination ackDestination,
-                HashSet<Dock> sendTorpedoesTo,
-                boolean peerUsed) {
-        int ret = 0;
-        if (dock.getShip().getType().equals("Debug")) return ret;
-
-        switch(phase) {
-
-            // Phase 0: torpedo every output dock, put it in
-            // collecting mode.  Cannot combine with phase 1,
-            // because until output docks are in vacuum mode we
-            // cannot be sure that the tokens to the input docks
-            // will eventually succeed.  This may cause the
-            // instructions sent after the tokens to back up into
-            // the switch fabric.
-            case 0: {
-                if (!dock.isInputDock()) {
-                    sendTorpedoesTo.add(dock);
-                    LoopFactory lf = new LoopFactory(ctx, dock, 1);
-                    lf.sendToken(ackDestination);
-                    lf = lf.makeNext(0);
-                    lf.abortLoopIfTorpedoPresent();
-                    lf.collectWord();
-                    ret++;
-                }
-                break;
-            }
-
-                // [wait for all output docks to confirm that they've been torpedoed]
-                // Phase 1: torpedo every input dock (causing them to flush), put it in loopback mode
-            case 1: {
-                if (dock.isInputDock()) {
-                    sendTorpedoesTo.add(dock);
-                    LoopFactory lf = new LoopFactory(ctx, dock, 1);
-                    lf.sendToken(ackDestination);
-
-                    // FIXME: this won't work right for ports that
-                    // get "shared" by two senders (for example,
-                    // inAddrRead1/2)
-
-                    if (peerUsed && peer!=null) {
-                        lf = lf.makeNext(0);
-                        lf.abortLoopIfTorpedoPresent();
-                        ((OutPort)peer).recvWord(lf);
-                        ((OutPort)peer).sendToken(lf);
-                    }
-                    ret++;
-                }
-                break;
-            }
-
-                // [wait for all input docks to confirm that they've been torpedoed and have flushed]
-                // Phase 2: torpedo every output dock, have it absorb tokens
-            case 2: {
-                if (!dock.isInputDock()) {
-                    sendTorpedoesTo.add(dock);
-                    LoopFactory lf = new LoopFactory(ctx, dock, 1);
-                    if (peer != null)
-                        for(int i=0; i<((InPort)peer).getTokensToAbsorb(); i++)
-                            lf.recvToken();
-                    lf.sendToken(ackDestination);
-                    ret++;
-                }
-                break;
-            }
-
-                // [wait for all output docks to confirm that they've absorbed enough tokens]
-                // Phase 3: torpedo every input dock, await confirmation, and we're done
-            case 3: {
-                if (dock.isInputDock()) {
-                    if (peerUsed && peer!=null) {
-                        sendTorpedoesTo.add(dock);
-                    }
-                    LoopFactory lf = new LoopFactory(ctx, dock, 1);
-                    lf.sendToken(ackDestination);
-                    ret++;
-                }
-                break;
-            }
-        }
-        return ret;
-    }
-
 }
index 1a95654..1d4d2aa 100644 (file)
@@ -8,8 +8,8 @@ public class OnceNode extends Node {
     public final OutPort out = new OutPort("out") {
             public void sendToken(LoopFactory lf) { }
             public void recvWord(LoopFactory lf) { }
-            public void build(Context ctx) { }
-            public int  reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) { return 0; }
+            public void build(CodeBag ctx) { }
+            public int  reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; }
             public void setPeer(InPort peer) {
                 this.peer = peer;
                 DockInPort pip = ((DockInPort)peer);
diff --git a/src/edu/berkeley/fleet/dataflow/ParameterNode.java b/src/edu/berkeley/fleet/dataflow/ParameterNode.java
new file mode 100644 (file)
index 0000000..365a114
--- /dev/null
@@ -0,0 +1,58 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+
+// derived from OnceNode
+public class ParameterNode extends Node {
+
+    private boolean forever;
+
+    public void set(CodeBag ctx, long l) {
+        set(ctx, new BitVector(ctx.fleet.getWordWidth()).set(l));
+    }
+    public void set(CodeBag ctx, BitVector bv) {
+        ctx.sendWord(bv, ((DockInPort)out.peer).dock.getDataDestination());
+    }
+
+    public final OutPort out = new OutPort("out") {
+            public void sendToken(LoopFactory lf) { }
+            public void recvWord(LoopFactory lf) { if (!forever) lf.recvWord(); }
+            public void build(CodeBag ctx) { }
+            public int  reset(CodeBag ctx, int phase,
+                              Destination ackDestination) {
+                return 0; }
+            public void setPeer(InPort peer) {
+                this.peer = peer;
+                DockInPort pip = ((DockInPort)peer);
+                BitVector[] pip_pattern = pip.pattern;
+
+                if (forever) {
+                    pip.sticky = true;
+                    return;
+                }
+
+                BitVector[] temp = new BitVector[pip_pattern.length * 2];
+                int j = 0;
+                int i = 0;
+                boolean done = false;
+                // FIXME: if peer.count is already 1, this gets simpler and different
+                for(i=0; i<temp.length; i++) {
+                    if (pip_pattern[j] != null) {
+                        temp[i] = pip_pattern[j];
+                    } else {
+                        if (done) break;
+                        done = true;
+                        //temp[i] = bv;
+                    }
+                    j++;
+                    if (j >= pip_pattern.length) j = 0;
+                }
+                pip.pattern = new BitVector[i];
+                System.arraycopy(temp, 0, pip.pattern, 0, i);
+                pip.count = 1;
+            }
+        };
+    public ParameterNode(DataFlowGraph dfg) { this(dfg, false); }
+    public ParameterNode(DataFlowGraph dfg, boolean forever) { super(dfg); this.forever = forever; }
+}
index cee58ae..dab8d4a 100644 (file)
@@ -2,21 +2,38 @@ package edu.berkeley.fleet.dataflow;
 import java.util.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
 
+/**
+ *  Takes an item from "count", passes that many items from "val" to
+ *  "out", and then supplies one instance of "punc" at "out".
+ */
 public class PunctuatorNode extends Node {
     private final long    punc;
-    private final Ship    ship  = dfg.pool.allocateShip("Counter");
-    private final InPort  op    = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] {
-            ship.getDock("inOp").getConstant("PASS_C2_V1"),
-            ship.getDock("inOp").getConstant("PASS_C2_V2") } );
-
     public  final InPort  count;
-    public  final OutPort out   = new DockOutPort("out", ship.getDock("out"));
+    private final Ship    ship  = dfg.pool.allocateShip("Counter");
+    private final InPort  op    = new DockInPort("inOp", ship.getDock("inOp"), "PASS_C2_V1");
     public  final InPort  val   = new DockInPort("val",  ship.getDock("in1"));
+    public  final OutPort out   = new DockOutPort("out", ship.getDock("out")) {
+            protected void build(CodeBag ctx, LoopFactory lf) {
+                lf = lf.makeNext(0);
+                lf.abortLoopIfTorpedoPresent();
+                peer.recvToken(lf);
+                lf.collectWord();
+                peer.sendWord(lf);
+
+                lf.literal(punc);
+                lf.setFlags(FlagFunction.ZERO.add(Predicate.FlagC), FlagFunction.ZERO);
+                lf.setPredicate(Predicate.FlagA);
+                peer.recvToken(lf);
+                peer.sendWord(lf);
+                lf.setPredicate(null);
+            }
+        };
 
     public PunctuatorNode(DataFlowGraph dfg, long punc) {
         super(dfg);
         this.punc = punc;
-        this.count = new DockInPort("in2", ship.getDock("in2"), 0, new BitVector[] { null, bv(1), bv(punc) });
+        this.count = new DockInPort("in2", ship.getDock("in2"));
     }
 }
diff --git a/src/edu/berkeley/fleet/dataflow/RandomNode.java b/src/edu/berkeley/fleet/dataflow/RandomNode.java
new file mode 100644 (file)
index 0000000..9143cf2
--- /dev/null
@@ -0,0 +1,10 @@
+package edu.berkeley.fleet.dataflow;
+import java.util.*;
+import edu.berkeley.fleet.loops.*;
+import edu.berkeley.fleet.api.*;
+
+public class RandomNode extends Node {
+    private final Ship    ship = dfg.pool.allocateShip("Random");
+    public final OutPort out  = new DockOutPort("out", ship.getDock("out"));
+    public RandomNode(DataFlowGraph dfg) { super(dfg); }
+}
index 2cc54db..f17586a 100644 (file)
@@ -3,14 +3,16 @@ import java.util.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
 
+/**
+ *  Takes a count from "count" and an item from "val" and emits
+ *  count-many copies of val at "out".
+ */
 public class RepeatNode extends Node {
     private final Ship    ship   = dfg.pool.allocateShip("Counter");
-    private final InPort  inOp   = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] {
-            ship.getDock("inOp").getConstant("REPEAT_C1_V2") });
-
-    public final InPort  count  = new DockInPort("count",  ship.getDock("in1"));
-    public final InPort  val    = new DockInPort("val",  ship.getDock("in2"));
-    public final OutPort out    = new DockOutPort("out", ship.getDock("out"));
+    private final InPort  inOp   = new DockInPort("inOp", ship.getDock("inOp"), "REPEAT_C1_V2");
+    public final InPort   count  = new DockInPort("count",  ship.getDock("in1"));
+    public final InPort   val    = new DockInPort("val",  ship.getDock("in2"));
+    public final OutPort  out    = new DockOutPort("out", ship.getDock("out"));
 
     public RepeatNode(DataFlowGraph dfg) { super(dfg); }
 }
index 038b388..62bf886 100644 (file)
@@ -2,16 +2,35 @@ package edu.berkeley.fleet.dataflow;
 import java.util.*;
 import edu.berkeley.fleet.loops.*;
 import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
 
+/**
+ *  Takes an item from the "count" port, then passes/drops through count-1
+ *  items from "val" to "out" and drops/passes the count-th item.
+ */
 public class UnPunctuatorNode extends Node {
     private final Ship    ship  = dfg.pool.allocateShip("Counter");
-    private final InPort  op    = new DockInPort("op",    ship.getDock("inOp"), 0, new BitVector[] {
-            ship.getDock("inOp").getConstant("PASS_C2_V1"),
-            ship.getDock("inOp").getConstant("DROP_C2_V1") } );
-
-    public  final OutPort out   = new DockOutPort("out",  ship.getDock("out"));
+    private final InPort  op    = new DockInPort("op",    ship.getDock("inOp"), "PASS_C2_V1");
     public  final InPort  val   = new DockInPort("val",   ship.getDock("in1"));
-    public  final InPort  count = new DockInPort("count", ship.getDock("in2"), 0, new BitVector[] { null, bv(1) });
+    public  final InPort  count = new DockInPort("count", ship.getDock("in2"));
+    public  final OutPort out   = new DockOutPort("out", ship.getDock("out")) {
+            protected void build(CodeBag ctx, LoopFactory lf) {
+                lf = lf.makeNext(0);
+                lf.abortLoopIfTorpedoPresent();
+                lf.collectWord();
+                lf.setFlags(FlagFunction.ZERO.add(Predicate.FlagC), FlagFunction.ZERO);
+                lf.setPredicate(passPunctuationInsteadOfValues ? Predicate.FlagA : Predicate.NotFlagA);
+                lf.abortLoopIfTorpedoPresent();
+                peer.recvToken(lf);
+                peer.sendWord(lf);
+                lf.setPredicate(null);
+            }
+        };
 
-    public UnPunctuatorNode(DataFlowGraph dfg) { super(dfg); }
+    private boolean passPunctuationInsteadOfValues;
+    public UnPunctuatorNode(DataFlowGraph dfg) { this(dfg, false); }
+    public UnPunctuatorNode(DataFlowGraph dfg, boolean passPunctuationInsteadOfValues) {
+        super(dfg);
+        this.passPunctuationInsteadOfValues = passPunctuationInsteadOfValues;
+    }
 }