massive overhaul of fpga code
[fleet.git] / src / edu / berkeley / fleet / fpga / FpgaDock.java
1 package edu.berkeley.fleet.fpga;
2 import edu.berkeley.fleet.api.*;
3 import edu.berkeley.fleet.two.*;
4 import edu.berkeley.fleet.*;
5 import java.lang.reflect.*;
6 import edu.berkeley.sbp.chr.*;
7 import edu.berkeley.sbp.misc.*;
8 import edu.berkeley.sbp.meta.*;
9 import edu.berkeley.sbp.util.*;
10 import java.util.*;
11 import java.io.*;
12 import static edu.berkeley.fleet.two.FleetTwoFleet.*;
13 import static edu.berkeley.fleet.fpga.verilog.Verilog.*;
14 import edu.berkeley.fleet.api.*;
15 import edu.berkeley.fleet.api.Dock;
16 import edu.berkeley.fleet.two.*;
17 import java.util.*;
18
19 /** the pump itself is a */
20 public class FpgaDock extends FleetTwoDock implements FabricElement {
21
22     private static final int INSTRUCTION_FIFO_SIZE = 16;
23     private static final int EPILOGUE_FIFO_SIZE    = 0;
24     private static final int DATA_FIFO_SIZE        = 16;
25         
26     private FpgaDestination dataDestination;
27     private FpgaDestination instructionDestination;
28
29     private Module.InstantiatedModule instance;
30
31     public Module.InstantiatedModule getInstance() { return instance; }
32
33     public Destination getDataDestination() { return dataDestination; }
34     public Destination getInstructionDestination() { return instructionDestination; }
35     public int         getInstructionFifoSize() { return INSTRUCTION_FIFO_SIZE; }
36
37     FpgaDock(FpgaShip ship, DockDescription bbd) {
38         super(ship, bbd);
39         this.instance = new Module.InstantiatedModule(((Fpga)ship.getFleet()).top, new DockModule(isInputDock()));
40         this.dataDestination = new FpgaDestination(this, this.instance.getInputPort("fabric_in"), false);
41         this.instructionDestination = new FpgaDestination(this, this.instance.getInputPort("instruction"), true);
42         Module.InstantiatedModule shipm = ship.getVerilogModule();            
43         if (isInputDock()) {
44             instance.getOutputPort("ship").connect(shipm.getInputPort(getName()));
45         } else {
46             shipm.getOutputPort(getName()).connect(instance.getInputPort("ship"));
47         }
48     }
49
50
51     // FabricElement methods //////////////////////////////////////////////////////////////////////////////
52
53     private FabricElement upstream;
54     public Module.SourcePort getOutputPort() { throw new RuntimeException(); }
55     public Module.Port getInputPort()  { throw new RuntimeException(); }
56     public FpgaPath getPath(FabricElement dest, BitVector signal) { return upstream.getPath((FabricElement)dest, signal); }
57     public FpgaPath getPath(Destination dest,BitVector signal) { return upstream.getPath((FabricElement)dest, signal); }
58     public void addInput(FabricElement in, Module.Port inPort) { throw new RuntimeException(); }
59     public void addOutput(FabricElement out, Module.Port outPort) {
60         this.upstream = out;
61         instance.getOutputPort("fabric_out").connect((Module.SinkPort)outPort);
62     }
63
64     public static class TorpedoBranchModule extends Module {
65         public TorpedoBranchModule() {
66             super("torpedobranch");
67             Module.SourcePort in      = createInputPort ("in",  WIDTH_PACKET);
68             // FIXME: assumes DISPATCH_PATH is at top of word!!!
69             Module.SinkPort   out     = createOutputPort("out", WIDTH_WORD-DISPATCH_PATH.valmaskwidth, "");
70             Module.SinkPort   torpedo = createOutputPort("torpedo", 0, "");
71             in.hasLatch = false;
72             out.hasLatch = false;
73             torpedo.hasLatch = false;
74
75             addPreCrap("assign out        = `packet_data(in);");
76             addPreCrap("assign out_r      = in_r && !("+PACKET_TOKEN.verilogVal("in")+");");
77             addPreCrap("assign torpedo_r  = in_r &&   "+PACKET_TOKEN.verilogVal("in")+";");
78             addPreCrap("assign in_a       = out_a || torpedo_a;");
79         }
80     }
81
82     public static class FanoutModule extends Module {
83         public FanoutModule(int width) {
84             super("fanout"+width);
85             Module.SourcePort in   = createInputPort ("in",   width);
86             Module.SinkPort   out0 = createOutputPort("out0", width, "");
87             Module.SinkPort   out1 = createOutputPort("out1", width, "");
88             in.hasLatch = false;
89             out0.hasLatch = false;
90             out1.hasLatch = false;
91             addPreCrap("assign out0 = in;");
92             addPreCrap("assign out1 = in;");
93             addPreCrap("assign out0_r = in_r;");
94             addPreCrap("assign out1_r = in_r;");
95             addPreCrap("reg in_a__;");
96             addPreCrap("assign in_a = in_a__;");
97             addPreCrap("always @(posedge clk) begin if (out0_a && out1_a) in_a__ <= 1; if (!out0_a && !out1_a) in_a__ <= 0; end");
98         }
99     }
100
101     public static class RequeueModule extends Module {
102         public RequeueModule() {
103             super("requeue");
104             Module.SourcePort fabric_in = createInputPort ("fabric_in",  WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
105             Module.SourcePort ondeck_in = createInputPort ("ondeck_in",  WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
106             Module.SourcePort olc_in    = createInputPort ("olc_in",     SET_OLC_FROM_IMMEDIATE.valmaskwidth);
107             Module.SinkPort   out       = createOutputPort("out",        WIDTH_WORD-DISPATCH_PATH.valmaskwidth, "");
108             out.hasLatch = true;
109
110             Module.StateWire  using       = new StateWire("using", false);
111             Module.StateWire  circulating = new StateWire("circulating", false);
112
113             // always: discard one-shot instructions
114             new Event(new Object[] { ondeck_in, /*olc_in,*/ OS.verilog(ondeck_in.getName()) },
115                       new Action[] { ondeck_in, /*olc_in */});
116
117             new Event(new Object[] { circulating.isEmpty(),                  fabric_in, TAIL.verilog(fabric_in.getName()) },
118                       new Action[] { circulating.doFill(),                   fabric_in });
119             new Event(new Object[] { circulating.isEmpty(),                  fabric_in, "!("+TAIL.verilog(fabric_in.getName())+")" },
120                       new Action[] {                                         fabric_in, out, new AssignAction(out, fabric_in) });
121             new Event(new Object[] { using.isEmpty(),                        ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in==0" },
122                       new Action[] {                                         ondeck_in, /*olc_in */ });
123             new Event(new Object[] { using.isEmpty(),                        ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in!=0" },
124                       new Action[] { using.doFill() });
125             new Event(new Object[] { circulating.isFull(),  using.isFull(),  ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in==0" },
126                       new Action[] { circulating.doDrain(), using.doDrain(), ondeck_in, /*olc_in */});
127             new Event(new Object[] { circulating.isFull(),  using.isFull(),  ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in!=0" },
128                       new Action[] {                                         ondeck_in, out, /*olc_in,*/ new AssignAction(out, ondeck_in) });
129
130         }
131     }
132
133     public static class DockModule extends Module {
134
135         public DockModule(boolean inbox) {
136             super(inbox ? "inbox" : "outbox");
137
138             int dfifo_width = inbox ? WIDTH_WORD+1 : 1;
139
140             // FIXME: assumes DISPATCH_PATH is at top of word!!!
141             Module ififo_m   = new FifoModule(INSTRUCTION_FIFO_SIZE, WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
142             Module dfifo_m   = new FifoModule(DATA_FIFO_SIZE,        dfifo_width);
143
144             Module.SourcePort instruction   = createInputPort("instruction", WIDTH_PACKET);
145             Module.SourcePort fabric_in     = createInputPort("fabric_in",   WIDTH_PACKET);
146
147             // FIXME: at inboxes, no need for a full set of latches
148             Module.SinkPort   fabric_out    = createOutputPort("fabric_out", WIDTH_PACKET, "");
149             
150             Module.InstantiatedModule dfifo = new Module.InstantiatedModule(this, dfifo_m);
151
152             fabric_in.hasLatch = false;
153             addPreCrap("assign "+dfifo.getInputPort("in").getName()+"_r = fabric_in_r;\n");
154             addPreCrap("assign fabric_in_a = "+dfifo.getInputPort("in").getName()+"_a;\n");
155             if (inbox)
156                 addPreCrap("assign "+dfifo.getInputPort("in").getName()+
157                            " = { "+PACKET_SIGNAL.verilogVal("fabric_in")+
158                            ",    "+PACKET_DATA.verilogVal("fabric_in")+" };\n");
159             else
160                 addPreCrap("assign "+dfifo.getInputPort("in").getName()+
161                            " = "+PACKET_SIGNAL.verilogVal("fabric_in")+";\n");
162
163         
164             Module.SourcePort dfifo_out = dfifo.getOutputPort("out");
165             Module.SourcePort   ship_out    = null;
166             if (!inbox) {
167                 ship_out = createInputPort("ship",        WIDTH_WORD+1);
168                 ship_out.hasLatch = true;
169             }
170
171             Module.SinkPort   ship_in     = null;
172             if (inbox) {
173                 ship_in = createOutputPort("ship",        WIDTH_WORD+1, "");
174                 ship_in.hasLatch = true;
175             }
176
177             Module.Latch     repeat_counter = new Latch("repeat_counter", SET_ILC_FROM_IMMEDIATE.valmaskwidth+1, 1);
178             Module.Latch     loop_counter   = new Latch("loop_counter", SET_OLC_FROM_IMMEDIATE.valmaskwidth, 1);
179             Module.Latch     flag_a         = new Latch("flag_a", 1);
180             Module.Latch     flag_b         = new Latch("flag_b", 1);
181             Module.Latch     flag_c         = new Latch("flag_c", 1);
182
183             Module.StateWire  torpedoWaiting = new StateWire("torpedoWaiting", false);
184         
185             Module.SinkPort   token_out     = fabric_out;
186             Module.SourcePort token_in      = dfifo_out;
187             Module.SinkPort   data_out      = inbox ? ship_in   : fabric_out;
188             Module.SourcePort data_in       = inbox ? dfifo_out : ship_out;
189
190             Module.InstantiatedModule ififo = new Module.InstantiatedModule(this, ififo_m);
191             Module.SinkPort   ififo_in      = ififo.getInputPort("in");
192             Module.SourcePort ififo_out     = ififo.getOutputPort("out");
193
194             Module.SinkPort data_latch_output_p = createWirePort("data_latch_output", inbox ? WIDTH_WORD+1 : WIDTH_WORD);
195
196             Module.InstantiatedModule torpedo_branch = new Module.InstantiatedModule(this, new TorpedoBranchModule());
197             instruction.connect(torpedo_branch.getInputPort("in"));
198             Module.SourcePort efifo_out              = torpedo_branch.getOutputPort("out");
199             Module.SourcePort torpedo_branch_torpedo = torpedo_branch.getOutputPort("torpedo");
200
201             Module.InstantiatedModule fanout_module = new Module.InstantiatedModule(this, new FanoutModule(WIDTH_WORD-DISPATCH_PATH.valmaskwidth));
202             Module.SinkPort   fanout_module_in   = fanout_module.getInputPort("in");
203             Module.SourcePort fanout_module_out0 = fanout_module.getOutputPort("out0");
204             Module.SourcePort fanout_module_out1 = fanout_module.getOutputPort("out1");
205
206             Module.InstantiatedModule requeue_module = new Module.InstantiatedModule(this, new RequeueModule());
207             Module.SinkPort   requeue_fabric_in = requeue_module.getInputPort("fabric_in");
208             Module.SinkPort   requeue_ondeck    = requeue_module.getInputPort("ondeck_in");
209             Module.SinkPort   requeue_olc_in    = requeue_module.getInputPort("olc_in");
210             Module.SourcePort requeue_out       = requeue_module.getOutputPort("out");
211
212             efifo_out.connect(requeue_fabric_in);
213             requeue_out.connect(ififo_in);
214             ififo_out.connect(fanout_module_in);
215             fanout_module_out0.connect(requeue_ondeck);
216             Module.SourcePort ondeck = fanout_module_out1;
217
218             addPreCrap("assign data_latch_output = " + (inbox ? data_out.getName() : "`packet_data("+data_out.getName()+")")+";");
219             addPreCrap("wire ["+(Math.max(repeat_counter.width,loop_counter.width)-1)+":0] decremented;");
220             addPreCrap("assign decremented = ("+SET_OLC_FROM_OLC_MINUS_ONE.verilog(ondeck.getName())+" ? {1'b0, loop_counter} : repeat_counter)-1;");
221             addPreCrap("assign "+requeue_olc_in.getName()+" = loop_counter;");
222
223             Assignable data_latch    = new SimpleAssignable(inbox ? data_out.getName() : "`packet_data("+data_out.getName()+")");
224             String data_latch_input  = inbox ? data_in.getName() : data_in.getName();
225
226             String magic_standing_value = "(1<<"+SET_ILC_FROM_IMMEDIATE.valmaskwidth+")";
227             String done_executing       = "(repeat_counter==0 || repeat_counter==1 || !"+MOVE.verilog(ondeck.getName())+")";
228
229             // Torpedo Arrival
230             new Event(new Object[] { torpedo_branch_torpedo, torpedoWaiting.isEmpty() },
231                       new Action[] { torpedo_branch_torpedo, torpedoWaiting.doFill() });
232
233             String predicate_met = 
234                 "("+
235                 "("+
236                 "!"+MOVE.verilog(ondeck.getName())+" || repeat_counter!=0"+
237                 ") && ("+
238                 "("+
239                 P_ALWAYS.verilog(ondeck.getName())+
240                 ") || ("+
241                 P_OLC_ZERO.verilog(ondeck.getName())+"==(loop_counter==0)"+
242                 ")"+
243                 ") && ("+
244                 " " + P_A.verilog(ondeck.getName())+" ? flag_a"+
245                 ":" + P_B.verilog(ondeck.getName())+" ? flag_b"+
246                 ":" + P_NOT_A.verilog(ondeck.getName())+" ? !flag_a"+
247                 ":" + P_NOT_B.verilog(ondeck.getName())+" ? !flag_b "+
248                 ": 1"+
249                 ")"+
250                 ")";
251
252             // Torpedo strikes
253             new Event(new Object[] {
254                     ondeck,
255                     data_out,
256                     token_out,
257                     predicate_met,
258                     MOVE.verilog(ondeck.getName()),
259                     I.verilog(ondeck.getName()),
260                     torpedoWaiting.isFull()
261                 },
262                 new Object[] {
263                     ondeck,
264                     torpedoWaiting.doDrain(),
265                     new AssignAction(loop_counter, "0"),
266                     new AssignAction(repeat_counter, "1")
267                 });
268
269             // Predicate not met
270             new Event(new Object[] { ondeck, "!("+predicate_met+")" },
271                       new Action[] { ondeck });
272
273             new Event(new Object[] { ondeck,
274                                      data_out,
275                                      token_out,
276                                      predicate_met,
277                                      "(!"+MOVE.verilog(ondeck.getName())+" || !"+I.verilog(ondeck.getName())+" || !"+torpedoWaiting.isFull()+")",
278                                      new ConditionalTrigger(DI.verilog(ondeck.getName()), data_in),
279                                      new ConditionalTrigger(TI.verilog(ondeck.getName()), token_in)
280                       },
281                       new Action[] { 
282                           new ConditionalAction(done_executing+" && "+MOVE.verilog(ondeck.getName()), new AssignAction(repeat_counter, "1")),
283                           new ConditionalAction(done_executing, ondeck),
284                           new ConditionalAction("!"+done_executing,
285                                                 new AssignAction(repeat_counter,
286                                                                  "repeat_counter=="+magic_standing_value+"?"+magic_standing_value+":decremented")),
287
288                           new ConditionalAction(SET_OLC_FROM_DATA_LATCH.verilog(ondeck.getName()), new AssignAction(loop_counter, "data_latch_output")),
289                           new ConditionalAction(SET_OLC_FROM_IMMEDIATE.verilog(ondeck.getName()),
290                                                 new AssignAction(loop_counter, SET_OLC_FROM_IMMEDIATE.verilogVal(ondeck.getName()))),
291                           new ConditionalAction(SET_OLC_FROM_OLC_MINUS_ONE.verilog(ondeck.getName()),
292                                                 new AssignAction(loop_counter, "loop_counter==0 ? 0 : decremented")),
293                           new ConditionalAction(SET_ILC_FROM_DATA_LATCH.verilog(ondeck.getName()), new AssignAction(repeat_counter, "data_latch_output")),
294                           new ConditionalAction(SET_ILC_FROM_IMMEDIATE.verilog(ondeck.getName()),
295                                                 new AssignAction(repeat_counter, SET_ILC_FROM_IMMEDIATE.verilogVal(ondeck.getName()))),
296                           new ConditionalAction(SET_ILC_FROM_INFINITY.verilog(ondeck.getName()), new AssignAction(repeat_counter, magic_standing_value)),
297                           new ConditionalAction(SHIFT.verilog(ondeck.getName()),
298                                                 new AssignAction(data_latch,
299                                                                  "{ data_latch_output["+(WIDTH_WORD-1-SHIFT.valmaskwidth)+":0], "+
300                                                                  SHIFT.verilogVal(ondeck.getName())+"}")),
301                           new ConditionalAction(SET_IMMEDIATE.verilog(ondeck.getName()),
302                                                 new AssignAction(data_latch,
303                                                                  "{ {"+(WIDTH_WORD-FleetTwoFleet.DataLatch_WIDTH)+
304                                                                  "{"+SET_IMMEDIATE_EXTEND.verilogVal(ondeck.getName())+"}}, "+
305                                                                  SET_IMMEDIATE.verilogVal(ondeck.getName())+" }")),
306                           new ConditionalAction(SET_FLAGS.verilog(ondeck.getName()), new AssignAction(flag_a, "`new_flag_a("+ondeck.getName()+")")),
307                           new ConditionalAction(SET_FLAGS.verilog(ondeck.getName()), new AssignAction(flag_b, "`new_flag_b("+ondeck.getName()+")")),
308                           new ConditionalAction(inbox
309                                                 ? "("+DI.verilog(ondeck.getName())+" || "+TI.verilog(ondeck.getName())+")"
310                                                 : "(!"+DI.verilog(ondeck.getName())+" && "+TI.verilog(ondeck.getName())+")",
311                                                 new AssignAction(flag_c, dfifo_out.getBits(dfifo_width-1, dfifo_width-1))),
312                           new ConditionalAction(DI.verilog(ondeck.getName()),    data_in),
313                           new ConditionalAction(DO.verilog(ondeck.getName()),    data_out),
314                           new ConditionalAction(FLUSH.verilog(ondeck.getName()), data_out),
315                           inbox
316                           ? new AssignAction(new SimpleAssignable(data_out.getName()+"["+WIDTH_WORD+"]"), FLUSH.verilog(ondeck.getName())+"?1:0")
317                           : new ConditionalAction(DI.verilog(ondeck.getName()),   new AssignAction(flag_c, data_latch_input+"["+WIDTH_WORD+"]")),
318                           new ConditionalAction(TI.verilog(ondeck.getName()),    token_in),
319                           new ConditionalAction(TO.verilog(ondeck.getName()),    token_out),
320                           new ConditionalAction(DC.verilog(ondeck.getName()),   new AssignAction(data_latch, data_latch_input)),
321                           new AssignAction(new SimpleAssignable("`packet_token("+token_out.getName()+")"), "("+TO.verilog(ondeck.getName())+")?1:0"),
322                           new ConditionalAction(PATH_DATA.verilog(ondeck.getName()),
323                                                 new AssignAction(new SimpleAssignable("{ "+PACKET_SIGNAL.verilogVal(token_out.getName())+", "+
324                                                                                       PACKET_DEST.verilogVal(token_out.getName())+" }"),
325                                                                  DISPATCH_PATH.verilogVal(data_latch_input))),
326                           new ConditionalAction(PATH_IMMEDIATE.verilog(ondeck.getName()),
327                                                 new AssignAction(new SimpleAssignable("{ "+PACKET_SIGNAL.verilogVal(token_out.getName())+", "+
328                                                                                       PACKET_DEST.verilogVal(token_out.getName())+" }"),
329                                                                  PATH_IMMEDIATE.verilogVal(ondeck.getName()))),
330                       }
331                       );
332         }
333
334         public void dump(PrintWriter pw, boolean fix) {
335             pw.println("`define new_flag(x)         ("+
336                        "( ((x >> 0) & 1) & !flag_c) |" +
337                        "( ((x >> 1) & 1) &  flag_c) |" +
338                        "( ((x >> 2) & 1) & !flag_b) |" +
339                        "( ((x >> 3) & 1) &  flag_b) |" +
340                        "( ((x >> 4) & 1) & !flag_a) |" +
341                        "( ((x >> 5) & 1) &  flag_a) | 0" +
342                        ")");
343             pw.println("`define new_flag_a(i)                   `new_flag("+SET_FLAGS_A.verilogVal("i")+")");
344             pw.println("`define new_flag_b(i)                   `new_flag("+SET_FLAGS_B.verilogVal("i")+")");
345             super.dump(pw,fix);
346         }
347     }
348 }