move FanoutModule into its own file
[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 RequeueModule extends Module {
83         public RequeueModule() {
84             super("requeue");
85             Module.SourcePort fabric_in = createInputPort ("fabric_in",  WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
86             Module.SourcePort ondeck_in = createInputPort ("ondeck_in",  WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
87             Module.SourcePort olc_in    = createInputPort ("olc_in",     SET_OLC_FROM_IMMEDIATE.valmaskwidth);
88             Module.SinkPort   out       = createOutputPort("out",        WIDTH_WORD-DISPATCH_PATH.valmaskwidth, "");
89             out.hasLatch = true;
90
91             Module.StateWire  using       = new StateWire("using", false);
92             Module.StateWire  circulating = new StateWire("circulating", false);
93
94             // always: discard one-shot instructions
95             new Event(new Object[] { ondeck_in, /*olc_in,*/ OS.verilog(ondeck_in.getName()) },
96                       new Action[] { ondeck_in, /*olc_in */});
97
98             new Event(new Object[] { circulating.isEmpty(),                  fabric_in, TAIL.verilog(fabric_in.getName()) },
99                       new Action[] { circulating.doFill(),                   fabric_in });
100             new Event(new Object[] { circulating.isEmpty(),                  fabric_in, "!("+TAIL.verilog(fabric_in.getName())+")" },
101                       new Action[] {                                         fabric_in, out, new AssignAction(out, fabric_in) });
102             new Event(new Object[] { using.isEmpty(),                        ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in==0" },
103                       new Action[] {                                         ondeck_in, /*olc_in */ });
104             new Event(new Object[] { using.isEmpty(),                        ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in!=0" },
105                       new Action[] { using.doFill() });
106             new Event(new Object[] { circulating.isFull(),  using.isFull(),  ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in==0" },
107                       new Action[] { circulating.doDrain(), using.doDrain(), ondeck_in, /*olc_in */});
108             new Event(new Object[] { circulating.isFull(),  using.isFull(),  ondeck_in, /*olc_in,*/   "!("+OS.verilog(ondeck_in.getName())+")", "olc_in!=0" },
109                       new Action[] {                                         ondeck_in, out, /*olc_in,*/ new AssignAction(out, ondeck_in) });
110
111         }
112     }
113
114     public static class DockModule extends Module {
115
116         public DockModule(boolean inbox) {
117             super(inbox ? "inbox" : "outbox");
118
119             int dfifo_width = inbox ? WIDTH_WORD+1 : 1;
120
121             // FIXME: assumes DISPATCH_PATH is at top of word!!!
122             Module ififo_m   = new FifoModule(INSTRUCTION_FIFO_SIZE, WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
123             Module dfifo_m   = new FifoModule(DATA_FIFO_SIZE,        dfifo_width);
124
125             Module.SourcePort instruction   = createInputPort("instruction", WIDTH_PACKET);
126             Module.SourcePort fabric_in     = createInputPort("fabric_in",   WIDTH_PACKET);
127
128             // FIXME: at inboxes, no need for a full set of latches
129             Module.SinkPort   fabric_out    = createOutputPort("fabric_out", WIDTH_PACKET, "");
130             
131             Module.InstantiatedModule dfifo = new Module.InstantiatedModule(this, dfifo_m);
132
133             fabric_in.hasLatch = false;
134             addPreCrap("assign "+dfifo.getInputPort("in").getName()+"_r = fabric_in_r;\n");
135             addPreCrap("assign fabric_in_a = "+dfifo.getInputPort("in").getName()+"_a;\n");
136             if (inbox)
137                 addPreCrap("assign "+dfifo.getInputPort("in").getName()+
138                            " = { "+PACKET_SIGNAL.verilogVal("fabric_in")+
139                            ",    "+PACKET_DATA.verilogVal("fabric_in")+" };\n");
140             else
141                 addPreCrap("assign "+dfifo.getInputPort("in").getName()+
142                            " = "+PACKET_SIGNAL.verilogVal("fabric_in")+";\n");
143
144         
145             Module.SourcePort dfifo_out = dfifo.getOutputPort("out");
146             Module.SourcePort   ship_out    = null;
147             if (!inbox) {
148                 ship_out = createInputPort("ship",        WIDTH_WORD+1);
149                 ship_out.hasLatch = true;
150             }
151
152             Module.SinkPort   ship_in     = null;
153             if (inbox) {
154                 ship_in = createOutputPort("ship",        WIDTH_WORD+1, "");
155                 ship_in.hasLatch = true;
156             }
157
158             Module.Latch     ilc = new Latch("ilc", SET_ILC_FROM_IMMEDIATE.valmaskwidth+1, 1);
159             Module.Latch     olc   = new Latch("olc", SET_OLC_FROM_IMMEDIATE.valmaskwidth, 1);
160             Module.Latch     flag_a         = new Latch("flag_a", 1);
161             Module.Latch     flag_b         = new Latch("flag_b", 1);
162             Module.Latch     flag_c         = new Latch("flag_c", 1);
163
164             Module.StateWire  torpedoWaiting = new StateWire("torpedoWaiting", false);
165         
166             Module.SinkPort   token_out     = fabric_out;
167             Module.SourcePort token_in      = dfifo_out;
168             Module.SinkPort   data_out      = inbox ? ship_in   : fabric_out;
169             Module.SourcePort data_in       = inbox ? dfifo_out : ship_out;
170
171             Module.InstantiatedModule ififo = new Module.InstantiatedModule(this, ififo_m);
172             Module.SinkPort   ififo_in      = ififo.getInputPort("in");
173             Module.SourcePort ififo_out     = ififo.getOutputPort("out");
174
175             Module.SinkPort data_latch_output_p = createWirePort("data_latch_output", inbox ? WIDTH_WORD+1 : WIDTH_WORD);
176
177             Module.InstantiatedModule torpedo_branch = new Module.InstantiatedModule(this, new TorpedoBranchModule());
178             instruction.connect(torpedo_branch.getInputPort("in"));
179             Module.SourcePort efifo_out              = torpedo_branch.getOutputPort("out");
180             Module.SourcePort torpedo_branch_torpedo = torpedo_branch.getOutputPort("torpedo");
181
182             Module.InstantiatedModule fanout_module = new Module.InstantiatedModule(this, new FanoutModule(WIDTH_WORD-DISPATCH_PATH.valmaskwidth));
183             Module.SinkPort   fanout_module_in   = fanout_module.getInputPort("in");
184             Module.SourcePort fanout_module_out0 = fanout_module.getOutputPort("out0");
185             Module.SourcePort fanout_module_out1 = fanout_module.getOutputPort("out1");
186
187             Module.InstantiatedModule requeue_module = new Module.InstantiatedModule(this, new RequeueModule());
188             Module.SinkPort   requeue_fabric_in = requeue_module.getInputPort("fabric_in");
189             Module.SinkPort   requeue_ondeck    = requeue_module.getInputPort("ondeck_in");
190             Module.SinkPort   requeue_olc_in    = requeue_module.getInputPort("olc_in");
191             Module.SourcePort requeue_out       = requeue_module.getOutputPort("out");
192
193             efifo_out.connect(requeue_fabric_in);
194             requeue_out.connect(ififo_in);
195             ififo_out.connect(fanout_module_in);
196             fanout_module_out0.connect(requeue_ondeck);
197             Module.SourcePort ondeck = fanout_module_out1;
198
199             addPreCrap("assign data_latch_output = " + (inbox ? data_out.getName() : "`packet_data("+data_out.getName()+")")+";");
200             addPreCrap("wire ["+(Math.max(ilc.width,olc.width)-1)+":0] decremented;");
201             addPreCrap("assign decremented = ("+SET_OLC_FROM_OLC_MINUS_ONE.verilog(ondeck.getName())+" ? {1'b0, olc} : ilc)-1;");
202             addPreCrap("assign "+requeue_olc_in.getName()+" = olc;");
203
204             Assignable data_latch    = new SimpleAssignable(inbox ? data_out.getName() : "`packet_data("+data_out.getName()+")");
205             String data_latch_input  = inbox ? data_in.getName() : data_in.getName();
206
207             String magic_standing_value = "(1<<"+SET_ILC_FROM_IMMEDIATE.valmaskwidth+")";
208             String done_executing       = "(ilc==0 || ilc==1 || !"+MOVE.verilog(ondeck.getName())+")";
209
210             // Torpedo Arrival
211             new Event(new Object[] { torpedo_branch_torpedo, torpedoWaiting.isEmpty() },
212                       new Action[] { torpedo_branch_torpedo, torpedoWaiting.doFill() });
213
214             String predicate_met = 
215                 "("+
216                 "("+
217                 "!"+MOVE.verilog(ondeck.getName())+" || ilc!=0"+
218                 ") && ("+
219                 "("+
220                 P_ALWAYS.verilog(ondeck.getName())+
221                 ") || ("+
222                 P_OLC_ZERO.verilog(ondeck.getName())+"==(olc==0)"+
223                 ")"+
224                 ") && ("+
225                 " " + P_A.verilog(ondeck.getName())+" ? flag_a"+
226                 ":" + P_B.verilog(ondeck.getName())+" ? flag_b"+
227                 ":" + P_NOT_A.verilog(ondeck.getName())+" ? !flag_a"+
228                 ":" + P_NOT_B.verilog(ondeck.getName())+" ? !flag_b "+
229                 ": 1"+
230                 ")"+
231                 ")";
232
233             // Torpedo strikes
234             new Event(new Object[] {
235                     ondeck,
236                     data_out,
237                     token_out,
238                     predicate_met,
239                     MOVE.verilog(ondeck.getName()),
240                     I.verilog(ondeck.getName()),
241                     torpedoWaiting.isFull()
242                 },
243                 new Object[] {
244                     ondeck,
245                     torpedoWaiting.doDrain(),
246                     new AssignAction(olc, "0"),
247                     new AssignAction(ilc, "1")
248                 });
249
250             // Predicate not met
251             new Event(new Object[] { ondeck, "!("+predicate_met+")" },
252                       new Action[] { ondeck,
253                                      new ConditionalAction(MOVE.verilog(ondeck.getName()), new AssignAction(ilc, "1"))
254                       });
255
256             new Event(new Object[] { ondeck,
257                                      data_out,
258                                      token_out,
259                                      predicate_met,
260                                      "(!"+MOVE.verilog(ondeck.getName())+" || !"+I.verilog(ondeck.getName())+" || !"+torpedoWaiting.isFull()+")",
261                                      new ConditionalTrigger(DI.verilog(ondeck.getName()), data_in),
262                                      new ConditionalTrigger(TI.verilog(ondeck.getName()), token_in)
263                       },
264                       new Action[] { 
265                           new ConditionalAction(done_executing+" && "+MOVE.verilog(ondeck.getName()), new AssignAction(ilc, "1")),
266                           new ConditionalAction(done_executing, ondeck),
267                           new ConditionalAction("!"+done_executing,
268                                                 new AssignAction(ilc,
269                                                                  "ilc=="+magic_standing_value+"?"+magic_standing_value+":decremented")),
270
271                           new ConditionalAction(SET_OLC_FROM_DATA_LATCH.verilog(ondeck.getName()), new AssignAction(olc, "data_latch_output")),
272                           new ConditionalAction(SET_OLC_FROM_IMMEDIATE.verilog(ondeck.getName()),
273                                                 new AssignAction(olc, SET_OLC_FROM_IMMEDIATE.verilogVal(ondeck.getName()))),
274                           new ConditionalAction(SET_OLC_FROM_OLC_MINUS_ONE.verilog(ondeck.getName()),
275                                                 new AssignAction(olc, "olc==0 ? 0 : decremented")),
276                           new ConditionalAction(SET_ILC_FROM_DATA_LATCH.verilog(ondeck.getName()), new AssignAction(ilc, "data_latch_output")),
277                           new ConditionalAction(SET_ILC_FROM_IMMEDIATE.verilog(ondeck.getName()),
278                                                 new AssignAction(ilc, SET_ILC_FROM_IMMEDIATE.verilogVal(ondeck.getName()))),
279                           new ConditionalAction(SET_ILC_FROM_INFINITY.verilog(ondeck.getName()), new AssignAction(ilc, magic_standing_value)),
280                           new ConditionalAction(SHIFT.verilog(ondeck.getName()),
281                                                 new AssignAction(data_latch,
282                                                                  "{ data_latch_output["+(WIDTH_WORD-1-SHIFT.valmaskwidth)+":0], "+
283                                                                  SHIFT.verilogVal(ondeck.getName())+"}")),
284                           new ConditionalAction(SET_IMMEDIATE.verilog(ondeck.getName()),
285                                                 new AssignAction(data_latch,
286                                                                  "{ {"+(WIDTH_WORD-FleetTwoFleet.DataLatch_WIDTH)+
287                                                                  "{"+SET_IMMEDIATE_EXTEND.verilogVal(ondeck.getName())+"}}, "+
288                                                                  SET_IMMEDIATE.verilogVal(ondeck.getName())+" }")),
289                           new ConditionalAction(SET_FLAGS.verilog(ondeck.getName()), new AssignAction(flag_a, new_flag(SET_FLAGS_A.verilogVal(ondeck.getName())))),
290                           new ConditionalAction(SET_FLAGS.verilog(ondeck.getName()), new AssignAction(flag_b, new_flag(SET_FLAGS_B.verilogVal(ondeck.getName())))),
291                           new ConditionalAction(inbox
292                                                 ? "("+DI.verilog(ondeck.getName())+" || "+TI.verilog(ondeck.getName())+")"
293                                                 : "(!"+DI.verilog(ondeck.getName())+" && "+TI.verilog(ondeck.getName())+")",
294                                                 new AssignAction(flag_c, dfifo_out.getBits(dfifo_width-1, dfifo_width-1))),
295                           new ConditionalAction(DI.verilog(ondeck.getName()),    data_in),
296                           new ConditionalAction(DO.verilog(ondeck.getName()),    data_out),
297                           new ConditionalAction(FLUSH.verilog(ondeck.getName()), data_out),
298                           inbox
299                           ? new AssignAction(new SimpleAssignable(data_out.getName()+"["+WIDTH_WORD+"]"), FLUSH.verilog(ondeck.getName())+"?1:0")
300                           : new ConditionalAction(DI.verilog(ondeck.getName()),   new AssignAction(flag_c, data_latch_input+"["+WIDTH_WORD+"]")),
301                           new ConditionalAction(TI.verilog(ondeck.getName()),    token_in),
302                           new ConditionalAction(TO.verilog(ondeck.getName()),    token_out),
303                           new ConditionalAction(DC.verilog(ondeck.getName()),   new AssignAction(data_latch, data_latch_input)),
304                           new AssignAction(new SimpleAssignable("`packet_token("+token_out.getName()+")"), "("+TO.verilog(ondeck.getName())+")?1:0"),
305                           new ConditionalAction(PATH_DATA.verilog(ondeck.getName()),
306                                                 new AssignAction(new SimpleAssignable("{ "+PACKET_SIGNAL.verilogVal(token_out.getName())+", "+
307                                                                                       PACKET_DEST.verilogVal(token_out.getName())+" }"),
308                                                                  DISPATCH_PATH.verilogVal(data_latch_input))),
309                           new ConditionalAction(PATH_IMMEDIATE.verilog(ondeck.getName()),
310                                                 new AssignAction(new SimpleAssignable("{ "+PACKET_SIGNAL.verilogVal(token_out.getName())+", "+
311                                                                                       PACKET_DEST.verilogVal(token_out.getName())+" }"),
312                                                                  PATH_IMMEDIATE.verilogVal(ondeck.getName()))),
313                       }
314                       );
315         }
316
317         private static String new_flag(String x) {
318             return "("+
319                 "( (("+x+" >> 0) & 1) & !flag_c) |" +
320                 "( (("+x+" >> 1) & 1) &  flag_c) |" +
321                 "( (("+x+" >> 2) & 1) & !flag_b) |" +
322                 "( (("+x+" >> 3) & 1) &  flag_b) |" +
323                 "( (("+x+" >> 4) & 1) & !flag_a) |" +
324                 "( (("+x+" >> 5) & 1) &  flag_a) | 0" +
325                 ")";
326         }
327     }
328 }
329