IES44: lots of cleanup, use safer bitfield operations
[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
6 public abstract class InstructionEncoder {
7
8     /** get the bits describing this box's location on the DESTINATION HORN */
9     protected abstract long getDestAddr(Destination box);
10
11     /** get the bits describing this box's location on the INSTRUCTION HORN */
12     protected abstract long getBoxInstAddr(BenkoBox box);
13
14     /** given an INSTRUCTION HORN address, retrieve the corresponding BenkoBox object */
15     protected abstract BenkoBox getBoxByInstAddr(long dest);
16     
17     /** given a DESTINATION HORN address, retrieve the corresponding BenkoBox object */
18     protected abstract Destination getDestByAddr(long dest);
19
20     /** read a machine-formatted instruction from a file (into a Java object) */
21     public Instruction readInstruction(DataInputStream is) throws IOException {
22         long inst = 0;
23         try {
24             inst = (inst << 8) | (is.readByte() & 0xff);
25             inst = (inst << 8) | (is.readByte() & 0xff);
26             inst = (inst << 8) | (is.readByte() & 0xff);
27             inst = (inst << 8) | (is.readByte() & 0xff);
28             inst = (inst << 8) | (is.readByte() & 0xff);
29             inst = (inst << 8) | (is.readByte() & 0xff);
30             return readInstruction(inst);
31         } catch (EOFException eof) {
32             return null;
33         }
34     }
35
36     // FIXME: use this more
37     private boolean getBit(int bit, long val) { return ((val & (1L << bit)) != 0); }
38     private long getSignedField(int highBit, int lowBit, long val) {
39         long ret = getField(highBit, lowBit, val);
40         if ((ret & (1L << ((highBit-lowBit)+1-1))) != 0)
41             ret |= 0xffffffffffffffffL << ((highBit-lowBit)+1);
42         return ret;
43     }
44     private int getIntField(int highBit, int lowBit, long val) {
45         if (highBit-lowBit+1 > 32) throw new RuntimeException("too big!");
46         return (int)getField(highBit, lowBit, val);
47     }
48     private long getField(int highBit, int lowBit, long val) {
49         long mask = 0xffffffffffffffffL;
50         mask = mask << ((highBit-lowBit)+1);
51         mask = ~mask;
52         mask = mask << lowBit;
53         long ret = val & mask;
54         ret = ret >> lowBit;
55         return ret;
56     }
57
58     private long doPutField(int highBit, int lowBit, long val) {
59         long mask = 0xffffffffffffffffL;
60         mask = mask << (highBit-lowBit+1);
61         mask = ~mask;
62         val = val & mask;
63         val = val << lowBit;
64         return val;
65     }
66     private long putField(int highBit, int lowBit, long val) {
67         if (val < 0 || val >= (1L << (highBit-lowBit+1)))
68             throw new RuntimeException("bitfield width exceeded");
69         return doPutField(highBit, lowBit, val);
70     }
71     private long putSignedField(int highBit, int lowBit, long val) {
72         if (val <= (-1L * (1L << (highBit-lowBit+1-1))))
73             throw new RuntimeException("bitfield width exceeded");
74         if (val >= (      (1L << (highBit-lowBit+1-1))))
75             throw new RuntimeException("bitfield width exceeded");
76         return doPutField(highBit, lowBit, val);
77     }
78
79     // FIXME: parameterize stuff in this file
80     private static final int WBITS              = 37;   /* word width */
81     private static final int IBITS              = 37;   /* instruction width */
82     private static final int CODEBAG_SIZE_BITS  = 6;
83     private static final int BENKOBOX_NAME_BITS = 11;
84     private static final int COUNT_BITS         = 7;
85     private static final int OPCODE_BITS        = 5;
86
87     public Instruction readInstruction(long instr) {
88         long inst = instr;
89         switch((int)getField(WBITS-1, WBITS-2, inst)) {
90             case 0: {
91                 BenkoBox name    = getBoxByInstAddr((inst >> 24) & 0x7ff);
92                 Destination dest = getDestByAddr    ((inst >>  1) & 0x7ff);
93                 int count        = getIntField(COUNT_BITS+BENKOBOX_NAME_BITS+1-1, BENKOBOX_NAME_BITS+1, instr);
94                 boolean tokenIn  = getBit(COUNT_BITS+BENKOBOX_NAME_BITS+1+0, instr);
95                 boolean dataIn   = getBit(COUNT_BITS+BENKOBOX_NAME_BITS+1+1, instr);
96                 boolean latch    = getBit(COUNT_BITS+BENKOBOX_NAME_BITS+1+2, instr);
97                 boolean dataOut  = getBit(COUNT_BITS+BENKOBOX_NAME_BITS+1+3, instr);
98                 boolean tokenOut = getBit(COUNT_BITS+BENKOBOX_NAME_BITS+1+4, instr);
99                 boolean recycle  = getBit(0, instr);
100                 if (latch & !dataIn) return new Instruction.Kill(name, count, tokenIn);
101                 return new Instruction.Executable(name, dest, count, tokenIn, dataIn,
102                                                   latch, dataOut, tokenOut, recycle);
103             }
104
105             case 1: {
106                 Destination name = getDestByAddr(getField(WBITS-3, WBITS-3-BENKOBOX_NAME_BITS+1, inst));
107                 long offset = getSignedField(WBITS-3-BENKOBOX_NAME_BITS, CODEBAG_SIZE_BITS, instr);
108                 long size   = getSignedField(CODEBAG_SIZE_BITS-1,        0,                 instr);
109                 return new Instruction.Literal.CodeBagDescriptor(name, offset, size);
110             }
111
112             case 2: {
113                 Destination name = getDestByAddr(getField(WBITS-3, WBITS-3-BENKOBOX_NAME_BITS+1, inst));
114                 return new Instruction.Literal.Absolute(name, getSignedField(WBITS-3-BENKOBOX_NAME_BITS, 0, instr));
115             }
116
117             case 3: {
118                 Destination name = getDestByAddr(getField(WBITS-3, WBITS-3-BENKOBOX_NAME_BITS+1, inst));
119                 return new Instruction.Literal.Relative(name, getSignedField(WBITS-3-BENKOBOX_NAME_BITS, 0, instr));
120             }
121
122         }
123         return null;
124
125     }
126
127     public long writeInstruction(Instruction d) {
128         long instr = 0;
129
130         // Kill is encoded as Execute with the illegal combination (Latch & ~DataIn)
131         if (d instanceof Instruction.Kill) {
132             Instruction.Kill k = (Instruction.Kill)d;
133             d = new Instruction.Executable(k.benkoBox, null, k.count, k.killOnlyStandingInstructions,
134                                            false, true, false, false, false);
135         }
136
137         if (d instanceof Instruction.Executable) {
138             Instruction.Executable inst = (Instruction.Executable)d;
139             if (inst.dest != null)
140                 instr |= putField(BENKOBOX_NAME_BITS, 1, getDestAddr(inst.dest));
141             instr |= putField(COUNT_BITS+BENKOBOX_NAME_BITS+1-1, BENKOBOX_NAME_BITS+1,              inst.count);
142             instr |= putField(COUNT_BITS+BENKOBOX_NAME_BITS+1+0, COUNT_BITS+BENKOBOX_NAME_BITS+1+0, inst.tokenIn  ? 1 : 0);
143             instr |= putField(COUNT_BITS+BENKOBOX_NAME_BITS+1+1, COUNT_BITS+BENKOBOX_NAME_BITS+1+1, inst.dataIn   ? 1 : 0);
144             instr |= putField(COUNT_BITS+BENKOBOX_NAME_BITS+1+2, COUNT_BITS+BENKOBOX_NAME_BITS+1+2, inst.latch    ? 1 : 0);
145             instr |= putField(COUNT_BITS+BENKOBOX_NAME_BITS+1+3, COUNT_BITS+BENKOBOX_NAME_BITS+1+3, inst.dataOut  ? 1 : 0);
146             instr |= putField(COUNT_BITS+BENKOBOX_NAME_BITS+1+4, COUNT_BITS+BENKOBOX_NAME_BITS+1+4, inst.tokenOut ? 1 : 0);
147             instr |= putField(0,                                 0,                                 inst.recycle  ? 1 : 0);
148             instr |= putField(BENKOBOX_NAME_BITS+OPCODE_BITS+COUNT_BITS+BENKOBOX_NAME_BITS+1-1,
149                               OPCODE_BITS+COUNT_BITS+BENKOBOX_NAME_BITS+1,
150                               getBoxInstAddr(inst.benkoBox));
151
152         } else if (d instanceof Instruction.Literal.CodeBagDescriptor) {
153             Instruction.Literal.CodeBagDescriptor lc = (Instruction.Literal.CodeBagDescriptor)d;
154             instr = putField(WBITS-1, WBITS-2, 1);
155             if (lc.dest != null) instr |= putField(WBITS-3, WBITS-3-BENKOBOX_NAME_BITS+1, getDestAddr(lc.dest));
156             instr |= putSignedField(WBITS-3-BENKOBOX_NAME_BITS, CODEBAG_SIZE_BITS, lc.offset);
157             instr |= putField(CODEBAG_SIZE_BITS-1,        0,                 lc.size);
158
159         } else if (d instanceof Instruction.Literal.Absolute) {
160             Instruction.Literal.Absolute ld = (Instruction.Literal.Absolute)d;
161             instr = putField(WBITS-1, WBITS-2, 2);
162             instr |= putField(WBITS-3, WBITS-3-BENKOBOX_NAME_BITS+1, getDestAddr(ld.dest));
163             instr |= putSignedField(WBITS-3-BENKOBOX_NAME_BITS, 0, ld.value);
164
165         } else if (d instanceof Instruction.Literal.Relative) {
166             Instruction.Literal.Relative lr = (Instruction.Literal.Relative)d;
167             instr = putField(WBITS-1, WBITS-2, 3);
168             instr |= putField(WBITS-3, WBITS-3-BENKOBOX_NAME_BITS+1, getDestAddr(lr.dest));
169             instr |= putSignedField(WBITS-3-BENKOBOX_NAME_BITS, 0, lr.offset);
170             
171         }
172         return instr;
173     }
174
175     public void writeInstruction(DataOutputStream os, Instruction d) throws IOException {
176         long instr = writeInstruction(d);
177         for(int i=5; i>=0; i--)
178             os.write(getIntField(i*8+7, i*8, instr));
179    }
180
181 }