added "mem" ship
[fleet.git] / src / edu / berkeley / fleet / interpreter / Interpreter.java
1 package edu.berkeley.fleet.interpreter;
2 import edu.berkeley.fleet.api.*;
3
4 import edu.berkeley.fleet.api.*;
5 import edu.berkeley.fleet.*;
6 import java.lang.reflect.*;
7 import edu.berkeley.sbp.chr.*;
8 import edu.berkeley.sbp.misc.*;
9 import edu.berkeley.sbp.meta.*;
10 import edu.berkeley.sbp.bind.*;
11 import edu.berkeley.sbp.util.*;
12 import java.util.*;
13 import java.io.*;
14 import edu.berkeley.fleet.ships.*;
15
16 public class Interpreter extends Fleet implements Iterable<Ship> {
17
18     public InterpreterBenkoBox resolve(edu.berkeley.fleet.api.BenkoBox bb) { return (InterpreterBenkoBox)bb; }
19
20     public void dumpCode(Instruction[] instructions) throws IOException {
21         DataOutputStream dos = new DataOutputStream(new FileOutputStream("build/fleet.bin"));
22         for(int i=1; i<instructions.length; i++) {
23             Instruction inst = instructions[i];
24             writeInstruction(dos, inst);
25         }
26         dos.flush();
27         dos.close();
28     }
29
30     public void dispatch(Instruction i, long address) {
31
32         if (i instanceof Instruction.Executable) {
33             InterpreterBenkoBox sourceBenkoBox = resolve(((Instruction.Executable)i).benkoBox);
34             if (!(sourceBenkoBox instanceof InstructionPort))
35                 throw new RuntimeException(sourceBenkoBox + " is not an InstructionPort!");
36             ((InstructionPort)sourceBenkoBox).addInstruction(((Instruction.Executable)i));
37
38         } else if (i instanceof Instruction.Literal.CodeBagDescriptor) {
39             Log.dispatch(i);
40             Instruction.Literal.CodeBagDescriptor cbd = (Instruction.Literal.CodeBagDescriptor)i;
41             dispatchCodeBag(cbd.offset+address, cbd.size);
42             
43         } else if (i instanceof Instruction.Literal.Absolute) {
44             InterpreterBenkoBox destBenkoBox = resolve(((Instruction.Literal.Absolute)i).dest);
45             Log.data(((Instruction.Literal.Absolute)i).value+"", null, destBenkoBox);
46             destBenkoBox.addDataFromFabric((int)((Instruction.Literal.Absolute)i).value);
47
48         } else if (i instanceof Instruction.Kill) {
49             InterpreterBenkoBox benkoBox = resolve(((Instruction.Kill)i).benkoBox);
50             if (!(benkoBox instanceof InstructionPort))
51                 throw new RuntimeException(benkoBox + " is not an InstructionPort!");
52             ((InstructionPort)benkoBox).kill(((Instruction.Kill)i).count);
53
54         } else {
55             throw new Error("unsupported: " + i.getClass().getName());
56         }
57     }
58
59     /** some "halt ship" can turn this on to stop the interpreter */
60     public boolean halt = false;
61
62     public int[] mem = new int[0];
63
64     public Instruction[] instructions = null;
65     public ArrayList<String> imports = new ArrayList<String>();
66
67     private static String getUniqueName(Ship ship) {
68         return ship.getType() + ship.getOrdinal();
69     }
70
71     public ArrayList<InterpreterShip> shiplist = new ArrayList<InterpreterShip>();
72     public HashMap<String,InterpreterShip> ships = new HashMap<String,InterpreterShip>();
73
74     /** read a machine-formatted instruction from a file (into a Java object) */
75     public Instruction readInstruction(DataInputStream is) throws IOException {
76         // FIXME
77         return null;
78     }
79
80     public void writeInstruction(DataOutputStream os, Instruction d) throws IOException {
81         long instr = 0;
82
83         // Kill is encoded as Execute with the illegal combination (Latch & ~DataIn)
84         if (d instanceof Instruction.Kill) {
85             Instruction.Kill k = (Instruction.Kill)d;
86             d = new Instruction.Executable(k.benkoBox, null, k.count, false, false, true, false, false, false);
87         }
88
89         if (d instanceof Instruction.Executable) {
90             Instruction.Executable inst = (Instruction.Executable)d;
91             InterpreterBenkoBox dest = resolve(inst.dest);
92             instr = dest==null ? 0 : (dest.addr << 1);
93             if (inst.count >= (1<<8))
94                 throw new RuntimeException("count field must be less than 128");
95             instr |= (((long)inst.count) << (11+1));
96             if (inst.tokenIn)  instr |= (1L << (11+1+7+0));
97             if (inst.dataIn)   instr |= (1L << (11+1+7+1));
98             if (inst.latch)    instr |= (1L << (11+1+7+2));
99             if (inst.dataOut)  instr |= (1L << (11+1+7+3));
100             if (inst.tokenOut) instr |= (1L << (11+1+7+4));
101             if (inst.recycle)  instr |= (1L);
102             instr |= ((long)resolve(inst.benkoBox).instr_addr) << (11+5+7+1);
103
104         } else if (d instanceof Instruction.Literal.Absolute) {
105             Instruction.Literal.Absolute ld = (Instruction.Literal.Absolute)d;
106             instr = (2L << (11+24));
107             instr |= (resolve(ld.dest).addr) << 24;
108             if (ld.value >= (1<<25))
109                 throw new RuntimeException("literals must be less than 2^24");
110             instr |= ((long)ld.value);
111         }
112
113         dump(os, (instr >> (5*8)) & 0xff);
114         dump(os, (instr >> (4*8)) & 0xff);
115         dump(os, (instr >> (3*8)) & 0xff);
116         dump(os, (instr >> (2*8)) & 0xff);
117         dump(os, (instr >> (1*8)) & 0xff);
118         dump(os, (instr >> (0*8)) & 0xff);
119     }
120     public void dump(OutputStream os, long data_) throws IOException {
121         int data = (int)data_;
122         os.write((byte)data);
123         //System.out.println(data);
124     }
125
126     public Iterator<Ship> iterator() {
127         return (Iterator<Ship>)(Object)shiplist.iterator();
128     }
129
130     public void dispatchCodeBag(long base, long size) {
131         for(long i=base; i<base+size; i++)
132             dispatch(instructions[(int)i], i);
133     }
134
135     public void go() {
136         Instruction.Literal.CodeBagDescriptor cbl =
137             (Instruction.Literal.CodeBagDescriptor)instructions[0];
138         dispatchCodeBag(cbl.offset+0, cbl.size);
139
140         while(!halt)
141             for(InterpreterShip ship : ships.values())
142                 for(int j=0; j<10; j++)
143                     ship._service();
144
145         // run the ships a bit longer for good measure
146         for(int i=0; i<100; i++)
147             for(InterpreterShip ship : ships.values())
148                 for(int j=0; j<10; j++)
149                     ship._service();
150
151         // check the state of the ships
152         for(InterpreterShip ship : ships.values())
153             ship.shutdown();
154
155         Log.println(Log.yellow("    DONE: ====== FLEET is halted.  Have a nice day.  ======"));
156     }
157
158     public void dumpMem() {
159         Log.print(Log.cyan("  MEMORY: "));
160         for(int i=0; i<mem.length; i++) {
161             if ((i%10)==0 && i!=0) Log.print(Log.cyan("          "));
162             Log.print(Log.cyan(mem[i] + " "));
163             if ((i%10)==9 && i!=mem.length-1) Log.println("");
164         }
165         Log.println();
166     }
167
168     public int readMem(int addr) {
169         return addr >= mem.length ? 0 : mem[addr];
170     }
171     public void writeMem(int addr, int data) {
172         if (addr >= mem.length) {
173             int[] mem2 = new int[addr*2+1];
174             System.arraycopy(mem, 0, mem2, 0, mem2.length);
175             mem = mem2;
176         }
177         mem[addr] = data;
178     }
179
180     public InterpreterShip getShip(String name) {
181         InterpreterShip s = ships.get(name);
182         if (s == null) throw new RuntimeException("unknown ship \""+name+"\"");
183         return s;
184     }
185
186     public InterpreterShip tryCreate(String classname, String shipname) {
187         try {
188             Class c = Class.forName(classname);
189             Constructor con = c.getConstructor(new Class[] { Interpreter.class, String.class });
190             InterpreterShip ret = (InterpreterShip)con.newInstance(new Object[] { this, shipname });
191             ships.put(shipname, ret);
192             shiplist.add(ret);
193             return ret;
194         } catch (Exception e) {
195             return null;
196         }
197     }
198
199     public void sendToken(InterpreterBenkoBox source, InterpreterBenkoBox dest) {
200         Log.token(source, dest);
201         dest.addTokenFromFabric();
202     }
203
204     public void sendData(InterpreterBenkoBox source, int data, InterpreterBenkoBox dest) {
205         Log.data(data+"", source, dest);
206         dest.addDataFromFabric(data);
207     }
208
209     public void dumpFabric(boolean quiet) {
210         // FIXME: this is really ugly: the order of port declarations in
211         //        the XXXShip.java file must match the order in the .balsa file!
212
213         ArrayList instructionports = new ArrayList<InterpreterBenkoBox>();
214         for(InterpreterShip ship : shiplist)
215             for(BenkoBox port : ship.getBenkoBoxes())
216                 if (!((InterpreterBenkoBox)port).special())
217                     instructionports.add(port);
218         FabricTree instructions =
219             new FabricTree((InterpreterBenkoBox[])instructionports.toArray(new InterpreterBenkoBox[0]),
220                            "ihorn",
221                            "instruction");
222
223         ArrayList inputports = new ArrayList<InterpreterBenkoBox>();
224         for(InterpreterShip ship : shiplist)
225             for(BenkoBox port : ship.getBenkoBoxes())
226                 if (!((InterpreterBenkoBox)port).special())
227                     inputports.add(port);
228         FabricTree inputs =
229             new FabricTree((InterpreterBenkoBox[])inputports.toArray(new InterpreterBenkoBox[0]),
230                            "horn",
231                            "dest");
232
233         ArrayList outputports = new ArrayList<InterpreterBenkoBox>();
234         for(InterpreterShip ship : shiplist)
235             for(BenkoBox port : ship.getBenkoBoxes())
236                 if (!((InterpreterBenkoBox)port).special())
237                     outputports.add(port);
238         FabricTree outputs =
239             new FabricTree((InterpreterBenkoBox[])outputports.toArray(new InterpreterBenkoBox[0]),
240                            "funnel",
241                            "source");
242
243         if (quiet) return;
244         System.out.println("`include \"macros.v\"");
245         /*
246           HashSet<Class> added = new HashSet<Class>();
247           for(Ship ship : shiplist)
248           if (!added.contains(ship.getClass())) {
249           added.add(ship.getClass());
250           System.out.println("import ["+ship.getBalsaName()+"]");
251           }
252         */
253         System.out.println("module fabric(clk, data_Execute0_in_r, data_Execute0_in_a, data_Execute0_in,");
254         System.out.println("                   data_Debug0_out_r, data_Debug0_out_a, data_Debug0_out);");
255         System.out.println("  input  clk;");
256         System.out.println("  input  data_Execute0_in_r;");
257         System.out.println("  output data_Execute0_in_a;");
258         System.out.println("  input  [(`PACKET_WIDTH-1):0] data_Execute0_in;");
259         System.out.println("  output data_Debug0_out_r;");
260         System.out.println("  input  data_Debug0_out_a;");
261         System.out.println("  output [(`PACKET_WIDTH-1):0] data_Debug0_out;");
262         System.out.println("  wire   [(`INSTRUCTION_WIDTH-1):0] data_Execute0_ihorn;");
263         System.out.println("  wire   [(`PACKET_WIDTH-1):0] data_Execute0_dhorn;");
264         System.out.println();
265         
266         System.out.println();
267
268         instructions.dumpChannels(true);
269         outputs.dumpChannels(true);
270         inputs.dumpChannels(true);
271         for(InterpreterShip ship : shiplist)
272             for(BenkoBox port : ship.getBenkoBoxes()) {
273                 if (ship instanceof Execute && port instanceof Outbox) continue;
274                 System.out.println("  wire [(`PACKET_WIDTH-1):0] data_"+getUniqueName(ship)+"_"+port.getName()+";");
275             }
276
277         System.out.println("");
278         instructions.dumpChannels(false);
279         System.out.println("");
280         outputs.dumpChannels(false);
281         System.out.println("");
282         inputs.dumpChannels(false);
283         System.out.println("");
284         for(InterpreterShip ship : shiplist) {
285             System.out.print(ship.getClass().getSimpleName().toLowerCase());
286             System.out.print(" ");
287             System.out.print("krunk"+(krunk++));
288             System.out.print("(clk, ");
289             boolean first = true;
290             for(BenkoBox port : ship.getBenkoBoxes()) {
291                 if (!first) System.out.print(", ");
292                 first = false;
293                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
294                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
295                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName());
296                 System.out.print(" ");
297             }
298             System.out.println(");");
299
300             for(BenkoBox port : ship.getBenkoBoxes()) {
301                 if (((InterpreterBenkoBox)port).special()) continue;
302                 if (port instanceof Inbox) {
303                     /*
304                     if (((InterpreterBenkoBox)port).noInbox())
305                         System.out.print("stupidinbox");
306                     else
307                     */
308                     System.out.print("inbox");
309                 } else {
310                     System.out.print("outbox");
311                 }
312                 System.out.print(" krunk"+(krunk++)+"(clk, ");
313                 System.out.print("instruction_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
314                 System.out.print("instruction_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
315                 System.out.print("instruction_"+getUniqueName(port.getShip())+"_"+port.getName()+", ");
316                 System.out.print("dest_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
317                 System.out.print("dest_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
318                 System.out.print("dest_"+getUniqueName(port.getShip())+"_"+port.getName()+", ");
319                 System.out.print("source_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
320                 System.out.print("source_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
321                 System.out.print("source_"+getUniqueName(port.getShip())+"_"+port.getName()+", ");
322                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
323                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
324                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName());
325                 System.out.print(");");
326                 System.out.println();
327             }
328
329         }
330         System.out.println("funnel topfun(clk,"+
331                            "              dest_r, dest_a, dest,"+
332                            "              source_r, source_a, source,"+
333                            "              data_Execute0_dhorn_r, data_Execute0_dhorn_a, data_Execute0_dhorn);");
334         System.out.println("assign instruction_r = data_Execute0_ihorn_r;");
335         System.out.println("assign data_Execute0_ihorn_a = instruction_a;");
336         System.out.println("assign instruction = data_Execute0_ihorn;");
337         System.out.println("endmodule");
338     }
339
340     private static class FabricTree {
341         int master_idx = 1;
342         String prefix;
343         Node root;
344         public void dumpChannels(boolean decl) { root.dumpChannels(0, decl); }
345         public FabricTree(InterpreterBenkoBox[] ports, String component, String prefix) {
346             this.prefix = prefix;
347             root = (Node)mkNode("", component, ports, 0, ports.length, 0, 0);
348         }
349         private Object mkNode(String name, String component, InterpreterBenkoBox[] ports,
350                               int start, int end, int addr, int bits) {
351             if (end-start == 0) return null;
352             if (end-start == 1) {
353                 InterpreterBenkoBox p = ports[start];
354                 if (prefix.equals("instruction")) {
355                     p.instr_addr = addr;
356                     p.instr_bits = bits;
357                 } else {
358                     p.addr = addr;
359                     p.bits = bits;
360                 }
361                 return p;
362             }
363             int len = end-start;
364             return new Node(name,
365                             component,
366                             mkNode(name+"_0", component, ports, start, start+len/2, addr, bits+1),
367                             mkNode(name+"_1", component, ports, start+len/2, end,   addr | (1 << bits), bits+1),
368                             addr,
369                             bits);
370         }
371         private String describe(String prefix, Object o) {
372             if (o==null) return null;
373             if (o instanceof InterpreterBenkoBox) {
374                 InterpreterBenkoBox p = (InterpreterBenkoBox)o;
375                 return prefix+"_"+getUniqueName(p.getShip())+"_"+p.getName();
376             }
377             if (o instanceof Node) {
378                 return ((Node)o).describe(prefix);
379             }
380             return null;
381         }
382         private class Node {
383             Object left;
384             Object right;
385             String name;
386             String component;
387             int addr;
388             int bits;
389             public Node(String name, String component, Object left, Object right, int addr, int bits) {
390                 this.left = left;
391                 this.right = right;
392                 this.name = name;
393                 this.component = component;
394                 this.addr = addr;
395                 this.bits = bits;
396             }
397             public void dumpChannels(int indentamount, boolean decl) {
398                 String indent = "";
399                 for(int i=0; i<indentamount; i++) indent += "  ";
400                 if (decl) {
401                     String n = describe(prefix).startsWith("instruction")
402                         ? "[(`INSTRUCTION_WIDTH-1):0]" : "[(`PACKET_WIDTH-1):0]";
403                     System.out.println("  wire "+n+" "+indent+describe(prefix)+";");
404                 } else {
405                     System.out.println("     "+indent+
406                                        component+" "+
407                                        "krunk"+(krunk++)+"(clk, "+
408                                        describe(prefix)+"_r, "+
409                                        describe(prefix)+"_a, "+
410                                        describe(prefix)+", "+
411                                        FabricTree.this.describe(prefix, left)+"_r, "+
412                                        FabricTree.this.describe(prefix, left)+"_a, "+
413                                        FabricTree.this.describe(prefix, left)+", "+
414                                        FabricTree.this.describe(prefix, right)+"_r, "+
415                                        FabricTree.this.describe(prefix, right)+"_a, "+
416                                        FabricTree.this.describe(prefix, right)+
417                                        ");");
418                 }
419                 dumpChannels(left, indentamount+1, decl);
420                 dumpChannels(right, indentamount+1, decl);
421             }
422             public void dumpChannels(Object o, int indentamount, boolean decl) {
423                 if (o==null) return;
424                 if (o instanceof Node) {
425                     ((Node)o).dumpChannels(indentamount, decl);
426                 } else {
427                     String indent = "";
428                     for(int i=0; i<indentamount; i++) indent += "  ";
429                     if (decl) {
430                         String n = FabricTree.this.describe(prefix,o).startsWith("instruction")
431                             ? "[(`INSTRUCTION_WIDTH-1):0]" : "[(`PACKET_WIDTH-1):0]";
432                         System.out.println("  wire "+n+" "+indent+FabricTree.this.describe(prefix,o)+";");
433                     }
434                 }
435             }
436             public String describe(String prefix) {
437                 return prefix+name;
438             }
439         }
440     }
441     public static int krunk=0;
442
443     public int computeOffset(int origin, int target) { return target - origin; }
444     public int computeTarget(int origin, int offset) { return origin + offset; }
445 }