use Mask.signExtend()
[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 edu.berkeley.fleet.util.*;
5 import java.io.*;
6 import static edu.berkeley.fleet.util.BitManipulations.*;
7 import static edu.berkeley.fleet.api.Instruction.*;
8 import static edu.berkeley.fleet.api.Instruction.Counter.*;
9
10 public abstract class InstructionEncoder {
11
12     public static final int WIDTH_WORD             = 37;
13     public static final int WIDTH_ADDR             = 11;
14     public static final int WIDTH_CODEBAG_SIZE     = 6;
15     public static final int WIDTH_COUNTER_LITERAL  = 6;
16
17     public static final Mask FLAGS                = new Mask("...............000000................");
18     public static final Mask FLAGS_A              = new Mask("...............000000vvvvvvvv........");
19     public static final Mask FLAGS_B              = new Mask("...............000000........vvvvvvvv");
20     public static final Mask REPEAT_FROM_DATA     = new Mask("...............000001........00......");
21     public static final Mask REPEAT_FROM_LITERAL  = new Mask("...............000001........10vvvvvv");
22     public static final Mask REPEAT_FROM_STANDING = new Mask("...............000001........11......");
23     public static final Mask LOOP_FROM_DATA       = new Mask("...............000010.........0......");
24     public static final Mask LOOP_FROM_LITERAL    = new Mask("...............000010.........1vvvvvv");
25     public static final Mask TAKE_LOOP            = new Mask("...............000011................");
26     public static final Mask KILL                 = new Mask("...............000100................");
27     public static final Mask MASSACRE             = new Mask("...............000101................");
28     public static final Mask CLOG                 = new Mask("...............000110................");
29     public static final Mask UNCLOG               = new Mask("...............000111................");
30
31     public static final Mask SK                  = new Mask("...........1.........................");
32     public static final Mask DL                  = new Mask("............1........................");
33     public static final Mask P                   = new Mask(".............vv......................");
34     public static final Mask P_A                 = new Mask(".............00......................");
35     public static final Mask P_B                 = new Mask(".............10......................");
36     public static final Mask P_Z                 = new Mask(".............01......................");
37     public static final Mask P_ALWAYS            = new Mask(".............11......................");
38     public static final Mask MOVE                = new Mask("...............001...................");
39     public static final Mask TI                  = new Mask("....................1................");
40     public static final Mask DI                  = new Mask(".....................1...............");
41     public static final Mask DC                  = new Mask("......................1..............");
42     public static final Mask DO                  = new Mask(".......................1.............");
43     public static final Mask TO                  = new Mask("........................1............");
44     public static final Mask PATH_LITERAL        = new Mask(".........................1vvvvvvvvvvv");
45     public static final Mask PATH_DATA           = new Mask(".........................01..........");
46     public static final Mask PATH_NOCHANGE       = new Mask(".........................00..........");
47
48     public static final Mask TOP_HALF_LITERAL    = new Mask("vvvvvvvvvvvvvvvvvv...................");
49     public static final Mask BOT_HALF_LITERAL    = new Mask("..................vvvvvvvvvvvvvvvvvvv");
50     public static final Mask TOP_HALF_ONE        = new Mask("111111111111111111...................");
51     public static final Mask BOT_HALF_ONE        = new Mask("..................1111111111111111111");
52     public static final Mask LITERAL_LO          = new Mask("...............010vvvvvvvvvvvvvvvvvvv");
53     public static final Mask LITERAL_HI          = new Mask("...............011vvvvvvvvvvvvvvvvvvv");
54     public static final Mask LITERAL             = new Mask("...............1..vvvvvvvvvvvvvvvvvvv");
55     public static final Mask LITERAL_SEL         = new Mask("................vv...................");
56     public static final Mask LITERAL_LOW_ZERO    = new Mask("...............100...................");
57     public static final Mask LITERAL_LOW_ONE     = new Mask("...............101...................");
58     public static final Mask LITERAL_HIGH_ZERO   = new Mask("...............110...................");
59     public static final Mask LITERAL_HIGH_ONE    = new Mask("...............111...................");
60     public static final Mask PUMP_NAME           = new Mask("vvvvvvvvvvv..........................");
61
62
63     /** get the bits describing this box's location on the DESTINATION HORN */
64     protected abstract long getDestAddr(Destination box);
65
66     /** get the bits describing this box's location on the INSTRUCTION HORN */
67     protected abstract long getBoxInstAddr(Pump box);
68
69     /** given an INSTRUCTION HORN address, retrieve the corresponding Pump object */
70     protected abstract Pump getBoxByInstAddr(long dest);
71     
72     /** given a DESTINATION HORN address, retrieve the corresponding Pump object */
73     protected abstract Destination getDestByAddr(long dest);
74
75     /** read a machine-formatted instruction from a file (into a Java object) */
76     public Instruction readInstruction(DataInputStream is) throws IOException {
77         long inst = 0;
78         try {
79             inst = (inst << 8) | (is.readByte() & 0xff);
80             inst = (inst << 8) | (is.readByte() & 0xff);
81             inst = (inst << 8) | (is.readByte() & 0xff);
82             inst = (inst << 8) | (is.readByte() & 0xff);
83             inst = (inst << 8) | (is.readByte() & 0xff);
84             inst = (inst << 8) | (is.readByte() & 0xff);
85             return readInstruction(inst);
86         } catch (EOFException eof) {
87             return null;
88         }
89     }
90
91     public Instruction readInstruction(long inst) {
92         Pump name           = getBoxByInstAddr(PUMP_NAME.getval(inst));
93
94         if (UNCLOG.get(inst))   return new Instruction.UnClog(name);
95         if (CLOG.get(inst))     return new Instruction.Clog(name);
96         if (MASSACRE.get(inst)) return new Instruction.Massacre(name);
97         if (KILL.get(inst))     return new Instruction.Kill(name, (int)(KILL.getval(inst)+1));
98
99         int predicate = 0;
100         if (P_ALWAYS.get(inst)) predicate = Instruction.PredicatedInstruction.P_ALWAYS;
101         if (P_A.get(inst)) predicate = Instruction.PredicatedInstruction.P_IF_A;
102         if (P_B.get(inst)) predicate = Instruction.PredicatedInstruction.P_IF_B;
103         if (P_Z.get(inst)) predicate = Instruction.PredicatedInstruction.P_IF_Z;
104
105         boolean dl = false;
106         if (DL.get(inst))                   dl = true;
107
108         if (LOOP_FROM_LITERAL.get(inst))    return new Counter(name, dl, predicate, (int)LOOP_FROM_LITERAL.getval(inst),   LOOP_COUNTER);
109         if (REPEAT_FROM_LITERAL.get(inst))  return new Counter(name, dl, predicate, (int)REPEAT_FROM_LITERAL.getval(inst), REPEAT_COUNTER);
110         if (LOOP_FROM_DATA.get(inst))       return new Counter(name, dl, predicate, DATA_LATCH, LOOP_COUNTER);
111         if (REPEAT_FROM_DATA.get(inst))     return new Counter(name, dl, predicate, DATA_LATCH, REPEAT_COUNTER);
112         if (REPEAT_FROM_STANDING.get(inst)) return new Counter(name, dl, predicate, STANDING, REPEAT_COUNTER);
113         if (TAKE_LOOP.get(inst))            return new Counter(name, dl, predicate, LOOP_COUNTER, DATA_LATCH);
114
115         if (LITERAL_LO.get(inst))  return new Instruction.HalfLiteral(name, dl, predicate, LITERAL_LO.getval(inst), 0, false);
116         if (LITERAL_HI.get(inst))  return new Instruction.HalfLiteral(name, dl, predicate, LITERAL_HI.getval(inst), 0, true);
117         if (LITERAL.get(inst)) {
118             long literal = LITERAL.getval(inst);
119             if      (LITERAL_LOW_ZERO.get(inst))  literal = TOP_HALF_LITERAL.setval(0, literal);
120             else if (LITERAL_LOW_ONE.get(inst))   literal = BOT_HALF_ONE.set(TOP_HALF_LITERAL.setval(0, literal));
121             else if (LITERAL_HIGH_ZERO.get(inst)) literal = BOT_HALF_LITERAL.setval(0, literal);
122             else if (LITERAL_HIGH_ONE.get(inst))  literal = TOP_HALF_ONE.set(BOT_HALF_LITERAL.setval(0, literal));
123             return new Instruction.Literal(name, dl, predicate, Mask.signExtend(literal, WIDTH_WORD));
124         }  
125         if (FLAGS.get(inst))       return new Instruction.SetFlags(name, dl, predicate, (int)FLAGS_A.getval(inst), (int)FLAGS_B.getval(inst));
126
127         if (!MOVE.get(inst)) throw new RuntimeException("unknown instruction: 0x" + Long.toString(inst, 16));
128
129         Destination dest    = getDestByAddr(PATH_LITERAL.getval(inst));
130         boolean tokenIn     = TI.get(inst);
131         boolean dataIn      = DI.get(inst);
132         boolean latch       = DC.get(inst);
133         boolean dataOut     = DO.get(inst);
134         boolean tokenOut    = TO.get(inst);
135         boolean dataOutDest = PATH_DATA.get(inst);
136         return new Instruction.Move(name,
137                                     dl,
138                                     predicate,
139                                     dest,
140                                     tokenIn,
141                                     dataIn,
142                                     latch,
143                                     dataOutDest,
144                                     dataOut,
145                                     tokenOut,
146                                     false,
147                                     false);
148     }
149
150     public long writeInstruction(Instruction d) {
151         long instr = 0;
152
153         if (d.pump != null)
154             instr = PUMP_NAME.setval(instr, getBoxInstAddr(d.pump));
155
156         boolean dl = false;
157         if (d instanceof Instruction.PredicatedInstruction) {
158             Instruction.PredicatedInstruction pi = (Instruction.PredicatedInstruction)d;
159             if (pi.dl) instr = DL.set(instr);
160             switch(pi.predicate) {
161                 case Instruction.PredicatedInstruction.P_ALWAYS: instr = P_ALWAYS.set(instr); break;
162                 case Instruction.PredicatedInstruction.P_IF_A:   instr = P_A.set(instr);      break;
163                 case Instruction.PredicatedInstruction.P_IF_B:   instr = P_B.set(instr);      break;
164                 case Instruction.PredicatedInstruction.P_IF_Z:   instr = P_Z.set(instr);      break;
165             }
166         }
167
168         if (d instanceof Instruction.CodeBagDescriptor) {
169             Instruction.CodeBagDescriptor lc = (Instruction.CodeBagDescriptor)d;
170             // MAJOR MAJOR FIXME: upper half here...
171             d = new Instruction.HalfLiteral(lc.pump, dl, Instruction.PredicatedInstruction.P_ALWAYS,
172                                             ((lc.offset << WIDTH_CODEBAG_SIZE)) | lc.size, 1, false);
173         }
174
175         if (d instanceof Instruction.UnClog) {
176             instr = UNCLOG.set(instr);
177
178         } else if (d instanceof Instruction.Kill) {
179             Instruction.Kill k = (Instruction.Kill)d;
180             instr = KILL.set(instr);
181             instr = KILL.setval(instr, k.count);
182
183         } else if (d instanceof Instruction.Clog) {
184             instr = CLOG.set(instr);
185
186         } else if (d instanceof Instruction.Massacre) {
187             instr = MASSACRE.set(instr);
188
189         } else if (d instanceof Instruction.SetFlags) {
190             Instruction.SetFlags sf = (Instruction.SetFlags)d;
191             instr = FLAGS.set(instr);
192             instr = FLAGS_A.setval(instr, sf.flag_a);
193             instr = FLAGS_B.setval(instr, sf.flag_b);
194
195         } else if (d instanceof Instruction.Literal) {
196             long il = ((Instruction.Literal)d).literal;
197             long literal = ((Instruction.Literal)d).literal;
198             long allones = ~(-1L << WIDTH_WORD);
199             il = literal = literal & allones;
200             long top_half = il >> LITERAL_HIGH_ZERO.getWidth();
201             long bot_half = il & ~(-1L << LITERAL_HIGH_ZERO.getWidth());
202             if      (((il &  (-1L << 19)) & allones) == 0)       instr = LITERAL.setval(LITERAL_HIGH_ZERO.set(instr), il);
203             else if (((il | ~(-1L << 19)) & allones) == allones) instr = LITERAL.setval(LITERAL_HIGH_ONE.set(instr),  il & ~(-1L<<19));
204             else if (((il & ~(-1L << 19)) & allones) == 0)       instr = LITERAL.setval(LITERAL_LOW_ZERO.set(instr), il >> 19);
205             else if (((il |  (-1L << 19)) & allones) == allones) instr = LITERAL.setval(LITERAL_LOW_ONE.set(instr),  (il >> 19));
206             
207         } else if (d instanceof Instruction.HalfLiteral) {
208             Instruction.HalfLiteral inst = (Instruction.HalfLiteral)d;
209             if (inst.pump != null) {
210                 if (inst.high) {
211                     instr = LITERAL_HI.set(instr);
212                     instr = LITERAL_HI.setval(instr, inst.literal);
213                 } else {
214                     instr = LITERAL_LO.set(instr);
215                     instr = LITERAL_LO.setval(instr, inst.literal);
216                 }
217             } else {
218                 instr = inst.literal;
219             }
220
221         } else if (d instanceof Instruction.DecrLoop) {
222             instr = DL.set(instr);
223
224         } else if (d instanceof Instruction.Counter) {
225             Instruction.Counter ic = (Instruction.Counter)d;
226             if      (ic.dest == DATA_LATCH && ic.source == LOOP_COUNTER)   instr = TAKE_LOOP.set(instr);
227             else if (ic.dest == LOOP_COUNTER && ic.source == DATA_LATCH)   instr = LOOP_FROM_DATA.set(instr);
228             else if (ic.dest == REPEAT_COUNTER && ic.source == DATA_LATCH) instr = REPEAT_FROM_DATA.set(instr);
229             else if (ic.dest == REPEAT_COUNTER && ic.source == STANDING)   instr = REPEAT_FROM_STANDING.set(instr);
230             else if (ic.dest == REPEAT_COUNTER)                            instr = REPEAT_FROM_LITERAL.setval(REPEAT_FROM_LITERAL.set(instr), ic.source);
231             else if (ic.dest == LOOP_COUNTER)                              instr = LOOP_FROM_LITERAL.setval(LOOP_FROM_LITERAL.set(instr), ic.source);
232             else throw new RuntimeException();
233
234         } else if (d instanceof Instruction.Move) {
235             Instruction.Move inst = (Instruction.Move)d;
236             instr  = MOVE.set(instr);
237             if (inst.tokenIn)                    instr = TI.set(instr);
238             if (inst.dataIn)                     instr = DI.set(instr);
239             if (inst.latch)                      instr = DC.set(instr);
240             if (inst.dataOut)                    instr = DO.set(instr);
241             if (inst.tokenOut)                   instr = TO.set(instr);
242             if (inst.dataOutDest)                instr = PATH_DATA.set(instr);
243             else {
244                 instr  = PATH_LITERAL.set(instr);
245                 instr  = PATH_LITERAL.setval(instr, inst.dest==null?0:getDestAddr(inst.dest));
246             }
247
248         } else {
249             throw new RuntimeException("unrecognized instruction " + d);
250
251         }
252         return instr;
253     }
254
255     public void writeInstruction(DataOutputStream os, Instruction d) throws IOException {
256         long instr = writeInstruction(d);
257         for(int i=5; i>=0; i--)
258             os.write(getIntField(i*8+7, i*8, instr));
259    }
260
261 }