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 BitVector immediate;
218 public Shift(Dock dock, BitVector immediate) { this(dock, Predicate.Default, immediate); }
219 public Shift(Dock dock, Predicate predicate, BitVector immediate) {
220 super(dock, predicate);
221 this.immediate = immediate;
222 this.immediate.setImmutable();
223 if (immediate.length() != dock.getShip().getFleet().getShiftWidth())
224 throw new RuntimeException("attempt to create a Shift instruction with a "+immediate.length()+
225 "-bit immediate on a Fleet that uses "+dock.getShip().getFleet().getShiftWidth()+
226 "-bit shift instructions");
228 public String toString() { return super.toString()+"shift "+immediate; }
231 /** a flush instruction */
232 public static class Flush extends Instruction {
233 public Flush(Dock dock) { this(dock, Predicate.Default); }
234 public Flush(Dock dock, Predicate predicate) {
235 super(dock, predicate);
236 if (!dock.isInputDock()) throw new RuntimeException("Flush is only allowed at input docks");
238 public String toString() { return super.toString()+"flush"; }
241 /** all communication is performed with this instruction */
242 public static class Move extends Instruction {
244 /** if true, this instruction is vulnerable to torpedoes */
245 public final boolean interruptible;
247 /** if non-null, the path to load into the path latch */
248 public final Path path;
250 /** if true, a token will be consumed before execution */
251 public final boolean tokenIn;
253 /** if true, data will be consumed before execution */
254 public final boolean dataIn;
256 /** if true, the data consumed will be copied into the data latch */
257 public final boolean latchData;
259 /** if true, the data consumed will be copied into the path latch */
260 public final boolean latchPath;
262 /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
263 public final boolean dataOut;
265 /** if true, the a token will be transmitted to the location in the path latch */
266 public final boolean tokenOut;
268 public Move(Dock dock,
277 this(dock, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
278 public Move(Dock dock,
280 boolean interruptible,
289 super(dock, predicate);
291 this.tokenIn = tokenIn;
292 this.dataIn = dataIn;
293 this.latchData = latchData;
294 this.latchPath = latchPath;
295 this.dataOut = dataOut;
296 this.tokenOut = tokenOut;
297 this.interruptible = interruptible;
298 if (dock != null && dock.isInputDock() && tokenIn && dataIn)
299 throw new RuntimeException("cannot have two \"recv\"s: " + this);
300 if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
301 throw new RuntimeException("cannot have two \"send\"s: " + this);
302 if (latchData && !dataIn)
303 throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
304 if (latchPath && !dataIn)
305 throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
306 if (latchPath && path!=null)
307 throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
310 public String toString() {
311 StringBuffer ret = new StringBuffer();
312 if (tokenIn) ret.append(", recv token");
314 if (latchPath && latchData) ret.append(!dock.isInputDock() ? ", collect packet" : ", recv packet");
315 if (latchPath) ret.append(!dock.isInputDock() ? ", collect path" : ", recv path");
316 else if (latchData) ret.append(!dock.isInputDock() ? ", collect" : ", recv");
317 else ret.append(!dock.isInputDock() ? ", collect nothing" : ", recv nothing");
319 if (dataOut && dock.isInputDock()) ret.append(", deliver");
320 if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send" : ", send to " + path.getDestination().getDock());
321 if (tokenOut) ret.append(path==null ? ", token" : ", send token to " + path.getDestination().getDock());
322 String s = ret.toString();
323 s = s.equals("") ? "nop" : s.substring(2);
324 if (interruptible) s = "[T] " + s;
325 return super.toString()+s+";";
329 /** a flush instruction */
330 public static class Abort extends Instruction {
331 public Abort(Dock dock, Predicate predicate) { super(dock, predicate); }
332 public String toString() { return super.toString()+"abort;"; }
335 /** marks the start of a loop; closes the hatch */
336 public static class Head extends Instruction {
337 public Head(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
338 public String toString() { return dock+": head;"; }
341 /** marks the end of a loop; closes the hatch */
342 public static class Tail extends Instruction {
343 public Tail(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
344 public String toString() { return dock+": tail;"; }