better comment on Instruction.Flush()
[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             if (immediate.length() != dock.getShip().getFleet().getShiftWidth())
222                 throw new RuntimeException("attempt to create a Shift instruction with a "+immediate.length()+
223                                            "-bit immediate on a Fleet that uses "+dock.getShip().getFleet().getShiftWidth()+
224                                            "-bit shift instructions");
225         }
226         public String toString() { return super.toString()+"shift "+immediate; }
227     }
228
229     /** a flush instruction */
230     public static class Flush extends Instruction {
231         public Flush(Dock dock) { this(dock, false, Predicate.Default); }
232         public Flush(Dock dock, boolean looping, Predicate predicate) {
233             super(dock, looping, predicate);
234             if (!dock.isInputDock()) throw new RuntimeException("Flush is only allowed at input docks");
235         }
236         public String toString() { return super.toString()+"flush"; }
237     }
238
239     /** all communication is performed with this instruction */
240     public static class Move extends Instruction {
241
242         /** if true, this instruction is vulnerable to torpedoes */
243         public final boolean     interruptible;
244
245         /** if non-null, the path to load into the path latch */
246         public final Path        path;
247
248         /** if true, a token will be consumed before execution */
249         public final boolean     tokenIn;
250
251         /** if true, data will be consumed before execution */
252         public final boolean     dataIn;
253
254         /** if true, the data consumed will be copied into the data latch */
255         public final boolean     latchData;
256
257         /** if true, the data consumed will be copied into the path latch */
258         public final boolean     latchPath;
259
260         /** if true, the value in the data latch will be transmitted (to the location in the path latch if at an output dock) */
261         public final boolean     dataOut;
262
263         /** if true, the a token will be transmitted to the location in the path latch */
264         public final boolean     tokenOut;
265
266         public Move(Dock        dock,
267                     Path        path,
268                     boolean     tokenIn,
269                     boolean     dataIn,
270                     boolean     latchData,
271                     boolean     latchPath,
272                     boolean     dataOut,
273                     boolean     tokenOut
274                     ) {
275             this(dock, false, Predicate.Default, false, path, tokenIn, dataIn, latchData, latchPath, dataOut, tokenOut); }
276         public Move(Dock        dock,
277                     boolean     looping,
278                     Predicate   predicate,
279                     boolean     interruptible,
280                     Path        path,
281                     boolean     tokenIn,
282                     boolean     dataIn,
283                     boolean     latchData,
284                     boolean     latchPath,
285                     boolean     dataOut,
286                     boolean     tokenOut
287                     ) {
288             super(dock, looping, predicate);
289             this.path = path;
290             this.tokenIn = tokenIn;
291             this.dataIn = dataIn;
292             this.latchData = latchData;
293             this.latchPath = latchPath;
294             this.dataOut = dataOut;
295             this.tokenOut = tokenOut;
296             this.interruptible = interruptible;
297             if (dock != null && dock.isInputDock() && tokenIn && dataIn)
298                 throw new RuntimeException("cannot have two \"recv\"s: " + this);
299             if (dock != null && dock.isOutputDock() && tokenOut && dataOut)
300                 throw new RuntimeException("cannot have two \"send\"s: " + this);
301             if (latchData && !dataIn)
302                 throw new RuntimeException("cannot have latchData bit set without dataIn bit: " + this);
303             if (latchPath && !dataIn)
304                 throw new RuntimeException("cannot have latchPath bit set without dataIn bit: " + this);
305             if (latchPath && path!=null)
306                 throw new RuntimeException("cannot have latchPath and a non-null path: " + this);
307         }
308
309         public String toString() {
310             StringBuffer ret = new StringBuffer();
311             if (tokenIn)                        ret.append(", recv token");
312             if (dataIn) {
313                 if (latchPath)                  ret.append(!dock.isInputDock() ? ", collect path" : ", recv path");
314                 if (latchData)                  ret.append(!dock.isInputDock() ? ", collect"      : ", recv");
315                 if (!latchPath && !latchData)   ret.append(", discard");
316             }
317             if (dataOut && dock.isInputDock())  ret.append(", deliver");
318             if (dataOut && !dock.isInputDock()) ret.append(path==null ? ", send"  : ", send to "  + path.getDestination().getDock());
319             if (tokenOut)                       ret.append(path==null ? ", token" : ", send token to " + path.getDestination().getDock());
320             String s = ret.toString();
321             s = s.equals("") ? "nop" : s.substring(2);
322             if (interruptible) s = "[T] " + s;
323             return super.toString()+s+";";
324         }
325     }
326
327     /** marks the end of a loop; closes the hatch */
328     public static class Tail extends Instruction {
329         public Tail(Dock dock) { super(dock, false, Predicate.IgnoreOLC); }
330         public String toString() { return dock+": tail;"; }
331     }
332
333 }