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