works
[fleet.git] / testCode / 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 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");
228                         return ret;
229                     }
230                 };
231         }
232         public String toString() { return super.toString()+"shift "+immediate.getBitVector(); }
233     }
234
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");
241         }
242         public String toString() { return super.toString()+"flush;"; }
243     }
244
245     /** all communication is performed with this instruction */
246     public static class Move extends Instruction {
247
248         /** if true, this instruction is vulnerable to torpedoes */
249         public final boolean     interruptible;
250
251         /** if non-null, the path to load into the path latch */
252         public final Path        path;
253
254         /** if true, a token will be consumed before execution */
255         public final boolean     tokenIn;
256
257         /** if true, data will be consumed before execution */
258         public final boolean     dataIn;
259
260         /** if true, the data consumed will be copied into the data latch */
261         public final boolean     latchData;
262
263         /** if true, the data consumed will be copied into the path latch */
264         public final boolean     latchPath;
265
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;
268
269         /** if true, the a token will be transmitted to the location in the path latch */
270         public final boolean     tokenOut;
271
272         public Move(Dock        dock,
273                     Path        path,
274                     boolean     tokenIn,
275                     boolean     dataIn,
276                     boolean     latchData,
277                     boolean     latchPath,
278                     boolean     dataOut,
279                     boolean     tokenOut
280                     ) {
281             this(dock, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
282         public Move(Dock        dock,
283                     Predicate   predicate,
284                     boolean     interruptible,
285                     Path        path,
286                     boolean     tokenIn,
287                     boolean     dataIn,
288                     boolean     latchData,
289                     boolean     latchPath,
290                     boolean     dataOut,
291                     boolean     tokenOut
292                     ) {
293             super(dock, predicate);
294             this.path = path;
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);
312         }
313
314         public String toString() {
315             StringBuffer ret = new StringBuffer();
316             if (tokenIn)                        ret.append(", recv token");
317             if (dataIn) {
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");
322             }
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 ? ", send 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+";";
330         }
331
332         private String pathToString(Path path) {
333             BitVector signal = path.getSignal();
334             if (signal!=null)
335                 for(int i=0; i<signal.length(); i++)
336                     if (signal.get(i))
337                         return (path.getDestination()+":"+signal.toLong());
338             return (path.getDestination()+"");
339         }
340     }
341
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;"; }
346     }
347
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;"; }
352     }
353
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;"; }
358     }
359
360 }