package edu.berkeley.fleet.loops;
-import edu.berkeley.fleet.api.*;
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.*;
+
+
+// QUESTION: does each dock mentioned by a context have a linear chain
+// of loops, or can it branch?
+
+// - or should we use "sub-contexts" for that
+// - advantage: it lets us convey the fact that a bunch of loops are dispatched together
+// - should loops have an "invoke context" opcode?
/**
- * A CodeBag represents the instructions of a Context along with
- * (compile-time) knowledge of where it resides. Consequently, it is
- * meaningful to say "give me the sequence of instructions which will
- * invoke this CodeBag".
+ * A CodeBag is a collection of Loops which obey these rules:
+ *
+ * - A CodeBag has exclusive control of all docks mentioned by any of its Loops.
+ * - A CodeBag includes a "starting loop" for every dock it mentions.
+ * - When a CodeBag is spawned, it starts the "starting loop" on all of its docks.
+ * - A loop may or may not have a successor.
+ * - Control may transfer only two ways:
+ * - If a loop has a successor, control will transfer to the successor when the loop finishes.
+ * - A loop may explicitly transfer control to another loop via abortAndInvoke(). The
+ * invoked loop must belong to the same Dock and the same CodeBag.
+ * - A CodeBag finishes when all of its docks have finished executing a loop with no successor.
+ *
+ * Definitions:
+ * - A Move instruction is a blocking instruction if either its tokenIn or dataIn bits are set.
+ * - All other instructions are non-blocking.
+ * - A dock is quiescent if its instruction ring is empty.
+ * - A dock is pre-quiescent if
+ * - all instructions which remain in the target dock's instruction
+ * fifo are nonblocking instructions,
+ * - either the docks' OLC=0 or all instructions which remain
+ * in its instruction fifo are one-shot instructions
+ * - after executing these remaining instructions, the dock's hatch is open
+ */
+
+/*
+ * SF works works @diff ok for non size ships
+ * Dispatch Method Crossings @inbox? docks? tail call? limit consumed
+ * ------------------------------------------------------------------------------------------
+ *
+ * Inline 0 Y N N Small None
+ *
+ * Inline literals 1 N Y Y Tiny None
+ * w/ "dispatch"
+ *
+ * Send CBD to 2+ N Y Y None None (mem ship)
+ * memory ship
+ *
+ * Send token to 3+ Y Y Y None One Output Dock
+ * assistant outbox first
+ *
+ * Release from FIFO 2 Y Y Y Med 1x FIFO, but can be shared
+ *
*/
+
public class CodeBag {
- /*
- * SF works works @diff ok for non size ships
- * Dispatch Method Crossings @inbox? docks? tail call? limit consumed
- * ------------------------------------------------------------------------------------------
- *
- * Inline 0 Y N N Small None
- *
- * Inline literals 1 N Y Y Tiny None
- * w/ "dispatch"
- *
- * Send CBD to 2+ N Y Y None None (mem ship)
- * memory ship
- *
- * Send token to 3+ Y Y Y None One Output Dock
- * assistant outbox first
- *
- * Release from FIFO 2 Y Y Y Med 1x FIFO, but can be shared
- *
- */
-
- final Program program;
- final Instruction[] instructions;
- final long baseAddress;
-
- /**
- * Given a Context, creates a CodeBag which will live in the
- * Memory ship memoryShip at the address given by baseAddress.
- */
- CodeBag(Program program, Instruction[] instructions, long baseAddress) {
- int MAX_BAG_SIZE = (1<<7)-1;
- if (instructions.length > MAX_BAG_SIZE)
- throw new RuntimeException("warning: code bag size is "+instructions.length+
- ", which exceeds maximum of "+MAX_BAG_SIZE+
- "; breaking into multiple bags");
- this.program = program;
- this.instructions = instructions;
- this.baseAddress = baseAddress;
+ public final Fleet fleet;
+
+ private Program program = null;
+ private BitVector descriptor = null;
+ public DeferredBitVector getDescriptor() {
+ return new DeferredBitVector() {
+ public BitVector getBitVector() {
+ if (program==null) throw new RuntimeException();
+ seal();
+ return descriptor;
+ } };
+ }
+
+ LinkedHashMap<Dock,LoopFactory> startupLoopFactories = new LinkedHashMap<Dock,LoopFactory>();
+ ArrayList<LoopFactory> loopFactories = new ArrayList<LoopFactory>();
+
+ // FIXME: currently not used
+ private boolean sealed = false;
+ public boolean isSealed() { return sealed; }
+ public void seal() {
+ if (sealed) return;
+ for(LoopFactory lf : loopFactories) lf.flush_pending();
+ sealed = true;
+ if (program!=null) descriptor = program.addInstructions(emit());
+ }
+
+ public CodeBag(Fleet fleet) { this(fleet, null); }
+ public CodeBag(Program prog) { this(prog.fleet, prog); }
+ public CodeBag(Fleet fleet, Program prog) {
+ this.fleet = fleet;
+ this.program = prog;
+ }
+
+ public LoopFactory loopFactory(Dock dock, int count) { return loopFactory(dock, count, count==0); }
+ public LoopFactory loopFactory(Dock dock, int count, boolean torpedoable) {
+ LoopFactory ret = startupLoopFactories.get(dock);
+ if (ret == null) return new LoopFactory(this, dock, count, torpedoable);
+ while (ret.getNext()!=null)
+ ret = ret.getNext();
+ return ret.makeNext(count, torpedoable);
+ }
+
+ boolean autoflush = false;
+ public void setAutoflush(boolean a) { this.autoflush = a; }
+ public boolean getAutoflush() { return autoflush; }
+
+ public void emit(ArrayList<Instruction> ic) {
+ seal();
+ for(LoopFactory lf : startupLoopFactories.values())
+ lf.emit(ic);
+ }
+
+ private LoopFactory hack = null;
+ public void sendTorpedo(Dock dock) {
+ if (hack==null) hack = loopFactory(fleet.getShip("Timer",0).getDock("out"), 1);
+ hack.sendToken(dock.getInstructionDestination());
+ }
+ public void sendWord(DeferredBitVector bv, Destination dest) {
+ // problem: this isn't actually atomic -- two uncoordinated
+ // actors might invoke these commands at the same time
+ if (hack==null) hack = loopFactory(fleet.getShip("Timer",0).getDock("out"), 1);
+ hack.literal(bv);
+ hack.sendWord(dest);
+ }
+
+ public Instruction[] emit() {
+ ArrayList<Instruction> ic = new ArrayList<Instruction>();
+ emit(ic);
+ return (Instruction[])ic.toArray(new Instruction[0]);
+ }
+
+ public void dispatch(FleetProcess fp) { dispatch(fp, false); }
+ public void dispatch(FleetProcess fp, boolean flushWhenDone) {
+ ArrayList<Instruction> ai;
+ emit(ai = new ArrayList<Instruction>());
+ for(Instruction ins : ai)
+ fp.sendInstruction(ins);
+ if (flushWhenDone) fp.flush();
+ }
+
+ public void append(CodeBag ctx) {
+ if (sealed) throw new RuntimeException("already sealed");
+ // how to handle ship pools?
+ throw new RuntimeException("not implemented");
}
}