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 /** true if the instruction is an outer-looping instruction */
11 public final boolean looping;
13 /** the instruction's predicate */
14 public final Predicate predicate;
16 Instruction(Dock dock, boolean looping, Predicate predicate) {
17 if (dock==null) throw new RuntimeException("dock may not be null");
18 if (predicate==null) throw new RuntimeException("predicate may not be null");
20 this.looping = looping;
21 this.predicate = predicate;
24 //public abstract Instruction withLooping(boolean newLooping);
25 //public abstract Instruction withPredicate(Predicate newPredicate);
27 public String toString() {
28 String s = predicate.toString();
29 if (s.length()>0) s = "["+s+"] ";
30 if (looping) s += "[Rq] ";
35 * A <tt>set</tt> instruction.
37 * Note that immediates are supplied as Java <tt>long</tt> values
38 * because they are actual integers with two's complement
39 * sign-extension semantics. This is in contrast to most other
40 * immediate values in the API which are raw bit sequences of
41 * fixed length -- these are represented by instances of
44 public static class Set extends Instruction {
46 /** the destination (latch to be set) */
47 public final SetDest dest;
49 /** the source (what will be put in the <tt>dest</tt> latch) */
50 public final SetSource source;
52 /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
53 public final long immediate;
55 /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
56 public final FlagFunction newFlagA;
58 /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
59 public final FlagFunction newFlagB;
61 /** basic constructor */
62 public Set(Dock dock, SetDest dest, SetSource source) { this(dock, false, Predicate.Default, dest, source); }
63 public Set(Dock dock, boolean looping, Predicate predicate, SetDest dest, SetSource source) {
64 super(dock, looping, predicate);
66 case InnerLoopCounter:
68 case Infinity: case DataLatch: case Immediate: break OUTER;
71 case OuterLoopCounter:
73 case Decrement: case DataLatch: case Immediate: break OUTER;
77 if (source==SetSource.Immediate) break;
78 default: throw new RuntimeException("cannot set " + dest + " to " + source);
87 /** constructor for set instructions with immediates */
88 public Set(Dock dock, SetDest dest, long immediate) { this(dock, false, Predicate.Default, dest, immediate); }
89 public Set(Dock dock, boolean looping, Predicate predicate, SetDest dest, long immediate) {
90 super(dock, looping, predicate);
91 if (dest!=SetDest.InnerLoopCounter && dest!=SetDest.OuterLoopCounter && dest!=SetDest.DataLatch)
92 throw new RuntimeException("a set instruction with dest="+dest+" may not take an immediate");
93 this.source = SetSource.Immediate;
95 this.immediate = immediate;
100 /** constructor for <tt>set flags</tt> instructions */
101 public Set(Dock dock, FlagFunction newFlagA, FlagFunction newFlagB) { this(dock, false, Predicate.Default, newFlagA, newFlagB); }
102 public Set(Dock dock, boolean looping, Predicate predicate, FlagFunction newFlagA, FlagFunction newFlagB) {
103 super(dock, looping, predicate);
104 this.source = SetSource.Immediate;
105 this.dest = SetDest.Flags;
107 this.newFlagA = newFlagA;
108 this.newFlagB = newFlagB;
111 /** possible sources for the Set instruction */
112 public static enum SetSource {
113 Infinity, DataLatch, Immediate, Decrement;
115 /** possible destinations for the Set instruction */
116 public static enum SetDest {
117 InnerLoopCounter, OuterLoopCounter, Flags, DataLatch;
121 * (Immutable) a truth table describing how to update a flag
122 * based on the value of other flags; it is the logical OR of
123 * a set of flag predicates. This class is immutable; all
124 * methods that alter the function return a new object.
126 public static class FlagFunction implements Iterable<Predicate> {
128 /** the function that always assigns zero */
129 public static final FlagFunction ZERO = new FlagFunction();
131 /** the function that always assigns one */
132 public static final FlagFunction ONE = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
134 private final java.util.Set<Predicate> predicates;
136 public Iterator<Predicate> iterator() { return predicates.iterator(); }
138 private FlagFunction() { this(Collections.EMPTY_SET); }
139 private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
141 /** returns the function which is the logical OR of this function and <tt>ff</tt> */
142 public FlagFunction add(FlagFunction ff) {
143 FlagFunction ret = this;
144 for(Predicate p : ff) ret = ret.add(p);
148 /** returns the function which is the logical OR of this function and <tt>p</tt> */
149 public FlagFunction add(Predicate p) {
150 HashSet h = new HashSet();
151 h.addAll(predicates);
153 case FlagA: case NotFlagA:
154 case FlagB: case NotFlagB:
155 case FlagC: case NotFlagC:
158 throw new RuntimeException("invalid predicate in FlagFunction: " + p);
161 return new FlagFunction(h);
164 /** remove <tt>p</tt> from the set of terms which this function is the logical OR of */
165 public FlagFunction remove(Predicate p) {
166 HashSet h = new HashSet();
167 h.addAll(predicates);
169 return new FlagFunction(h);
172 public String toString() {
173 if (predicates.isEmpty()) return "0";
174 if (predicates.contains(Predicate.FlagA) && predicates.contains(Predicate.NotFlagA)) return "1";
175 if (predicates.contains(Predicate.FlagB) && predicates.contains(Predicate.NotFlagB)) return "1";
176 if (predicates.contains(Predicate.FlagC) && predicates.contains(Predicate.NotFlagC)) return "1";
177 StringBuffer ret = new StringBuffer();
178 boolean empty = true;
179 for(Predicate p : new Predicate[] {
180 Predicate.FlagA, Predicate.NotFlagA,
181 Predicate.FlagB, Predicate.NotFlagB,
182 Predicate.FlagC, Predicate.NotFlagC })
183 if (predicates.contains(p)) {
184 if (!empty) ret.append("| ");
188 return ret.toString();
191 public boolean evaluate(boolean flag_a, boolean flag_b, boolean flag_c, boolean olc_zero) {
193 for(Predicate p : this)
194 ret |= p.evaluate(flag_a, flag_b, flag_c, olc_zero);
199 public String toString() {
201 case InnerLoopCounter:
203 case Infinity: return super.toString()+"set ilc=*;";
204 case DataLatch: return super.toString()+"set ilc=data;";
205 case Immediate: return super.toString()+"set ilc="+immediate+";";
207 case OuterLoopCounter:
209 case Decrement: return super.toString()+"set olc--;";
210 case DataLatch: return super.toString()+"set olc=data;";
211 case Immediate: return super.toString()+"set olc="+immediate+";";
213 case Flags: return super.toString()+"set flags a="+newFlagA+", b="+newFlagB+";";
214 case DataLatch: return super.toString()+"set word="+immediate+";";
216 throw new Error("impossible");
220 /** shifts an immediate into the low-order bits of the data latch */
221 public static class Shift extends Instruction {
222 public final BitVector immediate;
223 public Shift(Dock dock, BitVector immediate) { this(dock, false, Predicate.Default, immediate); }
224 public Shift(Dock dock, boolean looping, Predicate predicate, BitVector immediate) {
225 super(dock, looping, predicate);
226 this.immediate = immediate;
227 this.immediate.setImmutable();
228 if (immediate.length() != dock.getShip().getFleet().getShiftWidth())
229 throw new RuntimeException("attempt to create a Shift instruction with a "+immediate.length()+
230 "-bit immediate on a Fleet that uses "+dock.getShip().getFleet().getShiftWidth()+
231 "-bit shift instructions");
233 public String toString() { return super.toString()+"shift "+immediate; }
236 /** a flush instruction */
237 public static class Flush extends Instruction {
238 public Flush(Dock dock) { this(dock, false, Predicate.Default); }
239 public Flush(Dock dock, boolean looping, Predicate predicate) {
240 super(dock, looping, predicate);
241 if (!dock.isInputDock()) throw new RuntimeException("Flush is only allowed at input docks");
243 public String toString() { return super.toString()+"flush"; }
246 /** all communication is performed with this instruction */
247 public static class Move extends Instruction {
249 /** if true, this instruction is vulnerable to torpedoes */
250 public final boolean interruptible;
252 /** if non-null, the path to load into the path latch */
253 public final Path path;
255 /** if true, a token will be consumed before execution */
256 public final boolean tokenIn;
258 /** if true, data will be consumed before execution */
259 public final boolean dataIn;
261 /** if true, the data consumed will be copied into the data latch */
262 public final boolean latchData;
264 /** if true, the data consumed will be copied into the path latch */
265 public final boolean latchPath;
267 /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
268 public final boolean dataOut;
270 /** if true, the a token will be transmitted to the location in the path latch */
271 public final boolean tokenOut;
273 public Move(Dock dock,
282 this(dock, false, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
283 public Move(Dock dock,
286 boolean interruptible,
295 super(dock, looping, predicate);
297 this.tokenIn = tokenIn;
298 this.dataIn = dataIn;
299 this.latchData = latchData;
300 this.latchPath = latchPath;
301 this.dataOut = dataOut;
302 this.tokenOut = tokenOut;
303 this.interruptible = interruptible;
304 if (dock != null && dock.isInputDock() && tokenIn && dataIn)
305 throw new RuntimeException("cannot have two \"recv\"s: " + this);
306 if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
307 throw new RuntimeException("cannot have two \"send\"s: " + this);
308 if (latchData && !dataIn)
309 throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
310 if (latchPath && !dataIn)
311 throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
312 if (latchPath && path!=null)
313 throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
316 public String toString() {
317 StringBuffer ret = new StringBuffer();
318 if (tokenIn) ret.append(", recv token");
320 if (latchPath) ret.append(!dock.isInputDock() ? ", collect path" : ", recv path");
321 if (latchData) ret.append(!dock.isInputDock() ? ", collect" : ", recv");
322 if (!latchPath && !latchData) ret.append(", discard");
324 if (dataOut && dock.isInputDock()) ret.append(", deliver");
325 if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send" : ", send to " + path.getDestination().getDock());
326 if (tokenOut) ret.append(path==null ? ", token" : ", send token to " + path.getDestination().getDock());
327 String s = ret.toString();
328 s = s.equals("") ? "nop" : s.substring(2);
329 if (interruptible) s = "[T] " + s;
330 return super.toString()+s+";";
334 /** a flush instruction */
335 public static class Abort extends Instruction {
336 public Abort(Dock dock, Predicate predicate) { super(dock, false, predicate); }
337 public String toString() { return super.toString()+"abort;"; }
340 /** marks the start of a loop; closes the hatch */
341 public static class Head extends Instruction {
342 public Head(Dock dock) { super(dock, false, Predicate.IgnoreFlagD); }
343 public String toString() { return dock+": head;"; }
346 /** marks the end of a loop; closes the hatch */
347 public static class Tail extends Instruction {
348 public Tail(Dock dock) { super(dock, false, Predicate.IgnoreFlagD); }
349 public String toString() { return dock+": tail;"; }