fix Move.toString() to print a Path (includes signal bit(s)) rather than a Destination
[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     /** the instruction's predicate */
11     public final Predicate predicate;
12
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");
16         this.dock = dock;
17         this.predicate = predicate;
18     }
19
20     //public abstract Instruction withLooping(boolean newLooping);
21     //public abstract Instruction withPredicate(Predicate newPredicate);
22
23     public String toString() {
24         String s = predicate.toString();
25         if (s.length()>0) s = "["+s+"] ";
26         return dock+": "+s;
27     }
28
29     /**
30      *  A <tt>set</tt> instruction.
31      *
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
37      *  <tt>BitVector</tt>.
38      */
39     public static class Set extends Instruction {
40
41         /** the destination (latch to be set) */
42         public final SetDest        dest;
43
44         /** the source (what will be put in the <tt>dest</tt> latch) */
45         public final SetSource      source;
46
47         /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
48         public final long           immediate;
49
50         /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
51         public final FlagFunction   newFlagA;
52
53         /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
54         public final FlagFunction   newFlagB;
55
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);
60             OUTER: switch(dest) {
61                 case InnerLoopCounter:
62                     switch(source) {
63                         case Infinity: case DataLatch: case Immediate: break OUTER;
64                         default: break;
65                     }
66                 case OuterLoopCounter:
67                     switch(source) {
68                         case Decrement: case DataLatch: case Immediate: break OUTER;
69                         default: break;
70                     }
71                 case DataLatch:
72                     if (source==SetSource.Immediate) break;
73                 default: throw new RuntimeException("cannot set " + dest + " to " + source);
74             }
75             this.source = source;
76             this.dest = dest;
77             this.immediate = 0;
78             this.newFlagA = null;
79             this.newFlagB = null;
80         }
81
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;
89             this.dest = dest;
90             this.immediate = immediate;
91             this.newFlagA = null;
92             this.newFlagB = null;
93         }
94
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;
101             this.immediate = 0;
102             this.newFlagA = newFlagA;
103             this.newFlagB = newFlagB;
104         }
105
106         /** possible sources for the Set instruction */
107         public static enum SetSource {
108             Infinity, DataLatch, Immediate, Decrement;
109         }
110         /** possible destinations for the Set instruction */
111         public static enum SetDest {
112             InnerLoopCounter, OuterLoopCounter, Flags, DataLatch;
113         }
114
115         /**
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.
120          */
121         public static class FlagFunction implements Iterable<Predicate> {
122
123             /** the function that always assigns zero */
124             public static final FlagFunction ZERO = new FlagFunction();
125
126             /** the function that always assigns one */
127             public static final FlagFunction ONE  = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
128
129             private final java.util.Set<Predicate> predicates;
130
131             public Iterator<Predicate> iterator() { return predicates.iterator(); }
132
133             private FlagFunction() { this(Collections.EMPTY_SET); }
134             private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
135
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);
140                 return ret;
141             }
142
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);
147                 switch(p) {
148                     case FlagA: case NotFlagA:
149                     case FlagB: case NotFlagB:
150                     case FlagC: case NotFlagC:
151                         break;
152                     default:
153                         throw new RuntimeException("invalid predicate in FlagFunction: " + p);
154                 }
155                 h.add(p);
156                 return new FlagFunction(h);
157             }
158
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);
163                 h.remove(p);
164                 return new FlagFunction(h);
165             }
166
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("| ");
180                         ret.append(p);
181                         empty = false;
182                     }
183                 return ret.toString();
184             }
185
186             public boolean evaluate(boolean flag_a, boolean flag_b, boolean flag_c, boolean olc_zero) {
187                 boolean ret = false;
188                 for(Predicate p : this)
189                     ret |= p.evaluate(flag_a, flag_b, flag_c, olc_zero);
190                 return ret;
191             }
192         }
193
194         public String toString() {
195             switch(dest) {
196                 case InnerLoopCounter:
197                     switch(source) {
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+";";
201                     }
202                 case OuterLoopCounter:
203                     switch(source) {
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+";";
207                     }
208                 case Flags: return super.toString()+"set flags a="+newFlagA+", b="+newFlagB+";";
209                 case DataLatch: return super.toString()+"set word="+immediate+";";
210             }
211             throw new Error("impossible");
212         }
213     }
214
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");
227         }
228         public String toString() { return super.toString()+"shift "+immediate; }
229     }
230
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");
237         }
238         public String toString() { return super.toString()+"flush;"; }
239     }
240
241     /** all communication is performed with this instruction */
242     public static class Move extends Instruction {
243
244         /** if true, this instruction is vulnerable to torpedoes */
245         public final boolean     interruptible;
246
247         /** if non-null, the path to load into the path latch */
248         public final Path        path;
249
250         /** if true, a token will be consumed before execution */
251         public final boolean     tokenIn;
252
253         /** if true, data will be consumed before execution */
254         public final boolean     dataIn;
255
256         /** if true, the data consumed will be copied into the data latch */
257         public final boolean     latchData;
258
259         /** if true, the data consumed will be copied into the path latch */
260         public final boolean     latchPath;
261
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;
264
265         /** if true, the a token will be transmitted to the location in the path latch */
266         public final boolean     tokenOut;
267
268         public Move(Dock        dock,
269                     Path        path,
270                     boolean     tokenIn,
271                     boolean     dataIn,
272                     boolean     latchData,
273                     boolean     latchPath,
274                     boolean     dataOut,
275                     boolean     tokenOut
276                     ) {
277             this(dock, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
278         public Move(Dock        dock,
279                     Predicate   predicate,
280                     boolean     interruptible,
281                     Path        path,
282                     boolean     tokenIn,
283                     boolean     dataIn,
284                     boolean     latchData,
285                     boolean     latchPath,
286                     boolean     dataOut,
287                     boolean     tokenOut
288                     ) {
289             super(dock, predicate);
290             this.path = path;
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);
308         }
309
310         public String toString() {
311             StringBuffer ret = new StringBuffer();
312             if (tokenIn)                        ret.append(", recv token");
313             if (dataIn) {
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");
318             }
319             if (dataOut && dock.isInputDock())  ret.append(", deliver");
320             if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send"  : ", send to "  + pathToString(path));
321             if (tokenOut)                       ret.append(path==null ? ", token" : ", send token to " + pathToString(path));
322             String s = ret.toString();
323             s = s.equals("") ? "nop" : s.substring(2);
324             if (interruptible) s = "[T] " + s;
325             return super.toString()+s+";";
326         }
327
328         private String pathToString(Path path) {
329             BitVector signal = path.getSignal();
330             if (signal!=null)
331                 for(int i=0; i<signal.length(); i++)
332                     if (signal.get(i))
333                         return (path.getDestination()+":"+signal.toLong());
334             return (path.getDestination()+"");
335         }
336     }
337
338     /** a flush instruction */
339     public static class Abort extends Instruction {
340         public Abort(Dock dock, Predicate predicate) { super(dock, predicate); }
341         public String toString() { return super.toString()+"abort;"; }
342     }
343
344     /** marks the start of a loop; closes the hatch */
345     public static class Head extends Instruction {
346         public Head(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
347         public String toString() { return dock+": head;"; }
348     }
349
350     /** marks the end of a loop; closes the hatch */
351     public static class Tail extends Instruction {
352         public Tail(Dock dock) { super(dock, Predicate.IgnoreFlagD); }
353         public String toString() { return dock+": tail;"; }
354     }
355
356 }