add interpreter code and tests for loop counter instructions
[fleet.git] / src / edu / berkeley / fleet / ies44 / InstructionEncoder.java
1 package edu.berkeley.fleet.ies44;
2 import edu.berkeley.fleet.api.*;
3 import edu.berkeley.fleet.*;
4 import java.io.*;
5 import static edu.berkeley.fleet.util.BitManipulations.*;
6
7 public abstract class InstructionEncoder {
8
9     public static final int WIDTH_WORD             = 37;   /* word width */
10     public static final int WIDTH_CODEBAG_SIZE     = 6;
11     public static final int WIDTH_PUMP_ADDR        = 11;
12     public static final int WIDTH_DEST_ADDR        = 11;
13     public static final int WIDTH_COUNT            = 7;
14
15     public static final int OFFSET_MASK_LITERAL    = 20;
16     public static final int WIDTH_MASK_LITERAL     = 6;
17     public static final int MASK_LITERAL           = 13;   // this is an excessive approximation
18
19     public static final int OFFSET_MASK_MASSACRE   = 14;
20     public static final int WIDTH_MASK_MASSACRE    = 26-14;
21     public static final int MASK_MASSACRE          = 1;
22
23     public static final int OFFSET_MASK_KILL       = 14;
24     public static final int WIDTH_MASK_KILL        = 26-14;
25     public static final int MASK_KILL              = 0;
26
27     public static final int OFFSET_MASK_UNCLOG     = 14;
28     public static final int WIDTH_MASK_UNCLOG      = 26-14;
29     public static final int MASK_UNCLOG            = 3;
30
31     public static final int OFFSET_MASK_CLOG       = 14;
32     public static final int WIDTH_MASK_CLOG        = 26-14;
33     public static final int MASK_CLOG              = 2;
34
35     public static final int OFFSET_MASK_LOAD_LOOP_TO_DATA       = 14;
36     public static final int WIDTH_MASK_LOAD_LOOP_TO_DATA        = 12;
37     public static final int MASK_LOAD_LOOP_TO_DATA         = 0;
38
39     public static final int OFFSET_MASK_LOAD_LITERAL_TO_LOOP       = 14;
40     public static final int WIDTH_MASK_LOAD_LITERAL_TO_LOOP        = 12;
41     public static final int MASK_LOAD_LITERAL_TO_LOOP              = 1;
42
43     public static final int OFFSET_MASK_LOAD_LITERAL_TO_REPEAT       = 14;
44     public static final int WIDTH_MASK_LOAD_LITERAL_TO_REPEAT        = 12;
45     public static final int MASK_LOAD_LITERAL_TO_REPEAT              = 2;
46
47     public static final int OFFSET_MASK_LOAD_DATA_TO_REPEAT       = 14;
48     public static final int WIDTH_MASK_LOAD_DATA_TO_REPEAT        = 12;
49     public static final int MASK_LOAD_DATA_TO_REPEAT              = 3;
50
51     public static final int OFFSET_MASK_LOAD_DATA_TO_LOOP       = 14;
52     public static final int WIDTH_MASK_LOAD_DATA_TO_LOOP        = 12;
53     public static final int MASK_LOAD_DATA_TO_LOOP              = 4;
54
55     public static final int OFFSET_MASK_DECR_LOOP       = 14;
56     public static final int WIDTH_MASK_DECR_LOOP        = 12;
57     public static final int MASK_DECR_LOOP              = 5;
58
59     public static final int OFFSET_MASK_NORMAL     = 25;
60     public static final int WIDTH_MASK_NORMAL      = 1;
61     public static final int MASK_NORMAL            = 1;
62
63     public static final int OFFSET_COUNTER_LITERAL     = 0;
64     public static final int WIDTH_COUNTER_LITERAL      = 6;
65
66     public static final int OFFSET_COUNT           = 0;
67     public static final int OFFSET_DEST            = OFFSET_COUNT+WIDTH_COUNT;
68     public static final int OFFSET_CONTROL         = OFFSET_DEST+WIDTH_DEST_ADDR;
69     public static final int OFFSET_RQ              = OFFSET_CONTROL+0;
70     public static final int OFFSET_IG              = OFFSET_CONTROL+1;
71     public static final int OFFSET_TO              = OFFSET_CONTROL+2;
72     public static final int OFFSET_DO              = OFFSET_CONTROL+3;
73     public static final int OFFSET_DL              = OFFSET_CONTROL+4;
74     public static final int OFFSET_DI              = OFFSET_CONTROL+5;
75     public static final int OFFSET_TI              = OFFSET_CONTROL+6;
76     public static final int OFFSET_LITERAL_LOADHIGH = 19;
77     public static final int OFFSET_INSTRUCTIONTYPE = OFFSET_CONTROL+7;
78     public static final int OFFSET_PUMP_ADDR       = OFFSET_INSTRUCTIONTYPE+1;
79
80     public static final int OFFSET_LITERAL         = 0;
81     public static final int WIDTH_LITERAL          = 19;
82
83
84     /** get the bits describing this box's location on the DESTINATION HORN */
85     protected abstract long getDestAddr(Destination box);
86
87     /** get the bits describing this box's location on the INSTRUCTION HORN */
88     protected abstract long getBoxInstAddr(Pump box);
89
90     /** given an INSTRUCTION HORN address, retrieve the corresponding Pump object */
91     protected abstract Pump getBoxByInstAddr(long dest);
92     
93     /** given a DESTINATION HORN address, retrieve the corresponding Pump object */
94     protected abstract Destination getDestByAddr(long dest);
95
96     /** read a machine-formatted instruction from a file (into a Java object) */
97     public Instruction readInstruction(DataInputStream is) throws IOException {
98         long inst = 0;
99         try {
100             inst = (inst << 8) | (is.readByte() & 0xff);
101             inst = (inst << 8) | (is.readByte() & 0xff);
102             inst = (inst << 8) | (is.readByte() & 0xff);
103             inst = (inst << 8) | (is.readByte() & 0xff);
104             inst = (inst << 8) | (is.readByte() & 0xff);
105             inst = (inst << 8) | (is.readByte() & 0xff);
106             return readInstruction(inst);
107         } catch (EOFException eof) {
108             return null;
109         }
110     }
111
112     public Instruction readInstruction(long inst) {
113         Pump name           = getBoxByInstAddr(getIntField(OFFSET_PUMP_ADDR+WIDTH_PUMP_ADDR-1, OFFSET_PUMP_ADDR, inst));
114
115         int count_literal = getIntField(OFFSET_COUNTER_LITERAL+WIDTH_COUNTER_LITERAL-1, OFFSET_COUNTER_LITERAL, inst);
116         if (getIntField(OFFSET_MASK_LOAD_LOOP_TO_DATA+WIDTH_MASK_LOAD_LOOP_TO_DATA-1, OFFSET_MASK_LOAD_LOOP_TO_DATA,inst)==MASK_LOAD_LOOP_TO_DATA)
117             return new Instruction.Counter(name, Instruction.Counter.LOOP_COUNTER, Instruction.Counter.DATA_LATCH);
118         else if (getIntField(OFFSET_MASK_LOAD_DATA_TO_REPEAT+WIDTH_MASK_LOAD_DATA_TO_REPEAT-1, OFFSET_MASK_LOAD_DATA_TO_REPEAT,inst)==MASK_LOAD_DATA_TO_REPEAT)
119             return new Instruction.Counter(name, Instruction.Counter.DATA_LATCH, Instruction.Counter.REPEAT_COUNTER);
120         else if (getIntField(OFFSET_MASK_LOAD_DATA_TO_LOOP+WIDTH_MASK_LOAD_DATA_TO_LOOP-1, OFFSET_MASK_LOAD_DATA_TO_LOOP,inst)==MASK_LOAD_DATA_TO_LOOP)
121             return new Instruction.Counter(name, Instruction.Counter.DATA_LATCH, Instruction.Counter.LOOP_COUNTER);
122         else if (getIntField(OFFSET_MASK_LOAD_LITERAL_TO_LOOP+WIDTH_MASK_LOAD_LITERAL_TO_LOOP-1, OFFSET_MASK_LOAD_LITERAL_TO_LOOP,inst)==MASK_LOAD_LITERAL_TO_LOOP)
123             return new Instruction.Counter(name, count_literal, Instruction.Counter.LOOP_COUNTER);
124         else if (getIntField(OFFSET_MASK_LOAD_LITERAL_TO_REPEAT+WIDTH_MASK_LOAD_LITERAL_TO_REPEAT-1, OFFSET_MASK_LOAD_LITERAL_TO_REPEAT,inst)==MASK_LOAD_LITERAL_TO_REPEAT)
125             return new Instruction.Counter(name, count_literal, Instruction.Counter.REPEAT_COUNTER);
126         else if (getIntField(OFFSET_MASK_DECR_LOOP+WIDTH_MASK_DECR_LOOP-1, OFFSET_MASK_DECR_LOOP,inst)==MASK_DECR_LOOP)
127             return new Instruction.DecrLoop(name);
128
129         if (getIntField(OFFSET_MASK_UNCLOG+WIDTH_MASK_UNCLOG-1, OFFSET_MASK_UNCLOG,inst)==MASK_UNCLOG)
130             return new Instruction.UnClog(name);
131         if (getIntField(OFFSET_MASK_CLOG+WIDTH_MASK_CLOG-1, OFFSET_MASK_CLOG,inst)==MASK_CLOG)
132             return new Instruction.Clog(name);
133         if (getIntField(OFFSET_MASK_MASSACRE+WIDTH_MASK_MASSACRE-1, OFFSET_MASK_MASSACRE,inst)==MASK_MASSACRE)
134             return new Instruction.Massacre(name);
135         int count           = getIntField(                 OFFSET_COUNT+WIDTH_COUNT-1,         OFFSET_COUNT,     inst);
136         if (getIntField(OFFSET_MASK_KILL+WIDTH_MASK_KILL-1, OFFSET_MASK_KILL,inst)==MASK_KILL)
137             return new Instruction.Kill(name, count);
138         Destination dest    = getDestByAddr   (getIntField(OFFSET_DEST+WIDTH_DEST_ADDR-1,      OFFSET_DEST,      inst));
139         boolean tokenIn     = getBit(OFFSET_TI, inst);
140         boolean dataIn      = getBit(OFFSET_DI, inst);
141         boolean latch       = getBit(OFFSET_DL, inst);
142         boolean dataOut     = getBit(OFFSET_DO, inst);
143         boolean tokenOut    = getBit(OFFSET_TO, inst);
144         boolean requeue     = getBit(OFFSET_RQ, inst);
145         boolean ignoreUntilLast = getBit(OFFSET_IG, inst);
146         boolean dataOutDest = name.isOutbox() && dataOut && tokenOut;
147         boolean isLiteral   = getIntField(OFFSET_MASK_LITERAL+WIDTH_MASK_LITERAL-1, OFFSET_MASK_LITERAL, inst)==MASK_LITERAL;
148         if (isLiteral)
149             return new Instruction.LocalLiteral(name, getField(OFFSET_LITERAL+WIDTH_LITERAL-1, OFFSET_LITERAL, inst), 0,
150                                                 getField(OFFSET_LITERAL_LOADHIGH, OFFSET_LITERAL_LOADHIGH, inst)!=0);
151         if (dataOutDest) tokenOut = false;
152         return new Instruction.Move(name,
153                                     dest,
154                                     count,
155                                     tokenIn,
156                                     dataIn,
157                                     latch,
158                                     dataOutDest,
159                                     dataOut,
160                                     tokenOut,
161                                     requeue,
162                                     ignoreUntilLast);
163     }
164
165     public long writeInstruction(Instruction d) {
166         long instr = 0;
167
168         if (d.pump != null)
169             instr |= putField(OFFSET_PUMP_ADDR+WIDTH_PUMP_ADDR-1, OFFSET_PUMP_ADDR, getBoxInstAddr(d.pump));
170
171         if (d instanceof Instruction.CodeBagDescriptor) {
172             Instruction.CodeBagDescriptor lc = (Instruction.CodeBagDescriptor)d;
173             // MAJOR MAJOR FIXME: upper half here...
174             d = new Instruction.LocalLiteral(lc.pump, ((lc.offset << WIDTH_CODEBAG_SIZE)) | lc.size, 1, false);
175         }
176
177         if (d instanceof Instruction.UnClog) {
178             instr |= putField(OFFSET_MASK_UNCLOG+WIDTH_MASK_UNCLOG-1, OFFSET_MASK_UNCLOG,       MASK_UNCLOG);
179
180         } else if (d instanceof Instruction.Kill) {
181             Instruction.Kill k = (Instruction.Kill)d;
182             instr |= putField(OFFSET_MASK_KILL+WIDTH_MASK_KILL-1, OFFSET_MASK_KILL,       MASK_KILL);
183             instr |= putField(OFFSET_COUNT+WIDTH_COUNT-1,         OFFSET_COUNT,           k.count-1);
184
185         } else if (d instanceof Instruction.Clog) {
186             instr |= putField(OFFSET_MASK_CLOG+WIDTH_MASK_CLOG-1, OFFSET_MASK_CLOG,       MASK_CLOG);
187
188         } else if (d instanceof Instruction.Massacre) {
189             instr |= putField(OFFSET_MASK_MASSACRE+WIDTH_MASK_MASSACRE-1, OFFSET_MASK_MASSACRE,       MASK_MASSACRE);
190
191         } else if (d instanceof Instruction.LocalLiteral) {
192             Instruction.LocalLiteral inst = (Instruction.LocalLiteral)d;
193             if (inst.pump != null) {
194                 instr |= putField(OFFSET_MASK_LITERAL+WIDTH_MASK_LITERAL-1, OFFSET_MASK_LITERAL,    MASK_LITERAL);
195                 instr |= putField(OFFSET_LITERAL+WIDTH_LITERAL-1,           OFFSET_LITERAL,         inst.literal);
196                 instr |= putField(OFFSET_LITERAL_LOADHIGH, OFFSET_LITERAL_LOADHIGH, (inst.high?1:0));
197             } else {
198                 instr = inst.literal;
199             }
200
201         } else if (d instanceof Instruction.DecrLoop) {
202             instr |= putField(OFFSET_MASK_DECR_LOOP+WIDTH_MASK_DECR_LOOP-1, OFFSET_MASK_DECR_LOOP, MASK_DECR_LOOP);
203
204         } else if (d instanceof Instruction.Counter) {
205             Instruction.Counter ic = (Instruction.Counter)d;
206             if (ic.dest == Instruction.Counter.DATA_LATCH && ic.source == Instruction.Counter.LOOP_COUNTER)
207                 instr |= putField(OFFSET_MASK_LOAD_LOOP_TO_DATA+WIDTH_MASK_LOAD_LOOP_TO_DATA-1,
208                                   OFFSET_MASK_LOAD_LOOP_TO_DATA,       MASK_LOAD_LOOP_TO_DATA);
209             else if (ic.dest == Instruction.Counter.REPEAT_COUNTER && ic.source == Instruction.Counter.DATA_LATCH)
210                 instr |= putField(OFFSET_MASK_LOAD_DATA_TO_REPEAT+WIDTH_MASK_LOAD_DATA_TO_REPEAT-1,
211                                   OFFSET_MASK_LOAD_DATA_TO_REPEAT,       MASK_LOAD_DATA_TO_REPEAT);
212             else if (ic.dest == Instruction.Counter.LOOP_COUNTER && ic.source == Instruction.Counter.DATA_LATCH)
213                 instr |= putField(OFFSET_MASK_LOAD_DATA_TO_LOOP+WIDTH_MASK_LOAD_DATA_TO_LOOP-1,
214                                   OFFSET_MASK_LOAD_DATA_TO_LOOP,       MASK_LOAD_DATA_TO_LOOP);
215             else if (ic.dest == Instruction.Counter.REPEAT_COUNTER) {
216                 instr |= putField(OFFSET_MASK_LOAD_LITERAL_TO_REPEAT+WIDTH_MASK_LOAD_LITERAL_TO_REPEAT-1,
217                                   OFFSET_MASK_LOAD_LITERAL_TO_REPEAT,       MASK_LOAD_LITERAL_TO_REPEAT);
218                 instr |= putField(OFFSET_COUNTER_LITERAL+WIDTH_COUNTER_LITERAL-1,
219                                   OFFSET_COUNTER_LITERAL, ic.source);
220             } else if (ic.dest == Instruction.Counter.LOOP_COUNTER) {
221                 instr |= putField(OFFSET_MASK_LOAD_LITERAL_TO_LOOP+WIDTH_MASK_LOAD_LITERAL_TO_LOOP-1,
222                                   OFFSET_MASK_LOAD_LITERAL_TO_LOOP,       MASK_LOAD_LITERAL_TO_LOOP);
223                 instr |= putField(OFFSET_COUNTER_LITERAL+WIDTH_COUNTER_LITERAL-1,
224                                   OFFSET_COUNTER_LITERAL, ic.source);
225             } else throw new RuntimeException();
226
227         } else if (d instanceof Instruction.Move) {
228             Instruction.Move inst = (Instruction.Move)d;
229             instr |= putField(OFFSET_MASK_NORMAL+WIDTH_MASK_NORMAL-1, OFFSET_MASK_NORMAL,       MASK_NORMAL);
230             instr |= putField(OFFSET_DEST+WIDTH_DEST_ADDR-1,      OFFSET_DEST,        inst.dest==null?0:getDestAddr(inst.dest));
231             instr |= putField(OFFSET_COUNT+WIDTH_COUNT-1,         OFFSET_COUNT,       inst.count);
232             instr |= putField(OFFSET_TI,                          OFFSET_TI,          inst.tokenIn?1:0);
233             instr |= putField(OFFSET_DI,                          OFFSET_DI,          inst.dataIn?1:0);
234             instr |= putField(OFFSET_DL,                          OFFSET_DL,          inst.latch?1:0);
235             instr |= putField(OFFSET_DO,                          OFFSET_DO,          (inst.dataOutDest||inst.dataOut)?1:0);
236             instr |= putField(OFFSET_TO,                          OFFSET_TO,          (inst.dataOutDest||inst.tokenOut)?1:0);
237             instr |= putField(OFFSET_RQ,                          OFFSET_RQ,          inst.requeue?1:0);
238             instr |= putField(OFFSET_IG,                          OFFSET_IG,          inst.ignoreUntilLast?1:0);
239
240         }
241         return instr;
242     }
243
244     public void writeInstruction(DataOutputStream os, Instruction d) throws IOException {
245         long instr = writeInstruction(d);
246         for(int i=5; i>=0; i--)
247             os.write(getIntField(i*8+7, i*8, instr));
248    }
249
250 }