move LoopFactory into a separate class
authormegacz <adam@megacz.com>
Fri, 13 Mar 2009 16:04:54 +0000 (09:04 -0700)
committermegacz <adam@megacz.com>
Fri, 13 Mar 2009 16:04:54 +0000 (09:04 -0700)
src/edu/berkeley/fleet/ir/Counter.java
src/edu/berkeley/fleet/ir/Gadgets.java
src/edu/berkeley/fleet/ir/New.java
src/edu/berkeley/fleet/ir/Process.java
src/edu/berkeley/fleet/loops/Context.java
src/edu/berkeley/fleet/loops/LoopFactory.java [new file with mode: 0644]

index 1bd1920..059f5a6 100644 (file)
@@ -9,7 +9,6 @@ import edu.berkeley.fleet.api.*;
 import edu.berkeley.fleet.api.Instruction.*;
 import edu.berkeley.fleet.api.Instruction.Set;
 import edu.berkeley.fleet.api.Instruction.Set.*;
-import edu.berkeley.fleet.loops.Context.LoopFactory;
 import static edu.berkeley.fleet.util.BitManipulations.*;
 import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
 import edu.berkeley.fleet.api.Instruction.Set;
@@ -36,9 +35,9 @@ public class Counter {
         Dock in1  = alu.getDock("in1");
         Dock in2  = alu.getDock("in2");
 
-        LoopFactory lf_in1  = ctx.new LoopFactory(in1,  1);
-        LoopFactory lf_in2  = ctx.new LoopFactory(in2,  1);
-        LoopFactory lf_inOp = ctx.new LoopFactory(inOp, 1);
+        LoopFactory lf_in1  = new LoopFactory(ctx, in1,  1);
+        LoopFactory lf_in2  = new LoopFactory(ctx, in2,  1);
+        LoopFactory lf_inOp = new LoopFactory(ctx, inOp, 1);
 
         for(int i=0; i<inflight_in1; i++) lf_in1.sendToken(in1_ack);
         for(int i=0; i<inflight_in2; i++) lf_in2.sendToken(in2_ack);
@@ -59,7 +58,7 @@ public class Counter {
         
         lf_inOp.deliver();
 
-        LoopFactory lf_out  = ctx.new LoopFactory(out, 0);
+        LoopFactory lf_out  = new LoopFactory(ctx, out, 0);
         lf_out.recvToken();
         lf_out.collectWord();
         lf_out.sendWord(d);
@@ -104,10 +103,10 @@ public class Counter {
 
         // FIXME: update Alu to "take-one" behavior, then fix stuff below
 
-        LoopFactory lf_in1  = ctx.new LoopFactory(in1,  1);
-        LoopFactory lf_in2  = ctx.new LoopFactory(in2,  1);
-        LoopFactory lf_inOp = ctx.new LoopFactory(inOp, 1);
-        LoopFactory lf_out  = ctx.new LoopFactory(out, 1);
+        LoopFactory lf_in1  = new LoopFactory(ctx, in1,  1);
+        LoopFactory lf_in2  = new LoopFactory(ctx, in2,  1);
+        LoopFactory lf_inOp = new LoopFactory(ctx, inOp, 1);
+        LoopFactory lf_out  = new LoopFactory(ctx, out, 1);
 
         // Phase 1 //////////////////////////////////////////////////////////////////////////////
 
@@ -200,8 +199,8 @@ public class Counter {
         Dock inAddrRead = mem.getDock("inAddrRead");
         Dock out        = mem.getDock("out");
         
-        LoopFactory lf_inAddrRead = ctx.new LoopFactory(inAddrRead, 0);
-        LoopFactory lf_out        = ctx.new LoopFactory(out, 0);
+        LoopFactory lf_inAddrRead = new LoopFactory(ctx, inAddrRead, 0);
+        LoopFactory lf_out        = new LoopFactory(ctx, out, 0);
 
         lf_inAddrRead.recvWord();
         lf_inAddrRead.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
@@ -305,7 +304,7 @@ public class Counter {
 
 
         LoopFactory lf;
-        lf = ctx.new LoopFactory(debug.getDock("in"), 0);
+        lf = new LoopFactory(ctx, debug.getDock("in"), 0);
         lf.sendToken(d3.getDataDestination());
         lf.recvWord();
         lf.deliver();
index efd6df7..8e0c19c 100644 (file)
@@ -9,7 +9,6 @@ import edu.berkeley.fleet.api.*;
 import edu.berkeley.fleet.api.Instruction.*;
 import edu.berkeley.fleet.api.Instruction.Set;
 import edu.berkeley.fleet.api.Instruction.Set.*;
-import edu.berkeley.fleet.loops.Context.LoopFactory;
 import static edu.berkeley.fleet.util.BitManipulations.*;
 import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
 import edu.berkeley.fleet.api.Instruction.Set;
@@ -53,27 +52,27 @@ public class Gadgets {
         Context ctx = new Context(fp.getFleet());
         LoopFactory lf;
         if (read) {
-            lf = ctx.new LoopFactory(inAddrRead, 0);
+            lf = new LoopFactory(ctx, inAddrRead, 0);
             lf.abortLoopIfTorpedoPresent();
             lf.recvWord();
             lf.deliver();
         } else {
-            lf = ctx.new LoopFactory(inAddrWrite, 0);
+            lf = new LoopFactory(ctx, inAddrWrite, 0);
             lf.abortLoopIfTorpedoPresent();
             lf.recvWord();
             lf.deliver();
-            lf = ctx.new LoopFactory(inDataWrite, 0);
+            lf = new LoopFactory(ctx, inDataWrite, 0);
             lf.abortLoopIfTorpedoPresent();
             lf.recvWord();
             lf.deliver();
         }
 
-        lf = ctx.new LoopFactory(out, 0);
+        lf = new LoopFactory(ctx, out, 0);
         lf.abortLoopIfTorpedoPresent();
         lf.collectWord();
         lf.sendWord(debugIn.getDataDestination());
 
-        lf = ctx.new LoopFactory(debugIn, 0);
+        lf = new LoopFactory(ctx, debugIn, 0);
         lf.abortLoopIfTorpedoPresent();
         lf.recvWord();
         lf.deliver();
@@ -159,12 +158,12 @@ public class Gadgets {
             Dock ag_in2 = address_generators[i].getDock("in2");
             BitVector signal = new BitVector(1/*FIXME*/).set(i/*FIXME*/);
 
-            lf = ctx.new LoopFactory(ag_in1, 0);
+            lf = new LoopFactory(ctx, ag_in1, 0);
             lf.literal(1);
             lf = lf.makeNext(count);
             
 
-            lf = ctx.new LoopFactory(ag_out, 1);
+            lf = new LoopFactory(ctx, ag_out, 1);
             lf.literal(start);
             lf = lf.makeNext(0);
             lf.recvToken();
@@ -175,7 +174,7 @@ public class Gadgets {
 
         // Memory Read ////////////////////////////////////////////////////////////////////////////////////////
 
-        lf = ctx.new LoopFactory(mem_inAddrData, 0);
+        lf = new LoopFactory(ctx, mem_inAddrData, 0);
         lf.recvWord();
         lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
         lf.setPredicate(Predicate.NotFlagA);
@@ -185,7 +184,7 @@ public class Gadgets {
         lf.setPredicate(null);
         lf.deliver();
 
-        lf = ctx.new LoopFactory(mem_out, 0);
+        lf = new LoopFactory(ctx, mem_out, 0);
         lf.collectWord();
         lf.recvToken();
         lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
@@ -198,7 +197,7 @@ public class Gadgets {
         // Merger /////////////////////////////////////////////////////////////////////////////////////////////
 
         for(int i=0; i<merger_inputs.length; i++) {
-            lf = ctx.new LoopFactory(merger_inputs[i], stride_length);
+            lf = new LoopFactory(ctx, merger_inputs[i], stride_length);
             lf.sendToken(address_generators[i].getDock("out").getDataDestination());
             lf.recvWord();
             lf.deliver();
@@ -208,7 +207,7 @@ public class Gadgets {
             lf.deliver();
         }
 
-        lf = ctx.new LoopFactory(merger_inOp, 1);
+        lf = new LoopFactory(ctx, merger_inOp, 1);
         lf.literal(5); // MIN
         lf = lf.makeNext(stride_length * arity);
         lf.deliver();
index f1553a0..2a31591 100644 (file)
@@ -9,7 +9,6 @@ import edu.berkeley.fleet.api.Instruction.Set;
 import edu.berkeley.fleet.api.Instruction.Set.SetDest;
 import edu.berkeley.fleet.api.Instruction.Set.FlagFunction;
 import static edu.berkeley.fleet.api.Predicate.*;
-import edu.berkeley.fleet.loops.Context.LoopFactory;
 import java.io.*;
 import java.util.*;
 import java.net.*;
@@ -38,7 +37,7 @@ public class New {
     public LoopFactory getLoopFactory(Dock d, int count) {
         LoopFactory lf = loops.get(d);
         if (lf==null) {
-            loops.put(d, lf = context.new LoopFactory(d, count, d+""));
+            loops.put(d, lf = new LoopFactory(context, d, count, d+""));
             emitLoops.add(lf);
         }
         if (lf.count != count) throw new RuntimeException();
@@ -96,7 +95,7 @@ public class New {
         public void emitPrologue(ArrayList<Instruction> il) { }
         public void emitInstructions(ArrayList<Instruction> il) {
             LoopFactory lf;
-            lf = context.new LoopFactory(debugShip.getDock("in"), 0, "debug.in");
+            lf = new LoopFactory(context, debugShip.getDock("in"), 0, "debug.in");
             lf.recvWord();
             lf.deliver();
         }
index ce82b5a..8f48fef 100644 (file)
@@ -70,7 +70,7 @@ public class Process {
                 case 0: {
                     if (!dock.isInputDock()) {
                         torpedoes.add(dock);
-                        Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
+                        LoopFactory lf = new LoopFactory(ctx, dock, 1);
                         lf.sendToken(ackDestination);
                         lf = lf.makeNext(0);
                         lf.abortLoopIfTorpedoPresent();
@@ -84,7 +84,7 @@ public class Process {
                 case 1: {
                     if (dock.isInputDock()) {
                         torpedoes.add(dock);
-                        Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
+                        LoopFactory lf = new LoopFactory(ctx, dock, 1);
                         lf.sendToken(ackDestination);
 
                         // FIXME: this won't work right for ports that
@@ -106,7 +106,7 @@ public class Process {
                 case 2: {
                     if (!dock.isInputDock()) {
                         torpedoes.add(dock);
-                        Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
+                        LoopFactory lf = new LoopFactory(ctx, dock, 1);
                         if (peer != null)
                             for(int i=0; i<((InPort)peer).getTokensToAbsorb(); i++)
                                 lf.recvToken();
@@ -122,7 +122,7 @@ public class Process {
                         if (peerUsed && peer!=null) {
                             torpedoes.add(dock);
                         }
-                        Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
+                        LoopFactory lf = new LoopFactory(ctx, dock, 1);
                         lf.sendToken(ackDestination);
                         reset_count++;
                     }
@@ -171,9 +171,9 @@ public class Process {
             }
 
             /** this port's peer (an OutPort) invokes this to have "recvToken" or equivalent inserted */
-            public abstract void recvToken(Context.LoopFactory loopfactory_at_output_dock);
+            public abstract void recvToken(LoopFactory loopfactory_at_output_dock);
             /** this port's peer (an OutPort) invokes this to have "sendWord" or equivalent inserted */
-            public abstract void sendWord(Context.LoopFactory loopfactory_at_output_dock);
+            public abstract void sendWord(LoopFactory loopfactory_at_output_dock);
 
             public int getTokensToAbsorb() { return 0; }
         }
@@ -191,9 +191,9 @@ public class Process {
             }
 
             /** this port's peer (an InPort) invokes this to have "sendToken" or equivalent inserted */
-            public abstract void sendToken(Context.LoopFactory loopfactory_at_input_dock);
+            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(Context.LoopFactory loopfactory_at_input_dock);
+            public abstract void recvWord(LoopFactory loopfactory_at_input_dock);
         }
 
         public final class DockInPort extends InPort {
@@ -208,9 +208,9 @@ public class Process {
                 this.count = count;
                 this.pattern = pattern;
             }
-            public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
-            public void sendWord(Context.LoopFactory lf) { lf.sendWord(dock.getDataDestination()); }
-            public void build(Context ctx) { build(ctx, ctx.new LoopFactory(dock, 1)); }
+            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; }
@@ -223,7 +223,7 @@ public class Process {
             public void reset(Context ctx, int phase, Destination ackDestination) {
                 doReset(ctx, phase, dock, peer, ackDestination, peerUsed());
             }
-            protected void build(Context ctx, Context.LoopFactory lf) {
+            protected void build(Context ctx, LoopFactory lf) {
                 int inflight = (count != 0 && count < getInflight()) ? count : getInflight();
 
                 if (peer!=null)
@@ -260,10 +260,10 @@ public class Process {
             public final int count;
             public DockOutPort(String name, Dock dock) { this(name, dock, 0); }
             public DockOutPort(String name, Dock dock, int count) { super(name); this.dock = dock; this.count = count; }
-            public void sendToken(Context.LoopFactory lf) { lf.sendToken(dock.getDataDestination()); }
-            public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
-            public void build(Context ctx) { build(ctx, ctx.new LoopFactory(dock, 1)); }
-            protected void build(Context ctx, Context.LoopFactory lf) {
+            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) {
                 if (peer==null) return;
                 lf = lf.makeNext(count);
                 lf.abortLoopIfTorpedoPresent();
@@ -293,8 +293,8 @@ public class Process {
     public class ForeverModule extends Module {
         private BitVector bv;
         public final OutPort out = new OutPort("out") {
-                public void sendToken(Context.LoopFactory lf) { }
-                public void recvWord(Context.LoopFactory lf) { }
+                public void sendToken(LoopFactory lf) { }
+                public void recvWord(LoopFactory lf) { }
                 public void build(Context ctx) { }
                 public void reset(Context ctx, int phase, Destination ackDestination) { }
                 public void setPeer(InPort peer) {
@@ -313,8 +313,8 @@ public class Process {
     public class OnceModule extends Module {
         private BitVector bv;
         public final OutPort out = new OutPort("out") {
-                public void sendToken(Context.LoopFactory lf) { }
-                public void recvWord(Context.LoopFactory lf) { }
+                public void sendToken(LoopFactory lf) { }
+                public void recvWord(LoopFactory lf) { }
                 public void build(Context ctx) { }
                 public void reset(Context ctx, int phase, Destination ackDestination) { }
                 public void setPeer(InPort peer) {
@@ -427,8 +427,8 @@ public class Process {
             this.inAddrWrite  = new DockInPort("inAddrWrite", ship.getDock("inAddrWrite"));
             this.inDataWrite  = new DockInPort("inDataWrite", ship.getDock("inDataWrite"));
             this.inAddrRead1  = new InPort("inAddrRead1") {
-                    public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
-                    public void sendWord(Context.LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(0)); }
+                    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 int getTokensToAbsorb() { return outRead1.peer.getTokensToAbsorb(); }
                     public void reset(Context ctx, int phase, Destination ackDestination) {
@@ -436,26 +436,26 @@ public class Process {
                     }
                 };
             this.inAddrRead2  = new InPort("inAddrRead2") {
-                    public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
-                    public void sendWord(Context.LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(1)); }
+                    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 int getTokensToAbsorb() { return outRead2.peer.getTokensToAbsorb(); }
                     public void reset(Context ctx, int phase, Destination ackDestination) { }
                 };
             this.outRead1 = new OutPort("outRead1") {
-                    public void sendToken(Context.LoopFactory lf) { inAddrRead1.peer.sendToken(lf); }
-                    public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
+                    public void sendToken(LoopFactory lf) { inAddrRead1.peer.sendToken(lf); }
+                    public void recvWord(LoopFactory lf) { lf.recvWord(); }
                     public void build(Context ctx) { }
                     public void reset(Context ctx, int phase, Destination ackDestination) { }
                 };
             this.outRead2 = new OutPort("outRead2") {
-                    public void sendToken(Context.LoopFactory lf) { inAddrRead2.peer.sendToken(lf); }
-                    public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
+                    public void sendToken(LoopFactory lf) { inAddrRead2.peer.sendToken(lf); }
+                    public void recvWord(LoopFactory lf) { lf.recvWord(); }
                     public void build(Context ctx) { }
                     public void reset(Context ctx, int phase, Destination ackDestination) { }
                 };
             this.outWrite = new DockOutPort("out", ship.getDock("out")) {
-                    protected void build(Context ctx, Context.LoopFactory lf) {
+                    protected void build(Context ctx, LoopFactory lf) {
                         lf = lf.makeNext(0);
                         lf.abortLoopIfTorpedoPresent();
                         lf.collectWord();
@@ -487,9 +487,9 @@ public class Process {
         }
         public void build(Context ctx) {
             super.build(ctx);
-            Context.LoopFactory lf;
+            LoopFactory lf;
 
-            lf = ctx.new LoopFactory(ship.getDock("inAddrRead"), 0);
+            lf = new LoopFactory(ctx, ship.getDock("inAddrRead"), 0);
             lf.abortLoopIfTorpedoPresent();
             lf.recvWord();
             lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
@@ -562,10 +562,10 @@ public class Process {
         Dock debugIn = debug.getDock("in");
 
         Context ctx;
-        Context.LoopFactory lf;
+        LoopFactory lf;
 
         ctx = new Context(fp.getFleet());
-        lf = ctx.new LoopFactory(debugIn, 1);
+        lf = new LoopFactory(ctx, debugIn, 1);
         lf.literal(12);
         lf.deliver();
         lf.literal(5);
@@ -588,7 +588,7 @@ public class Process {
 
                     boolean reverse = (k%2)==0;
 
-                    lf = ctx.new LoopFactory(debugIn, 4);
+                    lf = new LoopFactory(ctx, debugIn, 4);
                     lf.recvToken();
                     lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
                     lf.setPredicate(Predicate.NotFlagA);
@@ -598,7 +598,7 @@ public class Process {
                     lf.setPredicate(null);
                     lf.deliver();
 
-                    lf = ctx.new LoopFactory(dock, 1);
+                    lf = new LoopFactory(ctx, dock, 1);
                     lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(reverse ? 1 : 0));
                     lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(reverse ? 0 : 1));
                     lf.sendToken(dock.getDataDestination(), new BitVector(1).set(reverse ? 1 : 0));
@@ -723,7 +723,7 @@ public class Process {
         fp.sendToken(debugIn.getInstructionDestination());
         fp.flush();
 
-        Context.LoopFactory lf = ctx2.new LoopFactory(debugIn, 0);
+        LoopFactory lf = new LoopFactory(ctx2, debugIn, 0);
         lf.literal(0);
         lf.abortLoopIfTorpedoPresent();
         lf.recvToken();
@@ -744,21 +744,21 @@ public class Process {
             proc.reset(ctx2, phase, ackDestination);
 
             Context ctx3 = new Context(fp.getFleet());
-            lf = ctx3.new LoopFactory(counter.getDock("inOp"), 1);
+            lf = new LoopFactory(ctx3, counter.getDock("inOp"), 1);
             lf.literal(9);
             lf.deliver();
             lf.literal(5);
             lf.deliver();
-            lf = ctx3.new LoopFactory(counter.getDock("in1"), 1);
+            lf = new LoopFactory(ctx3, counter.getDock("in1"), 1);
             lf.literal(reset_count-1);
             lf.deliver();
             lf.literal(1);
             lf.deliver();
-            lf = ctx3.new LoopFactory(counter.getDock("in2"), 0);
+            lf = new LoopFactory(ctx3, counter.getDock("in2"), 0);
             lf.abortLoopIfTorpedoPresent();
             lf.recvWord();
             lf.deliver();
-            lf = ctx3.new LoopFactory(counter.getDock("out"), 1);
+            lf = new LoopFactory(ctx3, 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());
index 5fd0851..7db5290 100644 (file)
@@ -40,378 +40,22 @@ import static edu.berkeley.fleet.util.BitManipulations.*;
  *        - after executing these remaining instructions, the dock's hatch is open
  */
 public class Context {
-    private HashMap<Dock,LoopFactory> startupLoopFactories = new HashMap<Dock,LoopFactory>();
-    private HashSet<LoopFactory> loopFactories = new HashSet<LoopFactory>();
 
     public final Fleet fleet;
-    public Context(Fleet fleet) { this.fleet = fleet; }
 
-    private boolean autoflush = false;
-    public void setAutoflush(boolean a) { this.autoflush = a; }
-
-    // FIXME: ability for a group of Contexts to share an "allocation
-    // pool" because they will run concurrently.
-    public HashSet<Ship>             allocatedShips       = new HashSet<Ship>();
+    HashMap<Dock,LoopFactory> startupLoopFactories = new HashMap<Dock,LoopFactory>();
+    HashSet<LoopFactory> loopFactories = new HashSet<LoopFactory>();
 
-    public Ship allocateShip(String name) {
-        for(int i=0; ; i++) {
-            Ship ship = fleet.getShip(name, i);
-            if (ship==null)
-                throw new RuntimeException("no more ships of type " + name);
-            if (allocatedShips.contains(ship)) continue;
-            allocatedShips.add(ship);
-            return ship;
-        }
+    private final ShipPool pool;
+    public Context(Fleet fleet) { this(fleet, new ShipPool(fleet)); }
+    public Context(Fleet fleet, ShipPool pool) {
+        this.fleet = fleet;
+        this.pool = pool;
     }
+    public Ship allocateShip(String type) { return pool.allocateShip(type); }
 
-    // FIXME: is it legitimate to send a torpedo to a count==1 loop?
-    // FIXME: is it legitimate to send a torpedo to a count>1  loop?
-    /**
-     *
-     *  A helper class for building loops of instructions.
-     *
-     *  This class abstracts away:
-     *    - The maximum size of a loop
-     *    - The maximum length of a "one shot" instruction sequence
-     *    - The looping/oneshot bit
-     *    - The outer loop counter
-     *    - The inner loop counter (opportunities to use it are auto-detected)
-     *
-     *  It also performs various optimizations and provides a more
-     *  convenient way of managing the predicate/interruptible fields.
-     *
-     *  To get the most compact coding, the components of a Move should be
-     *  performed in this order when possible, with no intervening commands:
-     *
-     *    1. recvToken()
-     *    2. recv()/collect()
-     *    3. sendToken()
-     *    4. deliver()/send()
-     *
-     */
-    public class LoopFactory {
-
-        // FIXME: vet this to see if it is sensible
-        private boolean instructionFifoSizeCheckDisabled = false;
-        public void disableInstructionFifoOverflowCheck() { instructionFifoSizeCheckDisabled = true; }
-
-        public final Dock dock;
-        public final String friendlyName;
-        public final int count;
-        private Predicate predicate = Predicate.Default;
-        private LoopFactory next = null;
-        private ArrayList<Instruction> instructions = new ArrayList<Instruction>();
-
-        /**
-         *  Creates a new loop.
-         *   @arg dock         the dock at which to execute the instructions
-         *   @arg friendlyName a descriptive string for debugging the compiler
-         *   @arg prev         a loop for which this is the successor loop (if any)
-         *   @arg count        the number of times to execute this loop; <tt>0</tt> means continue until torpedoed
-         */
-        public LoopFactory(Dock dock, int count) { this(dock, count, dock.toString(), null); }
-        public LoopFactory(Dock dock, int count, String friendlyName) { this(dock, count, friendlyName, null); }
-        private LoopFactory(Dock dock, int count, String friendlyName, LoopFactory prev) {
-            this.dock = dock;
-            this.count = count;
-            this.friendlyName = friendlyName;
-            Context.this.loopFactories.add(this);
-            if (Context.this.startupLoopFactories.get(dock) == null)
-                Context.this.startupLoopFactories.put(dock, this);
-            if (prev != null) {
-                if (prev.getNext() != null) throw new RuntimeException();
-                prev.setNext(this);
-            }
-        }
-
-        public LoopFactory makeNext(int new_count) { return makeNext(new_count, null); }
-        public LoopFactory makeNext(int new_count, String newFriendlyName) {
-            if (next != null) throw new RuntimeException("loop already has a successor");
-            return new LoopFactory(dock, new_count, newFriendlyName, this);
-        }
-        public LoopFactory getNext() { return next; }
-        private void setNext(LoopFactory next) {
-            if (this.next != null) throw new RuntimeException("attempt to setNext() twice");
-            this.next = next;
-        }
-
-
-        // Building Loops //////////////////////////////////////////////////////////////////////////////
-
-        boolean     pending_interruptible = false;
-        boolean     pending_recvToken = false;
-        boolean     pending_recvOrCollect = false;
-        boolean     pending_latchData = false;
-        boolean     pending_latchPath = false;
-        boolean     pending_sendToken = false;
-        Path        pending_path = null;
-
-        void flush_pending() { flush_pending(false); }
-        void flush_pending(boolean pending_dataOut) {
-            if (!pending_recvToken &&
-                !pending_recvOrCollect &&
-                !pending_sendToken &&
-                !pending_dataOut) {
-                if (pending_interruptible)
-                    throw new RuntimeException("abortLoopIfTorpedoPresent() must be followed immediately by a Move");
-            } else {
-                instructions.add(new Move(dock,
-                                          count!=1,
-                                          predicate,
-                                          pending_interruptible,
-                                          pending_path==null ? null : pending_path,
-                                          pending_recvToken,
-                                          pending_recvOrCollect,
-                                          pending_latchData,
-                                          pending_latchPath,
-                                          pending_dataOut,
-                                          pending_sendToken));
-            }
-            pending_interruptible = false;
-            pending_recvToken = false;
-            pending_recvOrCollect = false;
-            pending_latchData = false;
-            pending_latchPath = false;
-            pending_sendToken = false;
-            pending_path = null;
-        }
-
-        public void interruptibleNop() {
-            flush_pending();
-            instructions.add(new Move(dock,
-                                      count!=1,
-                                      predicate,
-                                      true,
-                                      null,
-                                      false,
-                                      false,
-                                      false,
-                                      false,
-                                      false,
-                                      false));
-        }
-
-        /** sets the predicate which will be applied to subsequent instructions, or null for the default predicate */
-        public void setPredicate(Predicate p) {
-            if (p==null) p = Predicate.Default;
-            if (predicate==p) return;
-            flush_pending();
-            predicate = p;
-        }
-
-        /** must be followed immediately by a move-based instruction */
-        public void abortLoopIfTorpedoPresent() {
-            flush_pending();
-            //if (count!=0) throw new RuntimeException("currently, only forever-loops may be sensitive to torpedoes");
-            pending_interruptible = true;
-        }
-
-        /** [either] */
-        public void recvToken() {
-            if (pending_recvToken || pending_recvOrCollect || pending_sendToken) flush_pending();
-            pending_recvToken = true;
-        }
-
-        /** [inboxes only] */
-        public void recv(boolean latchData, boolean latchPath) {
-            if (!dock.isInputDock()) throw new RuntimeException("recv() may only be used at input docks");
-            if (pending_recvOrCollect || pending_sendToken) flush_pending();
-            pending_recvOrCollect = true;
-            pending_latchData = latchData;
-            pending_latchPath = latchPath;
-        }
-
-        /** [outboxes only], will fuse with previous instruction if it was a recvToken() */
-        public void collect(boolean latchData, boolean latchPath) {
-            if (!dock.isOutputDock()) throw new RuntimeException("collect() may only be used at output docks");
-            if (pending_recvOrCollect || pending_sendToken) flush_pending();
-            pending_recvOrCollect = true;
-            pending_latchData = latchData;
-            pending_latchPath = latchPath;
-        }
-
-        /** [either], will fuse with previous instruction if it was a recvToken(), recv(), or collect() */
-        public void sendToken(Destination dest) { sendToken(dest, null); }
-        public void sendToken(Destination dest, BitVector signal) {
-            if (pending_sendToken) flush_pending();
-            pending_path = dock.getPath(dest, signal);
-            pending_sendToken = true;
-        }
-
-        /** [inboxes only], will fuse with previous instruction if it was a sendToken() */
-        public void deliver() {
-            if (!dock.isInputDock()) throw new RuntimeException("deliver() may only be used at input docks");
-            flush_pending(true);
-        }
-
-        /** [inboxes only], will fuse with previous instruction if it was a sendToken() */
-        public void flush() {
-            if (!dock.isInputDock()) throw new RuntimeException("flush() may only be used at input docks");
-            flush_pending();
-            instructions.add(new Instruction.Flush(dock, count!=1, predicate));
-        }
-
-        /** [outboxes only], will fuse with previous instruction if it was a sendToken() */
-        public void sendWord(Destination dest) { sendWord(dest, null); }
-        public void sendWord(Destination dest, BitVector signal) {
-            if (!dock.isOutputDock()) throw new RuntimeException("sendWord() may only be used at output docks");
-            if (pending_sendToken) flush_pending();
-            pending_path = dock.getPath(dest, signal);
-            flush_pending(true);
-        }
-
-        /** sets the data latch to a literal value */
-        public void literal(BitVector literal) {
-            // FIXME: code duplication here
-            // FIXME: be more intelligent here to avoid shifts if possible?
-            int counter = 0;
-            while(counter < dock.getShip().getFleet().getWordWidth()) counter += fleet.getShiftWidth();
-            while(counter > 0) {
-                BitVector temp = new BitVector(dock.getShip().getFleet().getShiftWidth());
-                for(int i=counter-1; i>=counter-fleet.getShiftWidth(); i--)
-                    if (i<literal.length())
-                        temp.set(i-(counter-fleet.getShiftWidth()), literal.get(i));
-                instructions.add(new Shift(dock, count!=1, predicate, temp));
-                counter -= fleet.getShiftWidth();
-            }
-        }
-
-        /** sets the data latch to a literal value */
-        public void literal(long literal) {
-            flush_pending();
-            if (((FleetTwoFleet)fleet).isSmallEnoughToFit(literal)) {
-                instructions.add(new Instruction.Set(dock, count!=1, predicate, SetDest.DataLatch, literal));
-            } else {
-                int counter = 0;
-                int extra = 0;
-                while(counter < dock.getShip().getFleet().getWordWidth()) { extra++; counter += fleet.getShiftWidth(); }
-                warn("literal " + literal + " requires " + extra + " instructions");
-                while(counter > 0) {
-                    instructions.add(new Shift(dock, count!=1, predicate,
-                                               new BitVector(dock.getShip().getFleet().getWordWidth())
-                                               .set(getField(counter-1, counter-fleet.getShiftWidth(), literal))));
-                    counter -= fleet.getShiftWidth();
-                }
-            }
-        }
-
-        /** sets the flags */
-        public void setFlags(Instruction.Set.FlagFunction newFlagA, Instruction.Set.FlagFunction newFlagB) {
-            flush_pending();
-            instructions.add(new Instruction.Set(dock,
-                                                 count!=1,
-                                                 predicate,
-                                                 newFlagA,
-                                                 newFlagB));
-        }
-
-        // FIXME: what if we're using an ILC-loop?
-        /** abort the loop immediately (if predicate is met) and invoke the successor loop */
-        public void abort() {
-            flush_pending();
-            instructions.add(new Instruction.Set(dock,
-                                                 count!=1,
-                                                 predicate,
-                                                 SetDest.OuterLoopCounter,
-                                                 0));
-        }
-
-        public void abortAndInvoke(LoopFactory lf) {
-            throw new RuntimeException("not implemented");
-        }
-
-        // Emitting Code //////////////////////////////////////////////////////////////////////////////
-
-        void optimize() {
-            flush_pending();
-            // FEATURE: find loops of 1 instruction, use ILC
-            // FEATURE: find sequences of >2 adjacent identical instructions, replace with use of ILC
-            // FEATURE: after optimizing, find single-instruction loops, replace with use of ILC
-            // FEATURE: consider doing loop unrolling if two copies of the loop fit in the instruction buffer...
-            // FEATURE: clever instruction re-oredering?
-        }
-
-        /**
-         *  The code emitted by this method makes the following assumptions:
-         *
-         *   - The instructions emitted are dispatched in order
-         *   - At the time of dispatch, the dock must be pre-quiescent.
-         *
-         */
-        public void emit(ArrayList<Instruction> ic) {
-            flush_pending();
-            optimize();
-
-            // FIXME: if this loop is a count==1 loop, we can emit the successor loop along with it...
-
-            // the number of instructions after and including the first blocking instruction
-            int numInstructionsNotIncludingNonblockingPrefix = 0;
-            int loopSize = 0;
-            boolean blockingInstructionEncountered = false;
-
-            // Set the OLC (it might previously have been zero)
-            ic.add(new Set(dock, false, Predicate.IgnoreFlagD, SetDest.OuterLoopCounter, count==0 ? 1 : count));
-            if (count!=1) {
-                ic.add(new Instruction.Head(dock));
-            }
-
-            for(Instruction i : instructions) {
-                if (i instanceof Move && (((Move)i).tokenIn || ((Move)i).dataIn))
-                    blockingInstructionEncountered = true;
-                if (blockingInstructionEncountered)
-                    numInstructionsNotIncludingNonblockingPrefix++;
-                loopSize++;
-                ic.add(i);
-            }
-
-            if (count==1) {
-                if (!instructionFifoSizeCheckDisabled &&
-                    numInstructionsNotIncludingNonblockingPrefix > dock.getInstructionFifoSize())
-                    throw new RuntimeException("instruction sequence is too long for instruction fifo at " + dock);
-            } else {
-                if (count != 0) {
-                    ic.add(new Instruction.Set(dock, true, Predicate.Default, SetDest.OuterLoopCounter, SetSource.Decrement));
-                    if (blockingInstructionEncountered)
-                        numInstructionsNotIncludingNonblockingPrefix++;
-                    loopSize++;
-                }
-            }
-            if (count!=1) {
-                ic.add(new Instruction.Abort(dock, Predicate.FlagD));
-            }
-            if (autoflush && !"Debug".equals(dock.getShip().getType()) && next==null) {
-                if (dock.isInputDock())
-                    ic.add(new Instruction.Flush(dock, true, Predicate.FlagD));
-            }
-            if (count!=1) {
-                ic.add(new Instruction.Tail(dock));
-                if (!instructionFifoSizeCheckDisabled &&
-                    loopSize > dock.getInstructionFifoSize())
-                    throw new RuntimeException("instruction loop is too long for instruction fifo");
-            }
-
-            if (next != null) {
-                if (count != 1) throw new RuntimeException("no support for successor loops when count!=1 yet");
-                // FIXME: must include check based on reduced FIFO capacity
-                // FIXME: review this
-                next.emit(ic);
-            }
-        }
-
-        void warn(String warning) {
-            System.err.println("warning: " + warning);
-        }
-
-        // Helpers //////////////////////////////////////////////////////////////////////////////
-
-        public void recvWord() { recv(true, false); }
-        public void recvPath() { recv(false, true); }
-        public void recvPacket() { recv(true, true); }
-        public void collectWord() { collect(true, false); }
-        public void collectPath() { collect(false, true); }
-        public void collectPacket() { collect(true, true); }
-
-    }
+    boolean autoflush = false;
+    public void setAutoflush(boolean a) { this.autoflush = a; }
 
     public void emit(ArrayList<Instruction> ic) {
         for(LoopFactory lf : startupLoopFactories.values())
diff --git a/src/edu/berkeley/fleet/loops/LoopFactory.java b/src/edu/berkeley/fleet/loops/LoopFactory.java
new file mode 100644 (file)
index 0000000..7d5649c
--- /dev/null
@@ -0,0 +1,365 @@
+package edu.berkeley.fleet.loops;
+import java.util.*;
+import java.net.*;
+import edu.berkeley.fleet.two.*;
+import edu.berkeley.fleet.api.*;
+import edu.berkeley.fleet.api.Instruction.*;
+import edu.berkeley.fleet.api.Instruction.Set;
+import edu.berkeley.fleet.api.Instruction.Set.*;
+import static edu.berkeley.fleet.util.BitManipulations.*;
+
+// FIXME: is it legitimate to send a torpedo to a count==1 loop?
+// FIXME: is it legitimate to send a torpedo to a count>1  loop?
+/**
+ *
+ *  A helper class for building loops of instructions.
+ *
+ *  This class abstracts away:
+ *    - The maximum size of a loop
+ *    - The maximum length of a "one shot" instruction sequence
+ *    - The looping/oneshot bit
+ *    - The outer loop counter
+ *    - The inner loop counter (opportunities to use it are auto-detected)
+ *
+ *  It also performs various optimizations and provides a more
+ *  convenient way of managing the predicate/interruptible fields.
+ *
+ *  To get the most compact coding, the components of a Move should be
+ *  performed in this order when possible, with no intervening commands:
+ *
+ *    1. recvToken()
+ *    2. recv()/collect()
+ *    3. sendToken()
+ *    4. deliver()/send()
+ *
+ */
+public class LoopFactory {
+
+    // FIXME: vet this to see if it is sensible
+    private boolean instructionFifoSizeCheckDisabled = false;
+    public void disableInstructionFifoOverflowCheck() { instructionFifoSizeCheckDisabled = true; }
+
+    public final Dock dock;
+    public final String friendlyName;
+    public final int count;
+
+    private final Context ctx;
+    private Predicate predicate = Predicate.Default;
+    private LoopFactory next = null;
+    private ArrayList<Instruction> instructions = new ArrayList<Instruction>();
+
+    /**
+     *  Creates a new loop.
+     *   @arg dock         the dock at which to execute the instructions
+     *   @arg friendlyName a descriptive string for debugging the compiler
+     *   @arg prev         a loop for which this is the successor loop (if any)
+     *   @arg count        the number of times to execute this loop; <tt>0</tt> means continue until torpedoed
+     */
+    public LoopFactory(Context ctx, Dock dock, int count) {
+        this(ctx, dock, count, dock.toString(), null);
+    }
+    public LoopFactory(Context ctx, Dock dock, int count, String friendlyName) {
+        this(ctx, dock, count, friendlyName, null);
+    }
+    private LoopFactory(Context ctx, Dock dock, int count, String friendlyName, LoopFactory prev) {
+        this.ctx = ctx;
+        this.dock = dock;
+        this.count = count;
+        this.friendlyName = friendlyName;
+        ctx.loopFactories.add(this);
+        if (ctx.startupLoopFactories.get(dock) == null)
+            ctx.startupLoopFactories.put(dock, this);
+        if (prev != null) {
+            if (prev.getNext() != null) throw new RuntimeException();
+            prev.setNext(this);
+        }
+    }
+
+    public LoopFactory makeNext(int new_count) { return makeNext(new_count, null); }
+    public LoopFactory makeNext(int new_count, String newFriendlyName) {
+        if (next != null) throw new RuntimeException("loop already has a successor");
+        return new LoopFactory(ctx, dock, new_count, newFriendlyName, this);
+    }
+    public LoopFactory getNext() { return next; }
+    private void setNext(LoopFactory next) {
+        if (this.next != null) throw new RuntimeException("attempt to setNext() twice");
+        this.next = next;
+    }
+
+
+    // Building Loops //////////////////////////////////////////////////////////////////////////////
+
+    boolean     pending_interruptible = false;
+    boolean     pending_recvToken = false;
+    boolean     pending_recvOrCollect = false;
+    boolean     pending_latchData = false;
+    boolean     pending_latchPath = false;
+    boolean     pending_sendToken = false;
+    Path        pending_path = null;
+
+    void flush_pending() { flush_pending(false); }
+    void flush_pending(boolean pending_dataOut) {
+        if (!pending_recvToken &&
+            !pending_recvOrCollect &&
+            !pending_sendToken &&
+            !pending_dataOut) {
+            if (pending_interruptible)
+                throw new RuntimeException("abortLoopIfTorpedoPresent() must be followed immediately by a Move");
+        } else {
+            instructions.add(new Move(dock,
+                                      count!=1,
+                                      predicate,
+                                      pending_interruptible,
+                                      pending_path==null ? null : pending_path,
+                                      pending_recvToken,
+                                      pending_recvOrCollect,
+                                      pending_latchData,
+                                      pending_latchPath,
+                                      pending_dataOut,
+                                      pending_sendToken));
+        }
+        pending_interruptible = false;
+        pending_recvToken = false;
+        pending_recvOrCollect = false;
+        pending_latchData = false;
+        pending_latchPath = false;
+        pending_sendToken = false;
+        pending_path = null;
+    }
+
+    public void interruptibleNop() {
+        flush_pending();
+        instructions.add(new Move(dock,
+                                  count!=1,
+                                  predicate,
+                                  true,
+                                  null,
+                                  false,
+                                  false,
+                                  false,
+                                  false,
+                                  false,
+                                  false));
+    }
+
+    /** sets the predicate which will be applied to subsequent instructions, or null for the default predicate */
+    public void setPredicate(Predicate p) {
+        if (p==null) p = Predicate.Default;
+        if (predicate==p) return;
+        flush_pending();
+        predicate = p;
+    }
+
+    /** must be followed immediately by a move-based instruction */
+    public void abortLoopIfTorpedoPresent() {
+        flush_pending();
+        //if (count!=0) throw new RuntimeException("currently, only forever-loops may be sensitive to torpedoes");
+        pending_interruptible = true;
+    }
+
+    /** [either] */
+    public void recvToken() {
+        if (pending_recvToken || pending_recvOrCollect || pending_sendToken) flush_pending();
+        pending_recvToken = true;
+    }
+
+    /** [inboxes only] */
+    public void recv(boolean latchData, boolean latchPath) {
+        if (!dock.isInputDock()) throw new RuntimeException("recv() may only be used at input docks");
+        if (pending_recvOrCollect || pending_sendToken) flush_pending();
+        pending_recvOrCollect = true;
+        pending_latchData = latchData;
+        pending_latchPath = latchPath;
+    }
+
+    /** [outboxes only], will fuse with previous instruction if it was a recvToken() */
+    public void collect(boolean latchData, boolean latchPath) {
+        if (!dock.isOutputDock()) throw new RuntimeException("collect() may only be used at output docks");
+        if (pending_recvOrCollect || pending_sendToken) flush_pending();
+        pending_recvOrCollect = true;
+        pending_latchData = latchData;
+        pending_latchPath = latchPath;
+    }
+
+    /** [either], will fuse with previous instruction if it was a recvToken(), recv(), or collect() */
+    public void sendToken(Destination dest) { sendToken(dest, null); }
+    public void sendToken(Destination dest, BitVector signal) {
+        if (pending_sendToken) flush_pending();
+        pending_path = dock.getPath(dest, signal);
+        pending_sendToken = true;
+    }
+
+    /** [inboxes only], will fuse with previous instruction if it was a sendToken() */
+    public void deliver() {
+        if (!dock.isInputDock()) throw new RuntimeException("deliver() may only be used at input docks");
+        flush_pending(true);
+    }
+
+    /** [inboxes only], will fuse with previous instruction if it was a sendToken() */
+    public void flush() {
+        if (!dock.isInputDock()) throw new RuntimeException("flush() may only be used at input docks");
+        flush_pending();
+        instructions.add(new Instruction.Flush(dock, count!=1, predicate));
+    }
+
+    /** [outboxes only], will fuse with previous instruction if it was a sendToken() */
+    public void sendWord(Destination dest) { sendWord(dest, null); }
+    public void sendWord(Destination dest, BitVector signal) {
+        if (!dock.isOutputDock()) throw new RuntimeException("sendWord() may only be used at output docks");
+        if (pending_sendToken) flush_pending();
+        pending_path = dock.getPath(dest, signal);
+        flush_pending(true);
+    }
+
+    /** sets the data latch to a literal value */
+    public void literal(BitVector literal) {
+        // FIXME: code duplication here
+        // FIXME: be more intelligent here to avoid shifts if possible?
+        int counter = 0;
+        while(counter < dock.getShip().getFleet().getWordWidth()) counter += ctx.fleet.getShiftWidth();
+        while(counter > 0) {
+            BitVector temp = new BitVector(dock.getShip().getFleet().getShiftWidth());
+            for(int i=counter-1; i>=counter-ctx.fleet.getShiftWidth(); i--)
+                if (i<literal.length())
+                    temp.set(i-(counter-ctx.fleet.getShiftWidth()), literal.get(i));
+            instructions.add(new Shift(dock, count!=1, predicate, temp));
+            counter -= ctx.fleet.getShiftWidth();
+        }
+    }
+
+    /** sets the data latch to a literal value */
+    public void literal(long literal) {
+        flush_pending();
+        if (((FleetTwoFleet)ctx.fleet).isSmallEnoughToFit(literal)) {
+            instructions.add(new Instruction.Set(dock, count!=1, predicate, SetDest.DataLatch, literal));
+        } else {
+            int counter = 0;
+            int extra = 0;
+            while(counter < dock.getShip().getFleet().getWordWidth()) { extra++; counter += ctx.fleet.getShiftWidth(); }
+            warn("literal " + literal + " requires " + extra + " instructions");
+            while(counter > 0) {
+                instructions.add(new Shift(dock, count!=1, predicate,
+                                           new BitVector(dock.getShip().getFleet().getWordWidth())
+                                           .set(getField(counter-1, counter-ctx.fleet.getShiftWidth(), literal))));
+                counter -= ctx.fleet.getShiftWidth();
+            }
+        }
+    }
+
+    /** sets the flags */
+    public void setFlags(Instruction.Set.FlagFunction newFlagA, Instruction.Set.FlagFunction newFlagB) {
+        flush_pending();
+        instructions.add(new Instruction.Set(dock,
+                                             count!=1,
+                                             predicate,
+                                             newFlagA,
+                                             newFlagB));
+    }
+
+    // FIXME: what if we're using an ILC-loop?
+    /** abort the loop immediately (if predicate is met) and invoke the successor loop */
+    public void abort() {
+        flush_pending();
+        instructions.add(new Instruction.Set(dock,
+                                             count!=1,
+                                             predicate,
+                                             SetDest.OuterLoopCounter,
+                                             0));
+    }
+
+    public void abortAndInvoke(LoopFactory lf) {
+        throw new RuntimeException("not implemented");
+    }
+
+    // Emitting Code //////////////////////////////////////////////////////////////////////////////
+
+    void optimize() {
+        flush_pending();
+        // FEATURE: find loops of 1 instruction, use ILC
+        // FEATURE: find sequences of >2 adjacent identical instructions, replace with use of ILC
+        // FEATURE: after optimizing, find single-instruction loops, replace with use of ILC
+        // FEATURE: consider doing loop unrolling if two copies of the loop fit in the instruction buffer...
+        // FEATURE: clever instruction re-oredering?
+    }
+
+    /**
+     *  The code emitted by this method makes the following assumptions:
+     *
+     *   - The instructions emitted are dispatched in order
+     *   - At the time of dispatch, the dock must be pre-quiescent.
+     *
+     */
+    public void emit(ArrayList<Instruction> ic) {
+        flush_pending();
+        optimize();
+
+        // FIXME: if this loop is a count==1 loop, we can emit the successor loop along with it...
+
+        // the number of instructions after and including the first blocking instruction
+        int numInstructionsNotIncludingNonblockingPrefix = 0;
+        int loopSize = 0;
+        boolean blockingInstructionEncountered = false;
+
+        // Set the OLC (it might previously have been zero)
+        ic.add(new Set(dock, false, Predicate.IgnoreFlagD, SetDest.OuterLoopCounter, count==0 ? 1 : count));
+        if (count!=1) {
+            ic.add(new Instruction.Head(dock));
+        }
+
+        for(Instruction i : instructions) {
+            if (i instanceof Move && (((Move)i).tokenIn || ((Move)i).dataIn))
+                blockingInstructionEncountered = true;
+            if (blockingInstructionEncountered)
+                numInstructionsNotIncludingNonblockingPrefix++;
+            loopSize++;
+            ic.add(i);
+        }
+
+        if (count==1) {
+            if (!instructionFifoSizeCheckDisabled &&
+                numInstructionsNotIncludingNonblockingPrefix > dock.getInstructionFifoSize())
+                throw new RuntimeException("instruction sequence is too long for instruction fifo at " + dock);
+        } else {
+            if (count != 0) {
+                ic.add(new Instruction.Set(dock, true, Predicate.Default, SetDest.OuterLoopCounter, SetSource.Decrement));
+                if (blockingInstructionEncountered)
+                    numInstructionsNotIncludingNonblockingPrefix++;
+                loopSize++;
+            }
+        }
+        if (count!=1) {
+            ic.add(new Instruction.Abort(dock, Predicate.FlagD));
+        }
+        if (ctx.autoflush && !"Debug".equals(dock.getShip().getType()) && next==null) {
+            if (dock.isInputDock())
+                ic.add(new Instruction.Flush(dock, true, Predicate.FlagD));
+        }
+        if (count!=1) {
+            ic.add(new Instruction.Tail(dock));
+            if (!instructionFifoSizeCheckDisabled &&
+                loopSize > dock.getInstructionFifoSize())
+                throw new RuntimeException("instruction loop is too long for instruction fifo");
+        }
+
+        if (next != null) {
+            if (count != 1) throw new RuntimeException("no support for successor loops when count!=1 yet");
+            // FIXME: must include check based on reduced FIFO capacity
+            // FIXME: review this
+            next.emit(ic);
+        }
+    }
+
+    void warn(String warning) {
+        System.err.println("warning: " + warning);
+    }
+
+    // Helpers //////////////////////////////////////////////////////////////////////////////
+
+    public void recvWord() { recv(true, false); }
+    public void recvPath() { recv(false, true); }
+    public void recvPacket() { recv(true, true); }
+    public void collectWord() { collect(true, false); }
+    public void collectPath() { collect(false, true); }
+    public void collectPacket() { collect(true, true); }
+
+}