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;
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);
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);
// 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 //////////////////////////////////////////////////////////////////////////////
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);
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();
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;
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();
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();
// 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);
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);
// 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();
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();
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.*;
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();
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();
}
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();
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
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();
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++;
}
}
/** 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; }
}
}
/** 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 {
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; }
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)
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();
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) {
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) {
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) {
}
};
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();
}
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);
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);
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);
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));
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();
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());
* - 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())
--- /dev/null
+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); }
+
+}