reduce use of verilog macro expansion in FpgaDock
[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 = 12;
23     private static final int EPILOGUE_FIFO_SIZE    = 0;
24     private static final int DATA_FIFO_SIZE        = 12;
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 DockModule extends Module {
65
66         public DockModule(boolean inbox) {
67             super(inbox ? "inbox" : "outbox");
68
69             /*
70               Module horn      = new HornModule();
71               Module funnel    = new FunnelModule();
72               Module.SourcePort instruction   = createInputPort("instruction",       WIDTH_PACKET);
73               Module.SourcePort fabric_in     = createInputPort("fabric_in",   WIDTH_PACKET);
74               Module.SinkPort   fabric_out    = createOutputPort("fabric_out", WIDTH_PACKET, "");
75               if (!inbox) {
76               FunnelModule.FunnelInstance f0 = new FunnelModule.FunnelInstance(this, instruction, fabric_in);
77               Module.SourcePort ship_out = createInputPort("ship",        WIDTH_WORD);
78               FunnelModule.FunnelInstance f1 = new FunnelModule.FunnelInstance(this, f0.getOutputPort(), ship_out);
79               f1.addOutput(f0, fabric_out);
80               } else {
81               Module.SinkPort ship_in = createOutputPort("ship",        WIDTH_PACKET, "");
82               instruction.connect(fabric_out);
83               fabric_in.connect(ship_in);
84               }
85             */
86
87             int dfifo_width = inbox ? WIDTH_WORD+1 : 1;
88
89             // FIXME: assumes DISPATCH_PATH is at top of word!!!
90             Module ififo_m   = new FifoModule(INSTRUCTION_FIFO_SIZE, WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
91             Module efifo_m   = new FifoModule(EPILOGUE_FIFO_SIZE,    WIDTH_WORD-DISPATCH_PATH.valmaskwidth);
92             Module dfifo_m   = new FifoModule(DATA_FIFO_SIZE,        dfifo_width);
93             Module.SourcePort instruction   = createInputPort("instruction", WIDTH_PACKET);
94             instruction.hasLatch = true;
95
96             Module.SourcePort fabric_in     = createInputPort("fabric_in",   WIDTH_PACKET);
97
98             // FIXME: at inboxes, no need for a full set of latches
99             Module.SinkPort   fabric_out    = createOutputPort("fabric_out", WIDTH_PACKET, "");
100             
101             Module.InstantiatedModule dfifo = new Module.InstantiatedModule(this, dfifo_m);
102
103             fabric_in.hasLatch = false;
104             addPreCrap("assign "+dfifo.getInputPort("in").getName()+"_r = fabric_in_r;\n");
105             addPreCrap("assign fabric_in_a = "+dfifo.getInputPort("in").getName()+"_a;\n");
106             if (inbox)
107                 addPreCrap("assign "+dfifo.getInputPort("in").getName()+
108                            " = { "+PACKET_SIGNAL.verilogVal("fabric_in")+
109                            ",    "+PACKET_DATA.verilogVal("fabric_in")+" };\n");
110             else
111                 addPreCrap("assign "+dfifo.getInputPort("in").getName()+
112                            " = "+PACKET_SIGNAL.verilogVal("fabric_in")+";\n");
113
114         
115             Module.SourcePort dfifo_out = dfifo.getOutputPort("out");
116             Module.SourcePort   ship_out    = null;
117             if (!inbox) {
118                 ship_out = createInputPort("ship",        WIDTH_WORD+1);
119                 ship_out.hasLatch = true;
120             }
121
122             Module.SinkPort   ship_in     = null;
123             if (inbox) {
124                 ship_in = createOutputPort("ship",        WIDTH_WORD, "");
125                 ship_in.hasLatch = true;
126             }
127
128             Module.Latch     repeat_counter = new Latch("repeat_counter", SET_ILC_FROM_IMMEDIATE.valmaskwidth+1, 1);
129             Module.Latch     loop_counter   = new Latch("loop_counter", SET_OLC_FROM_IMMEDIATE.valmaskwidth, 1);
130             Module.Latch     flag_a         = new Latch("flag_a", 1);
131             Module.Latch     flag_b         = new Latch("flag_b", 1);
132             Module.Latch     flag_c         = new Latch("flag_c", 1);
133
134             Module.StateWire  isHatchOpen   = new StateWire("hatch", true);
135             Module.StateWire  proceed       = new StateWire("proceed", false);
136         
137             Module.SinkPort   token_out     = fabric_out;
138             Module.SourcePort token_in      = dfifo_out;
139             Module.SinkPort   data_out      = inbox ? ship_in   : fabric_out;
140             Module.SourcePort data_in       = inbox ? dfifo_out : ship_out;
141
142             Module.InstantiatedModule ififo = new Module.InstantiatedModule(this, ififo_m);
143             Module.SinkPort   ififo_in      = ififo.getInputPort("in");
144             ififo_in.hasLatch = false;
145             ififo_in.forceNoLatch = true;
146
147             Module.SourcePort ififo_out     = ififo.getOutputPort("out");
148
149             Module.InstantiatedModule efifo = new Module.InstantiatedModule(this, efifo_m);
150             Module.SinkPort   efifo_in      = efifo.getInputPort("in");
151             Module.SourcePort efifo_out     = efifo.getOutputPort("out");
152             efifo_in.hasLatch = false;
153             efifo_in.forceNoLatch = true;
154
155             Module.SinkPort data_latch_output_p = createWirePort("data_latch_output", WIDTH_WORD);
156             Module.SinkPort data_latch_input_p  = createWirePort("data_latch_input", inbox ? WIDTH_WORD : WIDTH_WORD+1);
157
158             // FIXME
159             addPreCrap("wire ["+(ififo_out.width-1)+":0] ondeck;");
160             addPreCrap("wire ["+(Math.max(repeat_counter.width,loop_counter.width)-1)+":0] decremented;");
161             addPreCrap("assign data_latch_output = " + (inbox ? data_out.getName() : "`packet_data("+data_out.getName()+")")+";");
162             addPreCrap("assign data_latch_input = " + (inbox ? data_in.getName() : data_in.getName())+";");
163             addPreCrap("assign "+efifo_in.getName()+" = `packet_data("+instruction.getName()+");");
164             addPreCrap("assign "+ififo_in.getName()+" = hatch ? "+efifo_out.getName()+" : ondeck;");
165             addPreCrap("assign ondeck = "+ififo_out.getName()+";");
166             addPreCrap("assign decremented = ("+SET_OLC_FROM_OLC_MINUS_ONE.verilog("ondeck")+" ? {1'b0, loop_counter} : repeat_counter)-1;");
167
168             Assignable data_latch    = new SimpleAssignable(inbox ? data_out.getName() : "`packet_data("+data_out.getName()+")");
169             String data_latch_input  = "data_latch_input";
170
171             // Open the Hatch
172             new Event(new Object[] { "loop_counter==0" },
173                       new Action[] { isHatchOpen.doFill() });
174
175             // Torpedo Arrival
176             new Event(new Object[] { instruction,
177                                      PACKET_TOKEN.verilogVal("instruction"),
178                                      ififo_out,
179                                      I.verilog("ondeck") },
180                 new Action[] { instruction,
181                                ififo_out,
182                                new AssignAction(loop_counter, "0"),
183                                new AssignAction(repeat_counter, "1"),
184                                isHatchOpen.doFill() });
185             // Non-Torpedo Arrival
186             new Event(new Object[] { instruction, efifo_in, "!("+PACKET_TOKEN.verilogVal("instruction")+")" },
187                       new Action[] { efifo_in });
188             new Event(new Object[] { efifo_in.getName()+"_a" },
189                       new Action[] { new SimpleAction(instruction.getName()+"_a <= 1;") });
190
191             // Tail
192             new Event(new Object[] { efifo_out, ififo_in, isHatchOpen.isFull(), TAIL.verilog(efifo_out.getName()) },
193                       new Action[] { efifo_out,           isHatchOpen.doDrain() } );
194             // Enqueue
195             new Event(new Object[] { efifo_out, ififo_in, isHatchOpen.isFull(), "!("+TAIL.verilog(efifo_out.getName())+")" },
196                       new Action[] { efifo_out, ififo_in } );
197
198             // Execute                                     
199             new Event(new Object[] { ififo_out, ififo_in, proceed.isFull() },
200                       new Action[] { ififo_out,           proceed.doDrain() });
201             new Event(
202                       new Object[] { ififo_out,
203                                      data_out,
204                                      token_out,
205                                      ififo_in,
206                                      proceed.isEmpty(),
207                                      "(!`predicate_met(ondeck) || "+OS.verilog("ondeck")+" || !hatch)",
208                                      new ConditionalTrigger("(`predicate_met(ondeck) && `instruction_bit_datain(ondeck))", data_in),
209                                      new ConditionalTrigger("(`predicate_met(ondeck) && `instruction_bit_tokenin(ondeck))", token_in)
210                       },
211                       new Action[] { 
212                           new ConditionalAction(" `done_executing(ondeck) && "+MOVE.verilog("ondeck"), new AssignAction(repeat_counter, "1")),
213                           new ConditionalAction("!`should_requeue(ondeck) && `done_executing(ondeck)", ififo_out),
214                           new ConditionalAction(" `should_requeue(ondeck) && `done_executing(ondeck)", ififo_in),
215                           new ConditionalAction(" `should_requeue(ondeck) && `done_executing(ondeck)", proceed.doFill()),
216                           new ConditionalAction("!`done_executing(ondeck)",
217                                                 new AssignAction(repeat_counter,
218                                                                  "repeat_counter==`magic_standing_value?`magic_standing_value:decremented"))
219                       });
220             new Event(
221                       new Object[] { ififo_out,
222                                      data_out,
223                                      token_out,
224                                      ififo_in,
225                                      proceed.isEmpty(),
226                                      "`predicate_met(ondeck)",
227                                      "("+OS.verilog("ondeck")+" || !hatch)",
228                                      new ConditionalTrigger("`instruction_bit_datain(ondeck)", data_in),
229                                      new ConditionalTrigger("`instruction_bit_tokenin(ondeck)", token_in)
230                       },
231                       new Action[] { 
232                           new ConditionalAction(SET_OLC_FROM_DATA_LATCH.verilog("ondeck"), new AssignAction(loop_counter, "data_latch_output")),
233                           new ConditionalAction(SET_OLC_FROM_IMMEDIATE.verilog("ondeck"),
234                                                 new AssignAction(loop_counter, SET_OLC_FROM_IMMEDIATE.verilogVal("ondeck"))),
235                           new ConditionalAction(SET_OLC_FROM_OLC_MINUS_ONE.verilog("ondeck"),
236                                                 new AssignAction(loop_counter, "loop_counter==0 ? 0 : decremented")),
237                           new ConditionalAction(SET_ILC_FROM_DATA_LATCH.verilog("ondeck"), new AssignAction(repeat_counter, "data_latch_output")),
238                           new ConditionalAction(SET_ILC_FROM_IMMEDIATE.verilog("ondeck"),
239                                                 new AssignAction(repeat_counter, SET_ILC_FROM_IMMEDIATE.verilogVal("ondeck"))),
240                           new ConditionalAction(SET_ILC_FROM_INFINITY.verilog("ondeck"), new AssignAction(repeat_counter, "`magic_standing_value")),
241                           new ConditionalAction(SHIFT.verilog("ondeck"),
242                                                 new AssignAction(data_latch,
243                                                                  "{ data_latch_output["+(WIDTH_WORD-1-SHIFT.valmaskwidth)+":0], "+
244                                                                  SHIFT.verilogVal("ondeck")+"}")),
245                           new ConditionalAction(SET_IMMEDIATE.verilog("ondeck"),
246                                                 new AssignAction(data_latch,
247                                                                  "{ {"+(WIDTH_WORD-FleetTwoFleet.DataLatch_WIDTH)+
248                                                                  "{"+SET_IMMEDIATE_EXTEND.verilogVal("ondeck")+"}}, "+
249                                                                  SET_IMMEDIATE.verilogVal("ondeck")+" }")),
250                           new ConditionalAction(SET_FLAGS.verilog("ondeck"), new AssignAction(flag_a, "`new_flag_a(ondeck)")),
251                           new ConditionalAction(SET_FLAGS.verilog("ondeck"), new AssignAction(flag_b, "`new_flag_b(ondeck)")),
252                           new ConditionalAction(inbox
253                                                 ? "(`instruction_bit_datain(ondeck) || `instruction_bit_tokenin(ondeck))"
254                                                 : "(!`instruction_bit_datain(ondeck) && `instruction_bit_tokenin(ondeck))",
255                                                 new AssignAction(flag_c, dfifo_out.getBits(dfifo_width-1, dfifo_width-1))),
256                           inbox?null:new ConditionalAction("`instruction_bit_datain(ondeck)",   new AssignAction(flag_c, "data_latch_input["+WIDTH_WORD+"]")),
257                           new ConditionalAction("`instruction_bit_datain(ondeck)",   data_in),
258                           new ConditionalAction("`instruction_bit_dataout(ondeck)",  data_out),
259                           new ConditionalAction("`instruction_bit_tokenin(ondeck)",  token_in),
260                           new ConditionalAction("`instruction_bit_tokenout(ondeck)", token_out),
261                           new ConditionalAction("`instruction_bit_latch(ondeck)", new AssignAction(data_latch, data_latch_input)),
262                           new AssignAction(new SimpleAssignable("`packet_token("+token_out.getName()+")"), "`instruction_bit_tokenout(ondeck)?1:0"),
263                           new ConditionalAction("`instruction_path_from_data(ondeck)",
264                                                 new AssignAction(new SimpleAssignable("`packet_signal_and_dest("+token_out.getName()+")"),
265                                                                  DISPATCH_PATH.verilogVal(data_latch_input))),
266                           new ConditionalAction("`instruction_path_from_immediate(ondeck)",
267                                                 new AssignAction(new SimpleAssignable("`packet_signal_and_dest("+token_out.getName()+")"),
268                                                                  "`instruction_path_immediate(ondeck)")),
269                       }
270                       );
271
272         }
273
274         public void dump(PrintWriter pw, boolean fix) {
275
276             pw.println("`define packet_signal_and_dest(p)                 { "+PACKET_SIGNAL.verilogVal("p")+", "+PACKET_DEST.verilogVal("p")+" }");
277             pw.println("`define instruction_repeat_count_immediate(i)       "+SET_ILC_FROM_IMMEDIATE.verilogVal("i"));
278             pw.println("`define instruction_loop_count_immediate(i)         "+SET_OLC_FROM_IMMEDIATE.verilogVal("i"));
279
280             pw.println("`define instruction_path_immediate(i)              "+PATH_IMMEDIATE.verilogVal("i"));
281             pw.println("`define instruction_path_from_immediate(i)         "+PATH_IMMEDIATE.verilog("i"));
282             pw.println("`define instruction_path_from_data(i)            "+PATH_DATA.verilog("i"));
283
284             pw.println("`define instruction_bit_tokenout(i)     ("+MOVE.verilog("i")+" && "+TO.verilog("i")+")");
285             pw.println("`define instruction_bit_dataout(i)      ("+MOVE.verilog("i")+" && "+DO.verilog("i")+")");
286             pw.println("`define instruction_bit_latch(i)        ("+MOVE.verilog("i")+" && "+DC.verilog("i")+")");
287             pw.println("`define instruction_bit_datain(i)       ("+MOVE.verilog("i")+" && "+DI.verilog("i")+")");
288             pw.println("`define instruction_bit_tokenin(i)      ("+MOVE.verilog("i")+" && "+TI.verilog("i")+")");
289             pw.println("`define should_requeue(i)               (loop_counter!=0 && !("+OS.verilog("i")+"))");
290             pw.println("`define predicate_met(i)  ("+
291                        "("+
292                        "!"+MOVE.verilog("i")+" || repeat_counter!=0"+
293                        ") && ("+
294                        "("+
295                        P_ALWAYS.verilog("i")+
296                        ") || ("+
297                        P_OLC_ZERO.verilog("i")+"==(loop_counter==0)"+
298                        ")"+
299                        ") && ("+
300                        " " + P_A.verilog("i")+" ? flag_a"+
301                        ":" + P_B.verilog("i")+" ? flag_b"+
302                        ":" + P_NOT_A.verilog("i")+" ? !flag_a"+
303                        ":" + P_NOT_B.verilog("i")+" ? !flag_b "+
304                        ": 1"+
305                        ")"+
306                        ")");
307             pw.println("`define new_flag(x)         ("+
308                        "( ((x >> 0) & 1) & !flag_c) |" +
309                        "( ((x >> 1) & 1) &  flag_c) |" +
310                        "( ((x >> 2) & 1) & !flag_b) |" +
311                        "( ((x >> 3) & 1) &  flag_b) |" +
312                        "( ((x >> 4) & 1) & !flag_a) |" +
313                        "( ((x >> 5) & 1) &  flag_a) | 0" +
314                        ")");
315             pw.println("`define new_flag_a(i)                   `new_flag("+SET_FLAGS_A.verilogVal("i")+")");
316             pw.println("`define new_flag_b(i)                   `new_flag("+SET_FLAGS_B.verilogVal("i")+")");
317             pw.println("`define done_executing(i)               (repeat_counter==0 || repeat_counter==1 || !"+MOVE.verilog("i")+")");
318
319             pw.println("`define magic_standing_value            (1<<"+SET_ILC_FROM_IMMEDIATE.valmaskwidth+")");
320
321             super.dump(pw,fix);
322         }
323     }
324 }