fix typo in Instruction.Abort.toString()
[fleet.git] / src / edu / berkeley / fleet / api / Instruction.java
1 package edu.berkeley.fleet.api;
2 import java.util.*;
3
4 /** a Fleet instruction; includes execution location but not full dispatch path */
5 public abstract class Instruction {
6
7     /** the dock which is to execute this instruction */
8     public final Dock      dock;
9
10     /** true if the instruction is an outer-looping instruction */
11     public final boolean   looping;
12
13     /** the instruction's predicate */
14     public final Predicate predicate;
15
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");
19         this.dock = dock;
20         this.looping = looping;
21         this.predicate = predicate;
22     }
23
24     //public abstract Instruction withLooping(boolean newLooping);
25     //public abstract Instruction withPredicate(Predicate newPredicate);
26
27     public String toString() {
28         String s = predicate.toString();
29         if (s.length()>0) s = "["+s+"] ";
30         if (looping) s += "[Rq] ";
31         return dock+": "+s;
32     }
33
34     /**
35      *  A <tt>set</tt> instruction.
36      *
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
42      *  <tt>BitVector</tt>.
43      */
44     public static class Set extends Instruction {
45
46         /** the destination (latch to be set) */
47         public final SetDest        dest;
48
49         /** the source (what will be put in the <tt>dest</tt> latch) */
50         public final SetSource      source;
51
52         /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
53         public final long           immediate;
54
55         /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
56         public final FlagFunction   newFlagA;
57
58         /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
59         public final FlagFunction   newFlagB;
60
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);
65             OUTER: switch(dest) {
66                 case InnerLoopCounter:
67                     switch(source) {
68                         case Infinity: case DataLatch: case Immediate: break OUTER;
69                         default: break;
70                     }
71                 case OuterLoopCounter:
72                     switch(source) {
73                         case Decrement: case DataLatch: case Immediate: break OUTER;
74                         default: break;
75                     }
76                 case DataLatch:
77                     if (source==SetSource.Immediate) break;
78                 default: throw new RuntimeException("cannot set " + dest + " to " + source);
79             }
80             this.source = source;
81             this.dest = dest;
82             this.immediate = 0;
83             this.newFlagA = null;
84             this.newFlagB = null;
85         }
86
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;
94             this.dest = dest;
95             this.immediate = immediate;
96             this.newFlagA = null;
97             this.newFlagB = null;
98         }
99
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;
106             this.immediate = 0;
107             this.newFlagA = newFlagA;
108             this.newFlagB = newFlagB;
109         }
110
111         /** possible sources for the Set instruction */
112         public static enum SetSource {
113             Infinity, DataLatch, Immediate, Decrement;
114         }
115         /** possible destinations for the Set instruction */
116         public static enum SetDest {
117             InnerLoopCounter, OuterLoopCounter, Flags, DataLatch;
118         }
119
120         /**
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.
125          */
126         public static class FlagFunction implements Iterable<Predicate> {
127
128             /** the function that always assigns zero */
129             public static final FlagFunction ZERO = new FlagFunction();
130
131             /** the function that always assigns one */
132             public static final FlagFunction ONE  = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
133
134             private final java.util.Set<Predicate> predicates;
135
136             public Iterator<Predicate> iterator() { return predicates.iterator(); }
137
138             private FlagFunction() { this(Collections.EMPTY_SET); }
139             private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
140
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);
145                 return ret;
146             }
147
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);
152                 switch(p) {
153                     case FlagA: case NotFlagA:
154                     case FlagB: case NotFlagB:
155                     case FlagC: case NotFlagC:
156                         break;
157                     default:
158                         throw new RuntimeException("invalid predicate in FlagFunction: " + p);
159                 }
160                 h.add(p);
161                 return new FlagFunction(h);
162             }
163
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);
168                 h.remove(p);
169                 return new FlagFunction(h);
170             }
171
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("| ");
185                         ret.append(p);
186                         empty = false;
187                     }
188                 return ret.toString();
189             }
190
191             public boolean evaluate(boolean flag_a, boolean flag_b, boolean flag_c, boolean olc_zero) {
192                 boolean ret = false;
193                 for(Predicate p : this)
194                     ret |= p.evaluate(flag_a, flag_b, flag_c, olc_zero);
195                 return ret;
196             }
197         }
198
199         public String toString() {
200             switch(dest) {
201                 case InnerLoopCounter:
202                     switch(source) {
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+";";
206                     }
207                 case OuterLoopCounter:
208                     switch(source) {
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+";";
212                     }
213                 case Flags: return super.toString()+"set flags a="+newFlagA+", b="+newFlagB+";";
214                 case DataLatch: return super.toString()+"set word="+immediate+";";
215             }
216             throw new Error("impossible");
217         }
218     }
219
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");
232         }
233         public String toString() { return super.toString()+"shift "+immediate; }
234     }
235
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");
242         }
243         public String toString() { return super.toString()+"flush"; }
244     }
245
246     /** all communication is performed with this instruction */
247     public static class Move extends Instruction {
248
249         /** if true, this instruction is vulnerable to torpedoes */
250         public final boolean     interruptible;
251
252         /** if non-null, the path to load into the path latch */
253         public final Path        path;
254
255         /** if true, a token will be consumed before execution */
256         public final boolean     tokenIn;
257
258         /** if true, data will be consumed before execution */
259         public final boolean     dataIn;
260
261         /** if true, the data consumed will be copied into the data latch */
262         public final boolean     latchData;
263
264         /** if true, the data consumed will be copied into the path latch */
265         public final boolean     latchPath;
266
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;
269
270         /** if true, the a token will be transmitted to the location in the path latch */
271         public final boolean     tokenOut;
272
273         public Move(Dock        dock,
274                     Path        path,
275                     boolean     tokenIn,
276                     boolean     dataIn,
277                     boolean     latchData,
278                     boolean     latchPath,
279                     boolean     dataOut,
280                     boolean     tokenOut
281                     ) {
282             this(dock, false, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
283         public Move(Dock        dock,
284                     boolean     looping,
285                     Predicate   predicate,
286                     boolean     interruptible,
287                     Path        path,
288                     boolean     tokenIn,
289                     boolean     dataIn,
290                     boolean     latchData,
291                     boolean     latchPath,
292                     boolean     dataOut,
293                     boolean     tokenOut
294                     ) {
295             super(dock, looping, predicate);
296             this.path = path;
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);
314         }
315
316         public String toString() {
317             StringBuffer ret = new StringBuffer();
318             if (tokenIn)                        ret.append(", recv token");
319             if (dataIn) {
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");
323             }
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+";";
331         }
332     }
333
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;"; }
338     }
339
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;"; }
344     }
345
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;"; }
350     }
351
352 }