remove TAPL, improve Instruction.toString(), add convenience constructors to Instruction
[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 += "[L] ";
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
192         public String toString() {
193             switch(dest) {
194                 case InnerLoopCounter:
195                     switch(source) {
196                         /*
197                         case Infinity: return super.toString()+"set ilc=*";
198                         case DataLatch: return super.toString()+"set ilc=data";
199                         case Immediate: return super.toString()+"set ilc="+immediate;
200                         */
201                         case Infinity: return super.toString()+"load repeat counter with *;";
202                         case DataLatch: return super.toString()+"set ilc=data";
203                         case Immediate: return super.toString()+"load repeat counter with "+immediate+";";
204                     }
205                 case OuterLoopCounter:
206                     switch(source) {
207                         /*
208                         case Decrement: return super.toString()+"set olc--";
209                         case DataLatch: return super.toString()+"set olc=data";
210                         case Immediate: return super.toString()+"set olc="+immediate;
211                         */
212                         case Decrement: return super.toString()+"decrement loop counter;";
213                         case DataLatch: return super.toString()+"set olc=data;";
214                         case Immediate: return super.toString()+"load loop counter with "+immediate+";";
215                     }
216                 case Flags: return super.toString()+"set flags a="+newFlagA+" b="+newFlagB;
217                 case DataLatch: return super.toString()+"literal "+immediate+";";
218             }
219             throw new Error("impossible");
220         }
221     }
222
223     /** shifts an immediate into the low-order bits of the data latch */
224     public static class Shift extends Instruction {
225         public final BitVector immediate;
226         public Shift(Dock dock, BitVector immediate) { this(dock, false, Predicate.Default, immediate); }
227         public Shift(Dock dock, boolean looping, Predicate predicate, BitVector immediate) {
228             super(dock, looping, predicate);
229             this.immediate = immediate;
230             this.immediate.setImmutable();
231         }
232         public String toString() { return super.toString()+"shift "+immediate; }
233     }
234
235     /** all communication is performed with this instruction */
236     public static class Move extends Instruction {
237
238         /** if true, this instruction is vulnerable to torpedoes */
239         public final boolean     interruptible;
240
241         /** if non-null, the path to load into the path latch */
242         public final Path        path;
243
244         /** if true, a token will be consumed before execution */
245         public final boolean     tokenIn;
246
247         /** if true, data will be consumed before execution */
248         public final boolean     dataIn;
249
250         /** if true, the data consumed will be copied into the data latch */
251         public final boolean     latchData;
252
253         /** if true, the data consumed will be copied into the path latch */
254         public final boolean     latchPath;
255
256         /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
257         public final boolean     dataOut;
258
259         /** if true, the a token will be transmitted to the location in the path latch */
260         public final boolean     tokenOut;
261
262         public Move(Dock        dock,
263                     Path        path,
264                     boolean     tokenIn,
265                     boolean     dataIn,
266                     boolean     latchData,
267                     boolean     latchPath,
268                     boolean     dataOut,
269                     boolean     tokenOut
270                     ) {
271             this(dock, false, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
272         public Move(Dock        dock,
273                     boolean     looping,
274                     Predicate   predicate,
275                     boolean     interruptible,
276                     Path        path,
277                     boolean     tokenIn,
278                     boolean     dataIn,
279                     boolean     latchData,
280                     boolean     latchPath,
281                     boolean     dataOut,
282                     boolean     tokenOut
283                     ) {
284             super(dock, looping, predicate);
285             this.path = path;
286             this.tokenIn = tokenIn;
287             this.dataIn = dataIn;
288             this.latchData = latchData;
289             this.latchPath = latchPath;
290             this.dataOut = dataOut;
291             this.tokenOut = tokenOut;
292             this.interruptible = interruptible;
293             if (dock != null && dock.isInputDock() && tokenIn && dataIn)
294                 throw new RuntimeException("cannot have both \"wait\" and \"take\"/\"recieve\" on an input dock: " + this);
295             if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
296                 throw new RuntimeException("cannot have both \"sendto\" and \"notify\" on an output dock: " + this);
297             if (latchData && !dataIn)
298                 throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
299             if (latchPath && !dataIn)
300                 throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
301             if (latchPath && path!=null)
302                 throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
303         }
304
305         public String toString() {
306             StringBuffer ret = new StringBuffer();
307             if (tokenIn)                        ret.append(", wait");
308             if (dataIn) {
309                 if (latchPath)                  ret.append(!dock.isInputDock() ? ", collect path" : ", recv path");
310                 if (latchData)                  ret.append(!dock.isInputDock() ? ", collect"      : ", recv");
311                 if (!latchPath && !latchData)   ret.append(", discard");
312             }
313             if (dataOut && dock.isInputDock())  ret.append(", deliver");
314             if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send"  : ", sendto "  + path.getDestination().getDock());
315             if (tokenOut)                       ret.append(path==null ? ", token" : ", notify " + path.getDestination().getDock());
316             String s = ret.toString();
317             s = s.equals("") ? "nop" : s.substring(2);
318             if (interruptible) s = "[i] " + s;
319             return super.toString()+s+";";
320         }
321     }
322
323     /** marks the end of a loop; closes the hatch */
324     public static class Tail extends Instruction {
325         public Tail(Dock dock) { super(dock, false, Predicate.IgnoreOLC); }
326         public String toString() { return super.toString() + "tail;"; }
327     }
328
329 }