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