add interpreter code and tests for loop counter instructions
[fleet.git] / src / edu / berkeley / fleet / api / Instruction.java
1 package edu.berkeley.fleet.api;
2
3 public abstract class Instruction {
4
5     public final Pump pump;
6     public Instruction(Pump pump) { this.pump = pump; }
7     public String toString() { return pump+": "; }
8
9     public static abstract class CountingInstruction extends Instruction {
10         public final int count;
11         public CountingInstruction(Pump pump, int count) {
12             super(pump);
13             this.count = count;
14         }
15         public boolean isStanding() { return count==0; }
16         public abstract boolean isRequeueing();
17         public String toString() { return super.toString()+(count==1?"":(isRequeueing()?("("+(count==0?"*":(count+""))+")"):("["+(count==0?"*":(count+""))+"]")))+" "; }
18     }
19
20     public static class UnClog extends Instruction {
21         public UnClog(Pump pump) { super(pump); }
22         public String toString() { return super.toString() + "unclog;"; }
23     }
24
25     public static class Massacre extends Instruction {
26         public Massacre(Pump pump) { super(pump); }
27     }
28
29     public static class Clog extends Executable {
30         public Clog(Pump pump) { super(pump, 1); }
31         public String toString() { return super.toString() + "clog;"; }
32         public Instruction.Executable decrementCount() { return null; }
33         public boolean isRequeueing() { return false; }
34     }
35
36     public static class Kill extends CountingInstruction {
37         public Kill(Pump pump, int count) { super(pump, count); }
38         public boolean isRequeueing() { return false; }
39         public String toString() { return super.toString() + "kill;"; }
40     }
41
42     public static abstract class Executable extends CountingInstruction {
43         public Executable(Pump pump, int count) { super(pump, count); }
44         public abstract Instruction.Executable decrementCount();
45     }
46
47     public static class DecrLoop extends Executable {
48         public DecrLoop(Pump pump) { super(pump, 1); }
49         public Instruction.Executable decrementCount() { return null; }
50         public boolean isRequeueing() { return false; }
51     }
52
53     public static class Counter extends Executable {
54         public static final int DATA_LATCH = -1;
55         public static final int REPEAT_COUNTER = -2;
56         public static final int LOOP_COUNTER = -3;
57         public final int source;
58         public final int dest;
59         public Instruction.Executable decrementCount() { return null; }
60         public boolean isRequeueing() { return false; }
61         public Counter(Pump pump, int source, int dest) {
62             super(pump, 1);
63             this.source = source;
64             this.dest = dest;
65         }
66         public String toString() {
67             if (source==LOOP_COUNTER && dest==DATA_LATCH) return "take loop counter;";
68             StringBuffer ret = new StringBuffer();
69             ret.append("load ");
70             switch(dest) {
71                 case LOOP_COUNTER: ret.append("loop"); break;
72                 case REPEAT_COUNTER: ret.append("repeat"); break;
73                 default: throw new RuntimeException("invalid");
74             }
75             ret.append(" counter");
76             if (source >= 0) {
77                 ret.append(" with " + source);
78             } else if (source!=DATA_LATCH) {
79                 throw new RuntimeException("invalid");
80             }
81             ret.append(";");
82             return ret.toString();
83         }
84     }
85
86     public static class Move extends Executable {
87         public final Destination dest;
88
89         public final boolean     tokenIn;
90         public final boolean     dataIn;
91         public final boolean     latch;
92         public final boolean     dataOutDest;
93         public final boolean     dataOut;
94         public final boolean     tokenOut;
95         public final boolean     requeue;
96         public final boolean     ignoreUntilLast;
97
98         public boolean isRequeueing() { return requeue; }
99
100         /** count=0 denotes a standing move */
101         public Move(Pump        pump,
102                           Destination dest,
103                           int         count,
104                           boolean     tokenIn,
105                           boolean     dataIn,
106                           boolean     latch,
107                           boolean     dataOutDest,
108                           boolean     dataOut,
109                           boolean     tokenOut,
110                           boolean     requeue,
111                           boolean     ignoreUntilLast) {
112             super(pump, count);
113             this.dest = dest;
114             this.tokenIn = tokenIn;
115             this.dataIn = dataIn;
116             this.latch = latch;
117             this.dataOutDest = dataOutDest;
118             this.dataOut = dataOut;
119             this.tokenOut = tokenOut;
120             this.requeue = requeue;
121             this.ignoreUntilLast = ignoreUntilLast;
122             if (count < 0)
123                 throw new RuntimeException("count field of an instruction must be >=0");
124             if (pump.isInbox() && tokenIn && dataIn)
125                 throw new RuntimeException("cannot have both \"wait\" and \"take\"/\"recieve\" on an inbox: " + this);
126             if (pump.isOutbox() && tokenOut && dataOut)
127                 throw new RuntimeException("cannot have both \"sendto\" and \"notify\" on an outbox: " + this);
128             if (latch && !dataIn)
129                 throw new RuntimeException("cannot have latch bit set without dataIn bit: " + this);
130         }
131
132         public Instruction.Executable decrementCount() {
133             if (count==1) return null;
134             return new Move(pump, dest, count==0 ? 0 : count-1,
135                             tokenIn, dataIn, latch, dataOutDest, dataOut, tokenOut, requeue, ignoreUntilLast);
136         }
137
138         public String toString() {
139             // FIXME
140             String ret = super.toString();
141             boolean needcomma = false;
142             if (tokenIn)           { ret += (needcomma ? ", " : "") + "wait";    needcomma = true; }
143             if (dataIn && latch)  {
144                 if (pump.isInbox())
145                     ret += (needcomma ? ", " : "") + "receive";
146                 else
147                     ret += (needcomma ? ", " : "") + "take";
148                 needcomma = true;
149             }
150             if (dataIn && !latch)  { ret += (needcomma ? ", " : "") + "dismiss"; needcomma = true; }
151             if (dataOut)  {
152                 if (pump.isInbox() || dest==null)
153                     ret += (needcomma ? ", " : "") + "deliver";
154                 else
155                     ret += (needcomma ? ", " : "") + "sendto "+dest;
156                 needcomma = true;
157             }
158             if (tokenOut) { ret += (needcomma ? ", " : "") + "notify "+dest; needcomma = true; }
159             return ret;
160         }
161
162     }
163
164     public static class LocalLiteral extends Executable {
165         public final long literal;
166         public final boolean high;
167         public boolean isRequeueing() { return true; }
168         public LocalLiteral(Pump pump, long literal, int count, boolean high) {
169             super(pump, count);
170             this.literal = literal;
171             this.high = high;
172         }
173         public Instruction.Executable decrementCount() {
174             if (count==1) return null;
175             return new LocalLiteral(pump, literal, count-1, high);
176         }
177     }
178
179     public static class CodeBagDescriptor extends Instruction {
180         /** address of CBD, relative to address that this instruction was loaded from */
181         public final long offset;
182         public final long size;
183         public CodeBagDescriptor(Pump pump, long offset, long size) {
184             super(pump);
185             this.offset = offset;
186             this.size = size;
187         }
188         public String toString() {
189             String off = ""+offset;
190             if (offset > 0) off = "+"+off;
191             return "(CBD @"+off+"+"+size+"): sendto " + pump;
192         }
193     }
194
195 }