package edu.berkeley.fleet.api;
+import java.util.*;
+/** a Fleet instruction; includes execution location but not full dispatch path */
public abstract class Instruction {
- public static class Kill extends Instruction {
+ /** the dock which is to execute this instruction */
+ public final Dock dock;
- public final BenkoBox benkoBox;
- public final int count;
- public final boolean killOnlyStandingInstructions;
- public Kill(BenkoBox benkoBox, int count, boolean killOnlyStandingInstructions) {
- this.benkoBox=benkoBox;
- this.count=count;
- this.killOnlyStandingInstructions = killOnlyStandingInstructions;
- }
- public String toString() { return (count>1 ? "["+count+"] " : "") + "kill"; }
+ /** the instruction's predicate */
+ public final Predicate predicate;
+ Instruction(Dock dock, Predicate predicate) {
+ if (dock==null) throw new RuntimeException("dock may not be null");
+ if (predicate==null) throw new RuntimeException("predicate may not be null");
+ this.dock = dock;
+ this.predicate = predicate;
}
- public static class Executable extends Instruction {
-
- public final BenkoBox benkoBox;
- public final Destination dest;
- public final int count;
-
- public final boolean tokenIn;
- public final boolean dataIn;
- public final boolean latch;
- public final boolean dataOut;
- public final boolean tokenOut;
- public final boolean recycle;
-
- /** count=0 denotes a standing move */
- public Executable(BenkoBox benkoBox,
- Destination dest,
- int count,
- boolean tokenIn,
- boolean dataIn,
- boolean latch,
- boolean dataOut,
- boolean tokenOut,
- boolean recycle) {
- this.benkoBox = benkoBox;
+ //public abstract Instruction withLooping(boolean newLooping);
+ //public abstract Instruction withPredicate(Predicate newPredicate);
+
+ public String toString() {
+ String s = predicate.toString();
+ if (s.length()>0) s = "["+s+"] ";
+ return dock+": "+s;
+ }
+
+ /**
+ * A <tt>set</tt> instruction.
+ *
+ * Note that immediates are supplied as Java <tt>long</tt> values
+ * because they are actual integers with two's complement
+ * sign-extension semantics. This is in contrast to most other
+ * immediate values in the API which are raw bit sequences of
+ * fixed length -- these are represented by instances of
+ * <tt>BitVector</tt>.
+ */
+ public static class Set extends Instruction {
+
+ /** the destination (latch to be set) */
+ public final SetDest dest;
+
+ /** the source (what will be put in the <tt>dest</tt> latch) */
+ public final SetSource source;
+
+ /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
+ public final long immediate;
+
+ /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
+ public final FlagFunction newFlagA;
+
+ /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
+ public final FlagFunction newFlagB;
+
+ /** basic constructor */
+ public Set(Dock dock, SetDest dest, SetSource source) { this(dock, Predicate.Default, dest, source); }
+ public Set(Dock dock, Predicate predicate, SetDest dest, SetSource source) {
+ super(dock, predicate);
+ OUTER: switch(dest) {
+ case InnerLoopCounter:
+ switch(source) {
+ case Infinity: case DataLatch: case Immediate: break OUTER;
+ default: break;
+ }
+ case OuterLoopCounter:
+ switch(source) {
+ case Decrement: case DataLatch: case Immediate: break OUTER;
+ default: break;
+ }
+ case DataLatch:
+ if (source==SetSource.Immediate) break;
+ default: throw new RuntimeException("cannot set " + dest + " to " + source);
+ }
+ this.source = source;
this.dest = dest;
- this.count = count;
- this.tokenIn = tokenIn;
- this.dataIn = dataIn;
- this.latch = latch;
- this.dataOut = dataOut;
- this.tokenOut = tokenOut;
- this.recycle = recycle;
- if (count < 0)
- throw new RuntimeException("count field of an instruction must be >=0");
+ this.immediate = 0;
+ this.newFlagA = null;
+ this.newFlagB = null;
}
- public boolean isStanding() {
- return count==0;
+ /** constructor for set instructions with immediates */
+ public Set(Dock dock, SetDest dest, long immediate) { this(dock, Predicate.Default, dest, immediate); }
+ public Set(Dock dock, Predicate predicate, SetDest dest, long immediate) {
+ super(dock, predicate);
+ if (dest!=SetDest.InnerLoopCounter && dest!=SetDest.OuterLoopCounter && dest!=SetDest.DataLatch)
+ throw new RuntimeException("a set instruction with dest="+dest+" may not take an immediate");
+ this.source = SetSource.Immediate;
+ this.dest = dest;
+ this.immediate = immediate;
+ this.newFlagA = null;
+ this.newFlagB = null;
}
- public Instruction.Executable decrementCount() {
- if (count==1) return null;
- return new Executable(benkoBox, dest, count==0 ? 0 : count-1,
- tokenIn, dataIn, latch, dataOut, tokenOut, recycle);
+ /** constructor for <tt>set flags</tt> instructions */
+ public Set(Dock dock, FlagFunction newFlagA, FlagFunction newFlagB) { this(dock, Predicate.Default, newFlagA, newFlagB); }
+ public Set(Dock dock, Predicate predicate, FlagFunction newFlagA, FlagFunction newFlagB) {
+ super(dock, predicate);
+ this.source = SetSource.Immediate;
+ this.dest = SetDest.Flags;
+ this.immediate = 0;
+ this.newFlagA = newFlagA;
+ this.newFlagB = newFlagB;
}
- public String toString() {
- String ret = benkoBox.toString() + ": ";
- if (count==0 || count>1 || recycle) {
- ret += recycle ? "(" : "[";
- if (count>1) ret += count;
- if (count==0) ret += "*";
- ret += recycle ? ")" : "] ";
+ /** possible sources for the Set instruction */
+ public static enum SetSource {
+ Infinity, DataLatch, Immediate, Decrement;
+ }
+ /** possible destinations for the Set instruction */
+ public static enum SetDest {
+ InnerLoopCounter, OuterLoopCounter, Flags, DataLatch;
+ }
+
+ /**
+ * (Immutable) a truth table describing how to update a flag
+ * based on the value of other flags; it is the logical OR of
+ * a set of flag predicates. This class is immutable; all
+ * methods that alter the function return a new object.
+ */
+ public static class FlagFunction implements Iterable<Predicate> {
+
+ /** the function that always assigns zero */
+ public static final FlagFunction ZERO = new FlagFunction();
+
+ /** the function that always assigns one */
+ public static final FlagFunction ONE = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
+
+ private final java.util.Set<Predicate> predicates;
+
+ public Iterator<Predicate> iterator() { return predicates.iterator(); }
+
+ private FlagFunction() { this(Collections.EMPTY_SET); }
+ private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
+
+ /** returns the function which is the logical OR of this function and <tt>ff</tt> */
+ public FlagFunction add(FlagFunction ff) {
+ FlagFunction ret = this;
+ for(Predicate p : ff) ret = ret.add(p);
+ return ret;
}
- boolean needcomma = false;
- if (tokenIn) { ret += (needcomma ? ", " : "") + "wait"; needcomma = true; }
- if (dataIn && latch) {
- if (benkoBox instanceof BenkoBox.Inbox)
- ret += (needcomma ? ", " : "") + "receive";
- else
- ret += (needcomma ? ", " : "") + "take";
- needcomma = true;
+
+ /** returns the function which is the logical OR of this function and <tt>p</tt> */
+ public FlagFunction add(Predicate p) {
+ HashSet h = new HashSet();
+ h.addAll(predicates);
+ switch(p) {
+ case FlagA: case NotFlagA:
+ case FlagB: case NotFlagB:
+ case FlagC: case NotFlagC:
+ break;
+ default:
+ throw new RuntimeException("invalid predicate in FlagFunction: " + p);
+ }
+ h.add(p);
+ return new FlagFunction(h);
+ }
+
+ /** remove <tt>p</tt> from the set of terms which this function is the logical OR of */
+ public FlagFunction remove(Predicate p) {
+ HashSet h = new HashSet();
+ h.addAll(predicates);
+ h.remove(p);
+ return new FlagFunction(h);
+ }
+
+ public String toString() {
+ if (predicates.isEmpty()) return "0";
+ if (predicates.contains(Predicate.FlagA) && predicates.contains(Predicate.NotFlagA)) return "1";
+ if (predicates.contains(Predicate.FlagB) && predicates.contains(Predicate.NotFlagB)) return "1";
+ if (predicates.contains(Predicate.FlagC) && predicates.contains(Predicate.NotFlagC)) return "1";
+ StringBuffer ret = new StringBuffer();
+ boolean empty = true;
+ for(Predicate p : new Predicate[] {
+ Predicate.FlagA, Predicate.NotFlagA,
+ Predicate.FlagB, Predicate.NotFlagB,
+ Predicate.FlagC, Predicate.NotFlagC })
+ if (predicates.contains(p)) {
+ if (!empty) ret.append("| ");
+ ret.append(p);
+ empty = false;
+ }
+ return ret.toString();
}
- if (dataIn && !latch) { ret += (needcomma ? ", " : "") + "dismiss"; needcomma = true; }
- if (dataOut) {
- if (benkoBox instanceof BenkoBox.Inbox || dest==null)
- ret += (needcomma ? ", " : "") + "deliver";
- else
- ret += (needcomma ? ", " : "") + "sendto "+dest;
- needcomma = true;
+
+ public boolean evaluate(boolean flag_a, boolean flag_b, boolean flag_c, boolean olc_zero) {
+ boolean ret = false;
+ for(Predicate p : this)
+ ret |= p.evaluate(flag_a, flag_b, flag_c, olc_zero);
+ return ret;
}
- if (tokenOut) { ret += (needcomma ? ", " : "") + "notify "+dest; needcomma = true; }
- return ret;
}
+ public String toString() {
+ switch(dest) {
+ case InnerLoopCounter:
+ switch(source) {
+ case Infinity: return super.toString()+"set ilc=*;";
+ case DataLatch: return super.toString()+"set ilc=data;";
+ case Immediate: return super.toString()+"set ilc="+immediate+";";
+ }
+ case OuterLoopCounter:
+ switch(source) {
+ case Decrement: return super.toString()+"set olc--;";
+ case DataLatch: return super.toString()+"set olc=data;";
+ case Immediate: return super.toString()+"set olc="+immediate+";";
+ }
+ case Flags: return super.toString()+"set flags a="+newFlagA+", b="+newFlagB+";";
+ case DataLatch: return super.toString()+"set word="+immediate+";";
+ }
+ throw new Error("impossible");
+ }
}
- public static class Literal extends Instruction {
- public final Destination dest;
- protected Literal(Destination dest) { this.dest = dest; }
+ /** shifts an immediate into the low-order bits of the data latch */
+ public static class Shift extends Instruction {
+ public final DeferredBitVector immediate;
+ public Shift(Dock dock, DeferredBitVector immediate) { this(dock, Predicate.Default, immediate); }
+ public Shift(final Dock dock, Predicate predicate, final DeferredBitVector arg) {
+ super(dock, predicate);
+ this.immediate = new DeferredBitVector() {
+ public BitVector getBitVector() {
+ BitVector ret = arg.getBitVector();
+ if (ret.length() != dock.getShip().getFleet().getShiftWidth())
+ throw new RuntimeException("attempt to create a Shift instruction with a "+ret.length()+
+ "-bit immediate on a Fleet that uses "+dock.getShip().getFleet().getShiftWidth()+
+ "-bit shift instructions");
+ return ret;
+ }
+ };
+ }
+ public String toString() { return super.toString()+"shift "+immediate.getBitVector(); }
+ }
- public static class Absolute extends Literal {
- public final long value;
- public Absolute(Destination dest, long value) { super(dest); this.value = value; }
- public String toString() {
- return value + ": sendto " + dest;
- }
+ /** a flush instruction */
+ public static class Flush extends Instruction {
+ public Flush(Dock dock) { this(dock, Predicate.Default); }
+ public Flush(Dock dock, Predicate predicate) {
+ super(dock, predicate);
+ if (!dock.isInputDock()) throw new RuntimeException("Flush is only allowed at input docks");
}
+ public String toString() { return super.toString()+"flush;"; }
+ }
- public static class Relative extends Literal {
- /** value transmitted will be offset plus the address from which this instruction was loaded */
- public final long offset;
- public Relative(Destination dest, long offset) { super(dest); this.offset = offset; }
- public String toString() {
- String off = ""+offset;
- if (offset > 0) off = "+"+off;
- return "(@"+offset+"): sendto " + dest;
- }
+ /** all communication is performed with this instruction */
+ public static class Move extends Instruction {
+
+ /** if true, this instruction is vulnerable to torpedoes */
+ public final boolean interruptible;
+
+ /** if non-null, the path to load into the path latch */
+ public final Path path;
+
+ /** if true, a token will be consumed before execution */
+ public final boolean tokenIn;
+
+ /** if true, data will be consumed before execution */
+ public final boolean dataIn;
+
+ /** if true, the data consumed will be copied into the data latch */
+ public final boolean latchData;
+
+ /** if true, the data consumed will be copied into the path latch */
+ public final boolean latchPath;
+
+ /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
+ public final boolean dataOut;
+
+ /** if true, the a token will be transmitted to the location in the path latch */
+ public final boolean tokenOut;
+
+ public Move(Dock dock,
+ Path path,
+ boolean tokenIn,
+ boolean dataIn,
+ boolean latchData,
+ boolean latchPath,
+ boolean dataOut,
+ boolean tokenOut
+ ) {
+ this(dock, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
+ public Move(Dock dock,
+ Predicate predicate,
+ boolean interruptible,
+ Path path,
+ boolean tokenIn,
+ boolean dataIn,
+ boolean latchData,
+ boolean latchPath,
+ boolean dataOut,
+ boolean tokenOut
+ ) {
+ super(dock, predicate);
+ this.path = path;
+ this.tokenIn = tokenIn;
+ this.dataIn = dataIn;
+ this.latchData = latchData;
+ this.latchPath = latchPath;
+ this.dataOut = dataOut;
+ this.tokenOut = tokenOut;
+ this.interruptible = interruptible;
+ if (dock != null && dock.isInputDock() && tokenIn && dataIn)
+ throw new RuntimeException("cannot have two \"recv\"s: " + this);
+ if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
+ throw new RuntimeException("cannot have two \"send\"s: " + this);
+ if (latchData && !dataIn)
+ throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
+ if (latchPath && !dataIn)
+ throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
+ if (latchPath && path!=null)
+ throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
}
- public static class CodeBagDescriptor extends Literal {
- /** address of CBD, relative to address that this instruction was loaded from */
- public final long offset;
- public final long size;
- public CodeBagDescriptor(Destination dest, long offset, long size) {
- super(dest); this.offset = offset; this.size = size; }
- public String toString() {
- String off = ""+offset;
- if (offset > 0) off = "+"+off;
- return "(@"+off+":"+size+"): sendto " + dest;
+ public String toString() {
+ StringBuffer ret = new StringBuffer();
+ if (tokenIn) ret.append(", recv token");
+ if (dataIn) {
+ if (latchPath && latchData) ret.append(!dock.isInputDock() ? ", collect packet" : ", recv packet");
+ if (latchPath) ret.append(!dock.isInputDock() ? ", collect path" : ", recv path");
+ else if (latchData) ret.append(!dock.isInputDock() ? ", collect" : ", recv");
+ else ret.append(!dock.isInputDock() ? ", collect nothing" : ", recv nothing");
}
+ if (dataOut && dock.isInputDock()) ret.append(", deliver");
+ if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send" : ", send to " + pathToString(path));
+ if (tokenOut) ret.append(path==null ? ", token" : ", send token to " + pathToString(path));
+ String s = ret.toString();
+ s = s.equals("") ? "nop" : s.substring(2);
+ if (interruptible) s = "[T] " + s;
+ return super.toString()+s+";";
+ }
+
+ private String pathToString(Path path) {
+ BitVector signal = path.getSignal();
+ if (signal!=null)
+ for(int i=0; i<signal.length(); i++)
+ if (signal.get(i))
+ return (path.getDestination()+":"+signal.toLong());
+ return (path.getDestination()+"");
}
}
+
+ /** a flush instruction */
+ public static class Abort extends Instruction {
+ public Abort(Dock dock, Predicate predicate) { super(dock, predicate); }
+ public String toString() { return super.toString()+"abort;"; }
+ }
+
+ /** marks the start of a loop; closes the hatch */
+ public static class Head extends Instruction {
+ public Head(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
+ public String toString() { return dock+": head;"; }
+ }
+
+ /** marks the end of a loop; closes the hatch */
+ public static class Tail extends Instruction {
+ public Tail(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
+ public String toString() { return dock+": tail;"; }
+ }
+
}