1 package edu.berkeley.fleet.api;
4 /** a Fleet instruction; includes execution location but not full dispatch path */
5 public abstract class Instruction {
7 /** the dock which is to execute this instruction */
8 public final Dock dock;
10 /** the instruction's predicate */
11 public final Predicate predicate;
13 Instruction(Dock dock, Predicate predicate) {
14 if (dock==null) throw new RuntimeException("dock may not be null");
15 if (predicate==null) throw new RuntimeException("predicate may not be null");
17 this.predicate = predicate;
20 //public abstract Instruction withLooping(boolean newLooping);
21 //public abstract Instruction withPredicate(Predicate newPredicate);
23 public String toString() {
24 String s = predicate.toString();
25 if (s.length()>0) s = "["+s+"] ";
30 * A <tt>set</tt> instruction.
32 * Note that immediates are supplied as Java <tt>long</tt> values
33 * because they are actual integers with two's complement
34 * sign-extension semantics. This is in contrast to most other
35 * immediate values in the API which are raw bit sequences of
36 * fixed length -- these are represented by instances of
39 public static class Set extends Instruction {
41 /** the destination (latch to be set) */
42 public final SetDest dest;
44 /** the source (what will be put in the <tt>dest</tt> latch) */
45 public final SetSource source;
47 /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
48 public final long immediate;
50 /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
51 public final FlagFunction newFlagA;
53 /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
54 public final FlagFunction newFlagB;
56 /** basic constructor */
57 public Set(Dock dock, SetDest dest, SetSource source) { this(dock, Predicate.Default, dest, source); }
58 public Set(Dock dock, Predicate predicate, SetDest dest, SetSource source) {
59 super(dock, predicate);
61 case InnerLoopCounter:
63 case Infinity: case DataLatch: case Immediate: break OUTER;
66 case OuterLoopCounter:
68 case Decrement: case DataLatch: case Immediate: break OUTER;
72 if (source==SetSource.Immediate) break;
73 default: throw new RuntimeException("cannot set " + dest + " to " + source);
82 /** constructor for set instructions with immediates */
83 public Set(Dock dock, SetDest dest, long immediate) { this(dock, Predicate.Default, dest, immediate); }
84 public Set(Dock dock, Predicate predicate, SetDest dest, long immediate) {
85 super(dock, predicate);
86 if (dest!=SetDest.InnerLoopCounter && dest!=SetDest.OuterLoopCounter && dest!=SetDest.DataLatch)
87 throw new RuntimeException("a set instruction with dest="+dest+" may not take an immediate");
88 this.source = SetSource.Immediate;
90 this.immediate = immediate;
95 /** constructor for <tt>set flags</tt> instructions */
96 public Set(Dock dock, FlagFunction newFlagA, FlagFunction newFlagB) { this(dock, Predicate.Default, newFlagA, newFlagB); }
97 public Set(Dock dock, Predicate predicate, FlagFunction newFlagA, FlagFunction newFlagB) {
98 super(dock, predicate);
99 this.source = SetSource.Immediate;
100 this.dest = SetDest.Flags;
102 this.newFlagA = newFlagA;
103 this.newFlagB = newFlagB;
106 /** possible sources for the Set instruction */
107 public static enum SetSource {
108 Infinity, DataLatch, Immediate, Decrement;
110 /** possible destinations for the Set instruction */
111 public static enum SetDest {
112 InnerLoopCounter, OuterLoopCounter, Flags, DataLatch;
116 * (Immutable) a truth table describing how to update a flag
117 * based on the value of other flags; it is the logical OR of
118 * a set of flag predicates. This class is immutable; all
119 * methods that alter the function return a new object.
121 public static class FlagFunction implements Iterable<Predicate> {
123 /** the function that always assigns zero */
124 public static final FlagFunction ZERO = new FlagFunction();
126 /** the function that always assigns one */
127 public static final FlagFunction ONE = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
129 private final java.util.Set<Predicate> predicates;
131 public Iterator<Predicate> iterator() { return predicates.iterator(); }
133 private FlagFunction() { this(Collections.EMPTY_SET); }
134 private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
136 /** returns the function which is the logical OR of this function and <tt>ff</tt> */
137 public FlagFunction add(FlagFunction ff) {
138 FlagFunction ret = this;
139 for(Predicate p : ff) ret = ret.add(p);
143 /** returns the function which is the logical OR of this function and <tt>p</tt> */
144 public FlagFunction add(Predicate p) {
145 HashSet h = new HashSet();
146 h.addAll(predicates);
148 case FlagA: case NotFlagA:
149 case FlagB: case NotFlagB:
150 case FlagC: case NotFlagC:
153 throw new RuntimeException("invalid predicate in FlagFunction: " + p);
156 return new FlagFunction(h);
159 /** remove <tt>p</tt> from the set of terms which this function is the logical OR of */
160 public FlagFunction remove(Predicate p) {
161 HashSet h = new HashSet();
162 h.addAll(predicates);
164 return new FlagFunction(h);
167 public String toString() {
168 if (predicates.isEmpty()) return "0";
169 if (predicates.contains(Predicate.FlagA) && predicates.contains(Predicate.NotFlagA)) return "1";
170 if (predicates.contains(Predicate.FlagB) && predicates.contains(Predicate.NotFlagB)) return "1";
171 if (predicates.contains(Predicate.FlagC) && predicates.contains(Predicate.NotFlagC)) return "1";
172 StringBuffer ret = new StringBuffer();
173 boolean empty = true;
174 for(Predicate p : new Predicate[] {
175 Predicate.FlagA, Predicate.NotFlagA,
176 Predicate.FlagB, Predicate.NotFlagB,
177 Predicate.FlagC, Predicate.NotFlagC })
178 if (predicates.contains(p)) {
179 if (!empty) ret.append("|");
183 return ret.toString();
186 public boolean evaluate(boolean flag_a, boolean flag_b, boolean flag_c, boolean olc_zero) {
188 for(Predicate p : this)
189 ret |= p.evaluate(flag_a, flag_b, flag_c, olc_zero);
194 public String toString() {
196 case InnerLoopCounter:
198 case Infinity: return super.toString()+"set ilc=*;";
199 case DataLatch: return super.toString()+"set ilc=data;";
200 case Immediate: return super.toString()+"set ilc="+immediate+";";
202 case OuterLoopCounter:
204 case Decrement: return super.toString()+"set olc--;";
205 case DataLatch: return super.toString()+"set olc=data;";
206 case Immediate: return super.toString()+"set olc="+immediate+";";
208 case Flags: return super.toString()+"set flags a="+newFlagA+", b="+newFlagB+";";
209 case DataLatch: return super.toString()+"set word="+immediate+";";
211 throw new Error("impossible");
215 /** shifts an immediate into the low-order bits of the data latch */
216 public static class Shift extends Instruction {
217 public final DeferredBitVector immediate;
218 public Shift(Dock dock, DeferredBitVector immediate) { this(dock, Predicate.Default, immediate); }
219 public Shift(final Dock dock, Predicate predicate, final DeferredBitVector arg) {
220 super(dock, predicate);
221 this.immediate = new DeferredBitVector() {
222 public BitVector getBitVector() {
223 BitVector ret = arg.getBitVector();
224 if (ret.length() != dock.getShip().getFleet().getShiftWidth())
225 throw new RuntimeException("attempt to create a Shift instruction with a "+ret.length()+
226 "-bit immediate on a Fleet that uses "+dock.getShip().getFleet().getShiftWidth()+
227 "-bit shift instructions");
232 public String toString() { return super.toString()+"shift "+immediate.getBitVector(); }
235 /** a flush instruction */
236 public static class Flush extends Instruction {
237 public Flush(Dock dock) { this(dock, Predicate.Default); }
238 public Flush(Dock dock, Predicate predicate) {
239 super(dock, predicate);
240 if (!dock.isInputDock()) throw new RuntimeException("Flush is only allowed at input docks");
242 public String toString() { return super.toString()+"flush;"; }
245 /** all communication is performed with this instruction */
246 public static class Move extends Instruction {
248 /** if true, this instruction is vulnerable to torpedoes */
249 public final boolean interruptible;
251 /** if non-null, the path to load into the path latch */
252 public final Path path;
254 /** if true, a token will be consumed before execution */
255 public final boolean tokenIn;
257 /** if true, data will be consumed before execution */
258 public final boolean dataIn;
260 /** if true, the data consumed will be copied into the data latch */
261 public final boolean latchData;
263 /** if true, the data consumed will be copied into the path latch */
264 public final boolean latchPath;
266 /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
267 public final boolean dataOut;
269 /** if true, the a token will be transmitted to the location in the path latch */
270 public final boolean tokenOut;
272 public Move(Dock dock,
281 this(dock, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
282 public Move(Dock dock,
284 boolean interruptible,
293 super(dock, predicate);
295 this.tokenIn = tokenIn;
296 this.dataIn = dataIn;
297 this.latchData = latchData;
298 this.latchPath = latchPath;
299 this.dataOut = dataOut;
300 this.tokenOut = tokenOut;
301 this.interruptible = interruptible;
302 if (dock != null && dock.isInputDock() && tokenIn && dataIn)
303 throw new RuntimeException("cannot have two \"recv\"s: " + this);
304 if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
305 throw new RuntimeException("cannot have two \"send\"s: " + this);
306 if (latchData && !dataIn)
307 throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
308 if (latchPath && !dataIn)
309 throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
310 if (latchPath && path!=null)
311 throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
314 public String toString() {
315 StringBuffer ret = new StringBuffer();
316 if (tokenIn) ret.append(", recv token");
318 if (latchPath && latchData) ret.append(!dock.isInputDock() ? ", collect packet" : ", recv packet");
319 if (latchPath) ret.append(!dock.isInputDock() ? ", collect path" : ", recv path");
320 else if (latchData) ret.append(!dock.isInputDock() ? ", collect" : ", recv");
321 else ret.append(!dock.isInputDock() ? ", collect nothing" : ", recv nothing");
323 if (dataOut && dock.isInputDock()) ret.append(", deliver");
324 if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send" : ", send to " + pathToString(path));
325 if (tokenOut) ret.append(path==null ? ", token" : ", send token to " + pathToString(path));
326 String s = ret.toString();
327 s = s.equals("") ? "nop" : s.substring(2);
328 if (interruptible) s = "[T] " + s;
329 return super.toString()+s+";";
332 private String pathToString(Path path) {
333 BitVector signal = path.getSignal();
335 for(int i=0; i<signal.length(); i++)
337 return (path.getDestination()+":"+signal.toLong());
338 return (path.getDestination()+"");
342 /** a flush instruction */
343 public static class Abort extends Instruction {
344 public Abort(Dock dock, Predicate predicate) { super(dock, predicate); }
345 public String toString() { return super.toString()+"abort;"; }
348 /** marks the start of a loop; closes the hatch */
349 public static class Head extends Instruction {
350 public Head(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
351 public String toString() { return dock+": head;"; }
354 /** marks the end of a loop; closes the hatch */
355 public static class Tail extends Instruction {
356 public Tail(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
357 public String toString() { return dock+": tail;"; }