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