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