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