total overhaul: fleetcode-1.0 api finished
[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 String toString() {
25         String s = predicate.toString();
26         if (s.length()>0) s = "["+s+"] ";
27         return s+dock+": ";
28     }
29
30     /**
31      *  A <tt>set</tt> instruction.
32      *
33      *  Note that immediates are supplied as Java <tt>long</tt> values
34      *  because they are actual integers with two's complement
35      *  sign-extension semantics.  This is in contrast to most other
36      *  immediate values in the API which are raw bit sequences of
37      *  fixed length -- these are represented by instances of
38      *  <tt>BitVector</tt>.
39      */
40     public static class Set extends Instruction {
41
42         /** the destination (latch to be set) */
43         public final SetDest        dest;
44
45         /** the source (what will be put in the <tt>dest</tt> latch) */
46         public final SetSource      source;
47
48         /** if <tt>source</tt> is <tt>Immediate</tt>, this is the immediate value; an integer */
49         public final long           immediate;
50
51         /** if <tt>source</tt> is <tt>ImmediatePath</tt>, this is the immediate path */
52         public final Path           path;
53
54         /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "a" */
55         public final FlagFunction   newFlagA;
56
57         /** if <tt>dest</tt> is <tt>Flags</tt>, this is the truth table to update flag "b" */
58         public final FlagFunction   newFlagB;
59
60         /** basic constructor */
61         public Set(Dock dock, boolean looping, Predicate predicate, SetDest dest, SetSource source) {
62             super(dock, looping, predicate);
63             OUTER: switch(dest) {
64                 case InnerLoopCounter:
65                     switch(source) {
66                         case Infinity: case DataLatch: case Immediate: break OUTER;
67                         default: break;
68                     }
69                 case OuterLoopCounter:
70                     switch(source) {
71                         case Decrement: case DataLatch: case Immediate: break OUTER;
72                         default: break;
73                     }
74                 case DataLatch:
75                     if (source==SetSource.Immediate) break;
76                 default: throw new RuntimeException("cannot set " + dest + " to " + source);
77             }
78             this.source = source;
79             this.dest = dest;
80             this.immediate = 0;
81             this.path = null;
82             this.newFlagA = null;
83             this.newFlagB = null;
84         }
85
86         /** constructor for set instructions with immediates */
87         public Set(Dock dock, boolean looping, Predicate predicate, SetDest dest, long immediate) {
88             super(dock, looping, predicate);
89             if (dest!=SetDest.InnerLoopCounter && dest!=SetDest.OuterLoopCounter && dest!=SetDest.DataLatch)
90                 throw new RuntimeException("a set instruction with dest="+dest+" may not take an immediate");
91             this.source = SetSource.Immediate;
92             this.dest = dest;
93             this.immediate = immediate;
94             this.path = null;
95             this.newFlagA = null;
96             this.newFlagB = null;
97         }
98
99         /** constructor for set instructions with immediate paths */
100         public Set(Dock dock, boolean looping, Predicate predicate, SetDest dest, Path path) {
101             super(dock, looping, predicate);
102             if (dest!=SetDest.TAPL)
103                 throw new RuntimeException("a set instruction with dest="+dest+" may not take an immediate path");
104             this.source = SetSource.ImmediatePath;
105             this.dest = dest;
106             this.immediate = 0;
107             this.path = path;
108             this.newFlagA = null;
109             this.newFlagB = null;
110         }
111
112         /** constructor for <tt>set flags</tt> instructions */
113         public Set(Dock dock, boolean looping, Predicate predicate, FlagFunction newFlagA, FlagFunction newFlagB) {
114             super(dock, looping, predicate);
115             this.source = SetSource.Immediate;
116             this.dest = SetDest.Flags;
117             this.immediate = 0;
118             this.path = null;
119             this.newFlagA = newFlagA;
120             this.newFlagB = newFlagB;
121         }
122
123         /** possible sources for the Set instruction */
124         public static enum SetSource {
125             Infinity, DataLatch, Immediate, ImmediatePath, Decrement;
126         }
127         /** possible destinations for the Set instruction */
128         public static enum SetDest {
129             InnerLoopCounter, OuterLoopCounter, TAPL, Flags, DataLatch;
130         }
131
132         /**
133          *  (Immutable) a truth table describing how to update a flag
134          *  based on the value of other flags; it is the logical OR of
135          *  a set of flag predicates.  This class is immutable; all
136          *  methods that alter the function return a new object.
137          */
138         public static class FlagFunction implements Iterable<Predicate> {
139
140             /** the function that always assigns zero */
141             public static final FlagFunction ZERO = new FlagFunction();
142
143             /** the function that always assigns one */
144             public static final FlagFunction ONE  = ZERO.add(Predicate.FlagA).add(Predicate.NotFlagA);
145
146             private final java.util.Set<Predicate> predicates;
147
148             public Iterator<Predicate> iterator() { return predicates.iterator(); }
149
150             private FlagFunction() { this(Collections.EMPTY_SET); }
151             private FlagFunction(java.util.Set<Predicate> set) { this.predicates = Collections.unmodifiableSet(set); }
152
153             /** returns the function which is the logical OR of this function and <tt>ff</tt> */
154             public FlagFunction add(FlagFunction ff) {
155                 FlagFunction ret = this;
156                 for(Predicate p : ff) ret = ret.add(p);
157                 return ret;
158             }
159
160             /** returns the function which is the logical OR of this function and <tt>p</tt> */
161             public FlagFunction add(Predicate p) {
162                 HashSet h = new HashSet();
163                 h.addAll(predicates);
164                 switch(p) {
165                     case FlagA: case NotFlagA:
166                     case FlagB: case NotFlagB:
167                     case FlagC: case NotFlagC:
168                         break;
169                     default:
170                         throw new RuntimeException("invalid predicate in FlagFunction: " + p);
171                 }
172                 h.add(p);
173                 return new FlagFunction(h);
174             }
175
176             /** remove <tt>p</tt> from the set of terms which this function is the logical OR of */
177             public FlagFunction remove(Predicate p) {
178                 HashSet h = new HashSet();
179                 h.addAll(predicates);
180                 h.remove(p);
181                 return new FlagFunction(h);
182             }
183
184             public String toString() {
185                 if (predicates.isEmpty()) return "0";
186                 if (predicates.contains(Predicate.FlagA) && predicates.contains(Predicate.NotFlagA)) return "1";
187                 if (predicates.contains(Predicate.FlagB) && predicates.contains(Predicate.NotFlagB)) return "1";
188                 if (predicates.contains(Predicate.FlagC) && predicates.contains(Predicate.NotFlagC)) return "1";
189                 StringBuffer ret = new StringBuffer();
190                 boolean empty = true;
191                 for(Predicate p : new Predicate[] {
192                         Predicate.FlagA, Predicate.NotFlagA,
193                         Predicate.FlagB, Predicate.NotFlagB,
194                         Predicate.FlagC, Predicate.NotFlagC })
195                     if (predicates.contains(p)) {
196                         if (!empty) ret.append("| ");
197                         ret.append(p);
198                         empty = false;
199                     }
200                 return ret.toString();
201             }
202         }
203
204         public String toString() {
205             switch(dest) {
206                 case InnerLoopCounter:
207                     switch(source) {
208                         case Infinity: return super.toString()+"set ilc=*";
209                         case DataLatch: return super.toString()+"set ilc=data";
210                         case Immediate: return super.toString()+"set ilc="+immediate;
211                     }
212                 case OuterLoopCounter:
213                     switch(source) {
214                         case Decrement: return super.toString()+"set olc--";
215                         case DataLatch: return super.toString()+"set olc=data";
216                         case Immediate: return super.toString()+"set olc="+immediate;
217                     }
218                 case TAPL: return super.toString()+"set tapl="+path;
219                 case Flags: return super.toString()+"set flags a="+newFlagA+" b="+newFlagB;
220                 case DataLatch: return super.toString()+"set data="+immediate;
221             }
222             throw new Error("impossible");
223         }
224     }
225
226     /** shifts an immediate into the low-order bits of the data latch */
227     public static class Shift extends Instruction {
228         public final BitVector immediate;
229         public Shift(Dock dock, boolean looping, Predicate predicate, BitVector immediate) {
230             super(dock, looping, predicate);
231             this.immediate = immediate;
232         }
233         public String toString() { return super.toString()+"shift "+immediate; }
234     }
235
236     /** all communication is performed with this instruction */
237     public static class Move extends Instruction {
238
239         /** if true, this instruction is vulnerable to torpedoes */
240         public final boolean     interruptible;
241
242         /** if non-null, the path to load into the path latch */
243         public final Path        path;
244
245         /** if true, a token will be consumed before execution */
246         public final boolean     tokenIn;
247
248         /** if true, data will be consumed before execution */
249         public final boolean     dataIn;
250
251         /** if true, the data consumed will be copied into the data latch */
252         public final boolean     latchData;
253
254         /** if true, the data consumed will be copied into the path latch */
255         public final boolean     latchPath;
256
257         /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
258         public final boolean     dataOut;
259
260         /** if true, the a token will be transmitted to the location in the path latch */
261         public final boolean     tokenOut;
262
263         public Move(Dock        dock,
264                     boolean     looping,
265                     Predicate   predicate,
266                     boolean     interruptible,
267                     Path        path,
268                     boolean     tokenIn,
269                     boolean     dataIn,
270                     boolean     latchData,
271                     boolean     latchPath,
272                     boolean     dataOut,
273                     boolean     tokenOut
274                     ) {
275             super(dock, looping, predicate);
276             this.path = path;
277             this.tokenIn = tokenIn;
278             this.dataIn = dataIn;
279             this.latchData = latchData;
280             this.latchPath = latchPath;
281             this.dataOut = dataOut;
282             this.tokenOut = tokenOut;
283             this.interruptible = interruptible;
284             if (dock != null && dock.isInputDock() && tokenIn && dataIn)
285                 throw new RuntimeException("cannot have both \"wait\" and \"take\"/\"recieve\" on an input dock: " + this);
286             if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
287                 throw new RuntimeException("cannot have both \"sendto\" and \"notify\" on an output dock: " + this);
288             if (latchData && !dataIn)
289                 throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
290             if (latchPath && !dataIn)
291                 throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
292             if (latchPath && path!=null)
293                 throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
294         }
295
296         public String toString() {
297             StringBuffer ret = new StringBuffer();
298             if (tokenIn)                        ret.append(", wait");
299             if (dataIn) {
300                 if (latchPath)                  ret.append(dock.isInputDock() ? ", collect path" : ", recv path");
301                 if (latchData)                  ret.append(dock.isInputDock() ? ", collect"      : ", recv");
302                 if (!latchPath && !latchData)   ret.append(", discard");
303             }
304             if (dataOut && dock.isInputDock())  ret.append(", deliver");
305             if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send"  : "sendto "  + path);
306             if (tokenOut)                       ret.append(path==null ? ", token" : "tokento " + path);
307             String s = ret.toString();
308             s = s.equals("") ? "nop" : s.substring(2);
309             if (interruptible) s = "[i] " + s;
310             return super.toString()+s;
311         }
312     }
313
314     /** marks the end of a loop; closes the hatch */
315     public static class Tail extends Instruction {
316         public Tail(Dock dock) { super(dock, false, Predicate.IgnoreOLC); }
317         public String toString() { return super.toString() + "tail;"; }
318     }
319
320 }