major overhaul: update dock to am33
[fleet.git] / src / edu / berkeley / fleet / fpga / Fpga.java
1 package edu.berkeley.fleet.fpga;
2 import edu.berkeley.fleet.fpga.*;
3 import edu.berkeley.fleet.doc.*;
4 import edu.berkeley.fleet.api.*;
5 import edu.berkeley.fleet.ies44.*;
6 import edu.berkeley.fleet.*;
7 import java.lang.reflect.*;
8 import edu.berkeley.sbp.chr.*;
9 import edu.berkeley.sbp.misc.*;
10 import edu.berkeley.sbp.meta.*;
11 import edu.berkeley.sbp.util.*;
12 import java.util.*;
13 import java.io.*;
14
15 public class Fpga extends Fleet {
16
17     public ArrayList<FpgaShip> shiplist   = new ArrayList<FpgaShip>();
18     public HashMap<String,FpgaShip> ships = new HashMap<String,FpgaShip>();
19     public Iterator<Ship> iterator() { return (Iterator<Ship>)(Object)shiplist.iterator(); }
20
21     private String bitfile;
22
23     public static void main(String[] s) throws Exception {
24         new Fpga().dumpFabric(false);
25     }
26
27     public Fpga() { this("gaspified.bit"); }
28     public Fpga(String bitfile) {
29         this.bitfile = bitfile;
30         createShip("Debug",   "debug");
31         createShip("Memory",    "memory");
32         createShip("Memory",    "memory2");  // need this to avoid a bug
33         createShip("Fifo",    "fifo1");
34         createShip("Fifo",    "fifo2");
35         createShip("Alu2",    "alu2a");
36         createShip("BitFifo",   "bitfifo");
37         // above is the minimal ship set needed to run the regression suite, excluding "ships" tests
38         /*
39         createShip("Fifo",    "fifo3");
40         createShip("Alu1",    "alu1");
41         createShip("Lut3",      "lut3");
42         createShip("Choice",    "Choice");
43         createShip("Stack",     "Stack");
44         createShip("Alu3",      "alu3");
45         */
46         // above is the minimal ship set needed to run the regression suite, including "ships" tests
47
48         // below are extra bonus ships
49         /*
50         createShip("Alu2",    "alu2b");
51         createShip("Alu2",    "alu2c");
52         createShip("Alu2",    "alu2d");
53         createShip("Fifo",    "fifo4");
54         createShip("Memory",    "Memory");
55         createShip("Choice",    "Choice");
56         createShip("Choice",    "Choice");
57         createShip("Choice",    "Choice");
58         */
59         dumpFabric(true);
60     }
61
62     public Ship createShip(String type, String name) {
63         try {
64             ShipDescription sd = new ShipDescription(name, new BufferedReader(new InputStreamReader(new FileInputStream("ships/"+type+".ship"))));
65             FpgaShip ship = new FpgaShip(this, name, type, sd);
66             ships.put(name, ship);
67             shiplist.add(ship);
68             return ship;
69         } catch (IOException e) { throw new RuntimeException(e); }
70     }
71
72     public FleetProcess run(final byte[] instructions) {
73         try {
74             return new Client(bitfile, instructions);
75         } catch (IOException e) { throw new RuntimeException(e); }
76     }
77
78     public void dumpFabric(boolean quiet) {
79         // FIXME: this is really ugly: the order of port declarations in
80         //        the XXXShip.java file must match the order in the .balsa file!
81
82         ArrayList instructionports = new ArrayList<FpgaPump>();
83         for(FpgaShip ship : shiplist)
84             for(Pump port : ship.getPumps())
85                 if (!((FpgaPump)port).special())
86                     instructionports.add(port);
87         FabricTree instructions =
88             new FabricTree((FpgaPump[])instructionports.toArray(new FpgaPump[0]),
89                            "ihorn",
90                            "instruction");
91
92         ArrayList inputports = new ArrayList<FpgaPump>();
93         for(FpgaShip ship : shiplist)
94             for(Pump port : ship.getPumps())
95                 if (!((FpgaPump)port).special())
96                     inputports.add(port);
97         FabricTree inputs =
98             new FabricTree((FpgaPump[])inputports.toArray(new FpgaPump[0]),
99                            "horn",
100                            "dest");
101
102         ArrayList outputports = new ArrayList<FpgaPump>();
103         for(FpgaShip ship : shiplist)
104             for(Pump port : ship.getPumps())
105                 if (!((FpgaPump)port).special() || ((FpgaPump)port).dhorn())
106                     outputports.add(port);
107         FabricTree outputs =
108             new FabricTree((FpgaPump[])outputports.toArray(new FpgaPump[0]),
109                            "funnel",
110                            "source");
111
112         ArrayList ihornports = new ArrayList<FpgaPump>();
113         for(FpgaShip ship : shiplist)
114             for(Pump port : ship.getPumps())
115                 if (((FpgaPump)port).ihorn())
116                     ihornports.add(port);
117         FabricTree ihorns =
118             new FabricTree((FpgaPump[])ihornports.toArray(new FpgaPump[0]),
119                            "funnel",
120                            "ihorn");
121
122         if (quiet) return;
123         System.out.println("`include \"macros.v\"");
124         System.out.println("module fabric(clk, data_Memory0_command_r, data_Memory0_command_a, data_Memory0_command,");
125         System.out.println("                   data_Debug0_out_r, data_Debug0_out_a, data_Debug0_out);");
126         System.out.println("  input  clk;");
127         System.out.println("  input  data_Memory0_command_r;");
128         System.out.println("  output data_Memory0_command_a;");
129         System.out.println("  output data_Debug0_out_r;");
130         System.out.println("  input  data_Debug0_out_a;");
131         System.out.println("  output [(`PACKET_WIDTH-1):0]      data_Debug0_out;");
132         System.out.println("  input  [(`PACKET_WIDTH-1):0]      data_Memory0_command;");
133         //System.out.println("  wire   [(`INSTRUCTION_WIDTH-1):0] data_Memory0_ihorn;");
134         //System.out.println("  wire   [(`PACKET_WIDTH-1):0]      data_Memory0_dhorn;");
135         System.out.println();
136         
137         System.out.println();
138
139         instructions.dumpChannels(true);
140         outputs.dumpChannels(true);
141         inputs.dumpChannels(true);
142         ihorns.dumpChannels(true);
143         for(FpgaShip ship : shiplist)
144             for(Pump port : ship.getPumps())
145                 if (!((FpgaPump)port).special() || ((FpgaPump)port).dhorn())
146                     System.out.println("  wire [(`PACKET_WIDTH-1):0] data_"
147                                        +getUniqueName(ship)+"_"+port.getName()+";");
148
149         System.out.println("wire [(`PACKET_WIDTH-1):0] ihornleft;");
150
151         System.out.println("");
152         instructions.dumpChannels(false);
153         System.out.println("");
154         outputs.dumpChannels(false);
155         System.out.println("");
156         inputs.dumpChannels(false);
157         System.out.println("");
158         ihorns.dumpChannels(false);
159         System.out.println("");
160         for(FpgaShip ship : shiplist) {
161             System.out.print(ship.getType().toLowerCase());
162             System.out.print(" ");
163             System.out.print("krunk"+(krunk++));
164             System.out.print("(clk, ");
165             boolean first = true;
166             for(Pump port : ship.getPumps()) {
167                 if (!first) System.out.print(", ");
168                 first = false;
169                 String prefix = "data_";
170                 if (((FpgaPump)port).ihorn()) prefix = "ihorn_";
171                 if (((FpgaPump)port).dhorn()) prefix = "source_";
172                 System.out.print(prefix+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
173                 System.out.print(prefix+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
174                 System.out.print(prefix+getUniqueName(port.getShip())+"_"+port.getName());
175                 System.out.print(" ");
176             }
177             System.out.println(");");
178
179             for(Pump port : ship.getPumps()) {
180                 if (((FpgaPump)port).special()) continue;
181                 if (((FpgaPump)port).inbox) {
182                     System.out.print("inbox");
183                 } else {
184                     System.out.print("outbox");
185                 }
186                 System.out.print(" krunk"+(krunk++)+"(clk, ");
187                 System.out.print("instruction_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
188                 System.out.print("instruction_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
189                 System.out.print("`packet_data(instruction_"+getUniqueName(port.getShip())+"_"+port.getName()+"), ");
190                 System.out.print("dest_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
191                 System.out.print("dest_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
192                 System.out.print("dest_"+getUniqueName(port.getShip())+"_"+port.getName()+", ");
193                 System.out.print("source_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
194                 System.out.print("source_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
195                 System.out.print("source_"+getUniqueName(port.getShip())+"_"+port.getName()+", ");
196                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName()+"_r, ");
197                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName()+"_a, ");
198                 System.out.print("data_"+getUniqueName(port.getShip())+"_"+port.getName());
199                 System.out.print(");");
200                 System.out.println();
201             }
202
203         }
204
205         System.out.println("funnel ihornfun(clk,"+
206                            "             ihornleft_r, ihornleft_a, ihornleft,"+
207                            "             ihorn_r, ihorn_a, ihorn,"+
208                            "             source_r, source_a, source);");
209         System.out.println("horn tophorn(clk,"+
210                            "             ihornleft_r, ihornleft_a, ihornleft,"+
211                            "             instruction_r, instruction_a, instruction,"+
212                            "             dest_r, dest_a, dest);");
213         /*
214         System.out.println("assign instruction_r = ihorn_r;");
215         System.out.println("assign ihorn_a = instruction_a;");
216         System.out.println("assign instruction = ihorn;");
217         System.out.println("assign dest_r = source_r;");
218         System.out.println("assign source_a = dest_a;");
219         System.out.println("assign dest = source;");
220         */
221         System.out.println("endmodule");
222     }
223
224     private static class FabricTree {
225         int master_idx = 1;
226         String prefix;
227         Node root;
228         public void dumpChannels(boolean decl) { root.dumpChannels(0, decl); }
229         public FabricTree(FpgaPump[] ports, String component, String prefix) {
230             this.prefix = prefix;
231             root = (Node)mkNode("", component, ports, 0, ports.length, 0, 0);
232         }
233         private Object mkNode(String name, String component, FpgaPump[] ports,
234                               int start, int end, int addr, int bits) {
235             if (end-start == 0) return null;
236             if (end-start == 1) {
237                 FpgaPump p = ports[start];
238                 if (prefix.equals("instruction")) {
239                     p.instr_addr = (addr<<1);
240                     p.instr_bits = bits+1;
241                 } else if (prefix.equals("dest")) {
242                     p.addr = (addr << 1) | 1;
243                     p.bits = bits+1;
244                     if (bits >= 11)
245                         throw new RuntimeException("too many pumps!");
246                     int count = 0;
247                     for(Destination d : p.getDestinations()) {
248                         if (!(d instanceof FpgaPump.VirtualPort)) continue;
249                         FpgaPump.VirtualPort vp = (FpgaPump.VirtualPort)d;
250                         vp.addr = p.addr | (count << bits);
251                         count++;
252                     }
253                 }
254                 return p;
255             }
256             int len = end-start;
257             int count   = 0;
258             int count2  = 0;
259             int breakpt = 0;
260             if (end-start <= 2) {
261                 breakpt = (start+end)/2;
262             } else {
263                 for(int i=start; i<end; i++)
264                     count += count(ports[i].getDestinations());
265                 for(int i=start; i<end-1; i++) {
266                     count2 += count(ports[i].getDestinations());
267                     breakpt = i;
268                     if (i>start && count2 >= count/2) break;
269                 }
270             }
271             return new Node(name,
272                             component,
273                             mkNode(name+"_0", component, ports, start, breakpt, addr,               bits+1),
274                             mkNode(name+"_1", component, ports, breakpt, end,   addr | (1 << bits), bits+1),
275                             addr,
276                             bits);
277         }
278         private String describe(String prefix, Object o) {
279             if (o==null) return null;
280             if (o instanceof FpgaPump) {
281                 FpgaPump p = (FpgaPump)o;
282                 return prefix+"_"+getUniqueName(p.getShip())+"_"+p.getName();
283             }
284             if (o instanceof Node) {
285                 return ((Node)o).describe(prefix);
286             }
287             return null;
288         }
289         private class Node {
290             Object left;
291             Object right;
292             String name;
293             String component;
294             int addr;
295             int bits;
296             public Node(String name, String component, Object left, Object right, int addr, int bits) {
297                 this.left = left;
298                 this.right = right;
299                 this.name = name;
300                 this.component = component;
301                 this.addr = addr;
302                 this.bits = bits;
303             }
304             public void dumpChannels(int indentamount, boolean decl) {
305                 String indent = "";
306                 for(int i=0; i<indentamount; i++) indent += "  ";
307                 if (decl) {
308                     String n = describe(prefix).startsWith("instruction")
309                         ? "[(`PACKET_WIDTH-1):0]" : "[(`PACKET_WIDTH-1):0]";
310                     System.out.println("  wire "+n+" "+indent+describe(prefix)+";");
311                 } else {
312                     System.out.println("     "+indent+
313                                        component+" "+
314                                        "krunk"+(krunk++)+"(clk, "+
315                                        describe(prefix)+"_r, "+
316                                        describe(prefix)+"_a, "+
317                                        describe(prefix)+", "+
318                                        FabricTree.this.describe(prefix, left)+"_r, "+
319                                        FabricTree.this.describe(prefix, left)+"_a, "+
320                                        FabricTree.this.describe(prefix, left)+", "+
321                                        FabricTree.this.describe(prefix, right)+"_r, "+
322                                        FabricTree.this.describe(prefix, right)+"_a, "+
323                                        FabricTree.this.describe(prefix, right)+
324                                        ");");
325                 }
326                 dumpChannels(left, indentamount+1, decl);
327                 dumpChannels(right, indentamount+1, decl);
328             }
329             public void dumpChannels(Object o, int indentamount, boolean decl) {
330                 if (o==null) return;
331                 if (o instanceof Node) {
332                     ((Node)o).dumpChannels(indentamount, decl);
333                 } else {
334                     String indent = "";
335                     for(int i=0; i<indentamount; i++) indent += "  ";
336                     if (decl) {
337                         String n = FabricTree.this.describe(prefix,o).startsWith("instruction")
338                             ? "[(`PACKET_WIDTH-1):0]" : "[(`PACKET_WIDTH-1):0]";
339                         System.out.println("  wire "+n+" "+indent+FabricTree.this.describe(prefix,o)+";");
340                     }
341                 }
342             }
343             public String describe(String prefix) {
344                 return prefix+name;
345             }
346         }
347     }
348     public static int krunk=0;
349
350     private static String getUniqueName(Ship ship) {
351         return ship.getType() + ship.getOrdinal();
352     }
353
354     private static int count(Iterable<Destination> it) {
355         int ret = 0;
356         for(Destination d : it)
357             ret++;
358         return ret;
359     }
360
361     public void expand(ShipDescription sd) {
362         try {
363             if (sd.getSection("fpga")==null) return;
364             String filename = sd.getName().toLowerCase();
365             File outf = new File("build/fpga/"+filename+".v");
366             new File(outf.getParent()).mkdirs();
367             System.err.println("writing to " + outf);
368             FileOutputStream out = new FileOutputStream(outf);
369             PrintWriter pw = new PrintWriter(out);
370
371             boolean auto =
372                 !"debug".equals(filename) &&
373                 !"execute".equals(filename) &&
374                 !"memory".equals(filename) &&
375                 !"fifo".equals(filename);
376             if (auto) {
377                 pw.println("`include \"macros.v\"");
378                 pw.println();
379                 pw.println("module " + filename + "( clk");
380                 for(PumpDescription bb : sd) {
381                     String bb_name = bb.getName();
382                     pw.print("        ");
383                     if (bb.isInbox()) {
384                         pw.print(", " + bb_name+"_r");
385                         pw.print(", " + bb_name+"_a_");
386                         pw.print(", " + bb_name+"_d");
387                     } else {
388                         pw.print(", " + bb_name+"_r_");
389                         pw.print(", " + bb_name+"_a");
390                         pw.print(", " + bb_name+"_d_");
391                     }
392                     pw.println();
393                 }
394                 pw.println("        );");
395                 pw.println();
396                 pw.println("    input clk;");
397                 for(PumpDescription bb : sd) {
398                     String bb_name = bb.getName();
399                     pw.print("        ");
400                     if (bb.isInbox()) {
401                         pw.println("`input(" +
402                                    bb_name+"_r,  "+
403                                    bb_name+"_a,  "+
404                                    bb_name+"_a_, "+
405                                    "[(`PACKET_WIDTH-1):0],"+
406                                    bb_name+"_d)"
407                                    );
408                     } else {
409                         pw.println("`output(" +
410                                    bb_name+"_r,  "+
411                                    bb_name+"_r_, "+
412                                    bb_name+"_a,  "+
413                                    "[(`PACKET_WIDTH-1):0],"+
414                                    bb_name+"_d_)"
415                                    );
416                         pw.println("`defreg(" +
417                                    bb_name+"_d_,  "+
418                                    "[(`PACKET_WIDTH-1):0],"+
419                                    bb_name+"_d)"
420                                    );
421                     }
422                     pw.println();
423                 }
424             }
425
426             pw.println(sd.getSection("fpga"));
427
428             if (auto)
429                 pw.println("endmodule");
430
431             pw.flush();
432             pw.close();
433         } catch (Exception e) { throw new RuntimeException(e); }
434     }
435
436     public int computeOffset(int origin, int target) { return (target - origin)/6; }
437     public int computeTarget(int origin, int offset) { return origin + (offset*6); }
438
439     private FpgaInstructionEncoder iie = new FpgaInstructionEncoder();
440     public Instruction readInstruction(DataInputStream is) throws IOException { return iie.readInstruction(is); }
441     public Instruction readInstruction(long instr) { return iie.readInstruction(instr); }
442     public long writeInstruction(Instruction d) { return writeInstruction(d); }
443     public void writeInstruction(DataOutputStream os, Instruction d) throws IOException { iie.writeInstruction(os, d); }
444
445     private class FpgaInstructionEncoder extends InstructionEncoder {
446         public long getDestAddr(Destination box) { return ((FpgaPump.VirtualPort)box).addr; }
447         public long getBoxInstAddr(Pump box) { return ((FpgaPump)box).instr_addr; }
448         public Destination getDestByAddr(long dest) {
449             for(Ship ship : Fpga.this)
450                 for(Pump bb : ship.getPumps())
451                     for(Destination d : bb.getDestinations())
452                         if (getDestAddr(d)==dest)
453                             return d;
454             return null;
455         }
456         public Pump getBoxByInstAddr(long dest) {
457             for(Ship ship : Fpga.this)
458                 for(Pump bb : ship.getPumps())
459                     if (((FpgaPump)bb).instr_addr == dest)
460                         return bb;
461             return null;
462         }
463     }
464
465 }