updates to get some of the shutdown code to execute via Program
[fleet.git] / src / edu / berkeley / fleet / dataflow / Node.java
1 package edu.berkeley.fleet.dataflow;
2 import java.util.*;
3 import edu.berkeley.fleet.loops.*;
4 import java.util.concurrent.Semaphore;
5 import java.util.*;
6 import java.net.*;
7 import edu.berkeley.fleet.two.*;
8 import edu.berkeley.fleet.api.*;
9 import edu.berkeley.fleet.fpga.*;
10 import edu.berkeley.fleet.api.Instruction.*;
11 import edu.berkeley.fleet.api.Instruction.Set;
12 import edu.berkeley.fleet.api.Instruction.Set.*;
13 import static edu.berkeley.fleet.api.Predicate.*;
14 import static edu.berkeley.fleet.util.BitManipulations.*;
15
16 public class Node {
17
18     public final DataFlowGraph dfg;
19     public Node(DataFlowGraph dfg) {
20         this.dfg = dfg;
21         dfg.addNode(this);
22     }
23
24     private HashMap<String,Port> ports = new HashMap<String,Port>();
25     public void build(Context ctx) { for(Port p : ports.values()) p.build(ctx); }
26     public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
27         int ret = 0;
28         for(Port p : ports.values()) ret += p.reset(ctx, phase, ackDestination, sendTorpedoesTo);
29         return ret;
30     }
31
32     public abstract class Port {
33         public final String name;
34         public Port(String name) {
35             this.name = name;
36             if (Node.this.ports.get(name)!=null) throw new RuntimeException();
37             Node.this.ports.put(name,this);
38         }
39         public abstract void build(Context ctx);
40         public abstract int  reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo);
41         public String toString() { return Node.this+"."+name; }
42     }
43
44     public abstract class InPort extends Port {
45         OutPort peer;
46         public InPort(String name) { super(name); }
47         public void connect(OutPort peer) {
48             this.setPeer(peer);
49             peer.setPeer(this);
50         }
51         public void setPeer(OutPort peer) {
52             if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
53             this.peer = peer;
54         }
55
56         /** this port's peer (an OutPort) invokes this to have "recvToken" or equivalent inserted */
57         public abstract void recvToken(LoopFactory loopfactory_at_output_dock);
58         /** this port's peer (an OutPort) invokes this to have "sendWord" or equivalent inserted */
59         public abstract void sendWord(LoopFactory loopfactory_at_output_dock);
60
61         public int getTokensToAbsorb() { return 0; }
62     }
63
64     public abstract class OutPort extends Port {
65         InPort peer;
66         public OutPort(String name) { super(name); }
67         public void connect(InPort peer) {
68             this.setPeer(peer);
69             peer.setPeer(this);
70         }
71         public void setPeer(InPort peer) {
72             if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
73             this.peer = peer;
74         }
75
76         /** this port's peer (an InPort) invokes this to have "sendToken" or equivalent inserted */
77         public abstract void sendToken(LoopFactory loopfactory_at_input_dock);
78         /** this port's peer (an InPort) invokes this to have "recvWord" or equivalent inserted */
79         public abstract void recvWord(LoopFactory loopfactory_at_input_dock);
80     }
81
82     public final class DockInPort extends InPort {
83         final Dock dock;
84         int count;
85         BitVector[] pattern;
86         public DockInPort(String name, Dock dock) { this(name, dock, 0); }
87         public DockInPort(String name, Dock dock, int count) { this(name, dock, count, new BitVector[] { null }); }
88         public DockInPort(String name, Dock dock, int count, BitVector[] pattern) {
89             super(name);
90             this.dock = dock;
91             this.count = count;
92             this.pattern = pattern;
93         }
94         public void recvToken(LoopFactory lf) { lf.recvToken(); }
95         public void sendWord(LoopFactory lf) { lf.sendWord(dock.getDataDestination()); }
96         public void build(Context ctx) { build(ctx, new LoopFactory(ctx, dock, 1)); }
97         // number-in-flight is considered a property of the input dock in a pair
98         public int getInflight() { return 4; }
99         //public int getInflight() { return 1; }
100         public int getTokensToAbsorb() { return getInflight(); }
101         private boolean peerUsed() {
102             if (peer==null) return false;
103             for(int i=0; i<pattern.length; i++) if (pattern[i]==null) return true;
104             return false;
105         }
106         public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
107             return doReset(ctx, phase, dock, peer, ackDestination, sendTorpedoesTo, peerUsed());
108         }
109         protected void build(Context ctx, LoopFactory lf) {
110             int inflight = (count != 0 && count < getInflight()) ? count : getInflight();
111
112             if (peer!=null)
113                 for(int i=0; i<inflight; i++) peer.sendToken(lf);
114
115             lf = lf.makeNext(count, true);
116             for(int i=0; i<pattern.length; i++) {
117                 if (pattern[i]==null) {
118                     if (peer!=null) {
119                         lf.abortLoopIfTorpedoPresent();
120                         peer.recvWord(lf);
121                         peer.sendToken(lf);
122                         lf.deliver();
123                     } else {
124                         lf.interruptibleNop();
125                     }
126                 } else {
127                     lf.literal(pattern[i]);
128                     lf.abortLoopIfTorpedoPresent();
129                     lf.deliver();
130                 }
131             }
132
133             if (count!=0) {
134                 // "torpedoable nop" to keep the dock in a receptive state
135                 lf.abortLoopIfTorpedoPresent();
136                 lf.recvToken();
137             }
138         }
139         public BitVector getConstant(String constantName) {
140             return dock.getConstant(constantName);
141         }
142     }
143
144     public /*final*/ class DockOutPort extends OutPort {
145         public final Dock dock;
146         public final int count;
147         public DockOutPort(String name, Dock dock) { this(name, dock, 0); }
148         public DockOutPort(String name, Dock dock, int count) { super(name); this.dock = dock; this.count = count; }
149         public void sendToken(LoopFactory lf) { lf.sendToken(dock.getDataDestination()); }
150         public void recvWord(LoopFactory lf) { lf.recvWord(); }
151         public void build(Context ctx) { build(ctx, new LoopFactory(ctx, dock, 1)); }
152         protected void build(Context ctx, LoopFactory lf) {
153             if (peer==null) return;
154             lf = lf.makeNext(count);
155             lf.abortLoopIfTorpedoPresent();
156             peer.recvToken(lf);
157             lf.collectWord();
158             peer.sendWord(lf);
159         }
160         public int reset(Context ctx, int phase, Destination ackDestination, HashSet<Dock> sendTorpedoesTo) {
161             return doReset(ctx, phase, dock, peer, ackDestination, sendTorpedoesTo, true);
162         }
163     }
164
165     BitVector bv(long l) { return new BitVector(dfg.fleet.getWordWidth()).set(l); }
166     BitVector[] bv(long[] l) {
167         BitVector[] ret = new BitVector[l.length];
168         for(int i=0; i<ret.length; i++) ret[i] = bv(l[i]);
169         return ret;
170     }
171
172     // Reset //////////////////////////////////////////////////////////////////////////////
173
174     int doReset(Context ctx,
175                 int phase,
176                 Dock dock,
177                 Port peer,
178                 Destination ackDestination,
179                 HashSet<Dock> sendTorpedoesTo,
180                 boolean peerUsed) {
181         int ret = 0;
182         if (dock.getShip().getType().equals("Debug")) return ret;
183
184         switch(phase) {
185
186             // Phase 0: torpedo every output dock, put it in
187             // collecting mode.  Cannot combine with phase 1,
188             // because until output docks are in vacuum mode we
189             // cannot be sure that the tokens to the input docks
190             // will eventually succeed.  This may cause the
191             // instructions sent after the tokens to back up into
192             // the switch fabric.
193             case 0: {
194                 if (!dock.isInputDock()) {
195                     sendTorpedoesTo.add(dock);
196                     LoopFactory lf = new LoopFactory(ctx, dock, 1);
197                     lf.sendToken(ackDestination);
198                     lf = lf.makeNext(0);
199                     lf.abortLoopIfTorpedoPresent();
200                     lf.collectWord();
201                     ret++;
202                 }
203                 break;
204             }
205
206                 // [wait for all output docks to confirm that they've been torpedoed]
207                 // Phase 1: torpedo every input dock (causing them to flush), put it in loopback mode
208             case 1: {
209                 if (dock.isInputDock()) {
210                     sendTorpedoesTo.add(dock);
211                     LoopFactory lf = new LoopFactory(ctx, dock, 1);
212                     lf.sendToken(ackDestination);
213
214                     // FIXME: this won't work right for ports that
215                     // get "shared" by two senders (for example,
216                     // inAddrRead1/2)
217
218                     if (peerUsed && peer!=null) {
219                         lf = lf.makeNext(0);
220                         lf.abortLoopIfTorpedoPresent();
221                         ((OutPort)peer).recvWord(lf);
222                         ((OutPort)peer).sendToken(lf);
223                     }
224                     ret++;
225                 }
226                 break;
227             }
228
229                 // [wait for all input docks to confirm that they've been torpedoed and have flushed]
230                 // Phase 2: torpedo every output dock, have it absorb tokens
231             case 2: {
232                 if (!dock.isInputDock()) {
233                     sendTorpedoesTo.add(dock);
234                     LoopFactory lf = new LoopFactory(ctx, dock, 1);
235                     if (peer != null)
236                         for(int i=0; i<((InPort)peer).getTokensToAbsorb(); i++)
237                             lf.recvToken();
238                     lf.sendToken(ackDestination);
239                     ret++;
240                 }
241                 break;
242             }
243
244                 // [wait for all output docks to confirm that they've absorbed enough tokens]
245                 // Phase 3: torpedo every input dock, await confirmation, and we're done
246             case 3: {
247                 if (dock.isInputDock()) {
248                     if (peerUsed && peer!=null) {
249                         sendTorpedoesTo.add(dock);
250                     }
251                     LoopFactory lf = new LoopFactory(ctx, dock, 1);
252                     lf.sendToken(ackDestination);
253                     ret++;
254                 }
255                 break;
256             }
257         }
258         return ret;
259     }
260
261 }