017b17fc7d6298e2a6ab5bab88f18d69eef89dfe
[fleet.git] / src / edu / berkeley / fleet / ir / Process.java
1 package edu.berkeley.fleet.ir;
2 import java.util.concurrent.Semaphore;
3 import java.util.*;
4 import java.net.*;
5 import edu.berkeley.fleet.two.*;
6 import edu.berkeley.fleet.api.*;
7 import edu.berkeley.fleet.fpga.*;
8 import edu.berkeley.fleet.api.Instruction.*;
9 import edu.berkeley.fleet.api.Instruction.Set;
10 import edu.berkeley.fleet.api.Instruction.Set.*;
11 import static edu.berkeley.fleet.api.Predicate.*;
12 import static edu.berkeley.fleet.util.BitManipulations.*;
13
14
15 /*
16  - refactor the cleanup into the subclasses of Port (phase1, phase2, etc)
17  */
18
19 // does peer.recvWord() have to honor the currently-set predicate?
20
21 // public class ReplaceModule extends Module { }
22 // public class CountMergeModule extends Module { }
23 // public class SortMergeModule extends Module { }
24 // public class FanOutModule extends Module { }
25 // public class MemoryModule extends Module { }
26 // public class DoneModule extends Module { }
27
28 public class Process {
29
30     public static int reset_count = 0;
31     public static HashSet<Dock> torpedoes = new HashSet<Dock>();
32
33     public final Fleet    fleet;
34     public final ShipPool pool;
35
36     public Process(Fleet fleet) {
37         this.fleet = fleet;
38         this.pool  = new ShipPool(fleet);
39     }
40
41     private HashSet<Module> modules = new HashSet<Module>();
42
43     public void build(Context ctx) {
44         for(Module mod : modules)
45             mod.build(ctx);
46     }
47     public void reset(Context ctx, int phase) {
48         reset_count = 0;
49         torpedoes.clear();
50         for(Module mod : modules)
51             mod.reset(ctx, phase);
52     }
53
54     public class Module {
55
56         public Module() {
57             Process.this.modules.add(this);
58         }
59
60         private HashMap<String,Port> ports = new HashMap<String,Port>();
61
62         public InPort  getInPort(String name)  { return (InPort)ports.get(name); }
63         public OutPort getOutPort(String name) { return (OutPort)ports.get(name); }
64         
65         public void build(Context ctx) { for(Port p : ports.values()) p.build(ctx); }
66         public void reset(Context ctx, int phase) { for(Port p : ports.values()) p.reset(ctx, phase); }
67
68         public abstract class Port {
69             public final String name;
70             public Port(String name) {
71                 this.name = name;
72                 if (Module.this.ports.get(name)!=null) throw new RuntimeException();
73                 Module.this.ports.put(name,this);
74             }
75             public abstract void build(Context ctx);
76             public abstract void reset(Context ctx, int phase);
77         }
78
79         public abstract class InPort extends Port {
80             OutPort peer;
81             public InPort(String name) { super(name); }
82             public void connect(OutPort peer) {
83                 this.setPeer(peer);
84                 peer.setPeer(this);
85             }
86             public void setPeer(OutPort peer) {
87                 if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
88                 this.peer = peer;
89             }
90
91             /** this port's peer (an OutPort) invokes this to have "recvToken" or equivalent inserted */
92             public abstract void recvToken(Context.LoopFactory loopfactory_at_output_dock);
93             /** this port's peer (an OutPort) invokes this to have "sendWord" or equivalent inserted */
94             public abstract void sendWord(Context.LoopFactory loopfactory_at_output_dock);
95
96             public int getTokensToAbsorb() { return 0; }
97         }
98
99         public abstract class OutPort extends Port {
100             InPort peer;
101             public OutPort(String name) { super(name); }
102             public void connect(InPort peer) {
103                 this.setPeer(peer);
104                 peer.setPeer(this);
105             }
106             public void setPeer(InPort peer) {
107                 if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
108                 this.peer = peer;
109             }
110
111             /** this port's peer (an InPort) invokes this to have "sendToken" or equivalent inserted */
112             public abstract void sendToken(Context.LoopFactory loopfactory_at_input_dock);
113             /** this port's peer (an InPort) invokes this to have "recvWord" or equivalent inserted */
114             public abstract void recvWord(Context.LoopFactory loopfactory_at_input_dock);
115         }
116
117         public final class DockInPort extends InPort {
118             final Dock dock;
119             int count;
120             BitVector[] pattern;
121             public DockInPort(String name, Dock dock) { this(name, dock, 0); }
122             public DockInPort(String name, Dock dock, int count) { this(name, dock, count, new BitVector[] { null }); }
123             public DockInPort(String name, Dock dock, int count, BitVector[] pattern) {
124                 super(name);
125                 this.dock = dock;
126                 this.count = count;
127                 this.pattern = pattern;
128             }
129             public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
130             public void sendWord(Context.LoopFactory lf) { lf.sendWord(dock.getDataDestination()); }
131             public void build(Context ctx) { build(ctx, ctx.new LoopFactory(dock, 1)); }
132             // number-in-flight is considered a property of the input dock in a pair
133             //public int getInflight() { return 4; }
134             public int getInflight() { return 1; }
135             public int getTokensToAbsorb() { return getInflight(); }
136             private boolean peerUsed() {
137                 if (peer==null) return false;
138                 for(int i=0; i<pattern.length; i++) if (pattern[i]==null) return true;
139                 return false;
140             }
141             public void reset(Context ctx, int phase) {
142                 if (dock.getShip().getType().equals("Debug")) {
143                     return;
144                 }
145                 switch(phase) {
146                     case 0: {
147                         torpedoes.add(dock);
148                         break;
149                     }
150                     case 2: {
151                         reset_count++;
152                         Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
153                         lf.sendToken(fleet.getShip("Debug",0).getDock("in").getDataDestination());
154                         if (peerUsed()) {
155                             lf = lf.makeNext(0);
156                             lf.abortLoopIfTorpedoPresent();
157                             peer.recvWord(lf);
158                             peer.sendToken(lf);
159                         }
160                         break;
161                     }
162                     case 3: {
163                         if (peerUsed()) {
164                             torpedoes.add(dock);
165                         }
166                         break;
167                     }
168                 }
169             }
170             protected void build(Context ctx, Context.LoopFactory lf) {
171                 int inflight = (count != 0 && count < getInflight()) ? count : getInflight();
172
173                 if (peer!=null)
174                     for(int i=0; i<inflight; i++) peer.sendToken(lf);
175
176                 lf = lf.makeNext(count);
177                 for(int i=0; i<pattern.length; i++) {
178                     if (pattern[i]==null) {
179                         if (peer!=null) {
180                             lf.abortLoopIfTorpedoPresent();
181                             peer.recvWord(lf);
182                             peer.sendToken(lf);
183                             lf.deliver();
184                         } else {
185                             lf.interruptibleNop();
186                         }
187                     } else {
188                         lf.literal(pattern[i]);
189                         lf.abortLoopIfTorpedoPresent();
190                         lf.deliver();
191                     }
192                 }
193
194                 if (count!=0) {
195                     // "torpedoable nop" to keep the dock in a receptive state
196                     lf.abortLoopIfTorpedoPresent();
197                     lf.recvToken();
198                 }
199             }
200         }
201
202         public /*final*/ class DockOutPort extends OutPort {
203             public final Dock dock;
204             public final int count;
205             public DockOutPort(String name, Dock dock) { this(name, dock, 0); }
206             public DockOutPort(String name, Dock dock, int count) { super(name); this.dock = dock; this.count = count; }
207             public void sendToken(Context.LoopFactory lf) { lf.sendToken(dock.getDataDestination()); }
208             public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
209             public void build(Context ctx) { build(ctx, ctx.new LoopFactory(dock, 1)); }
210             protected void build(Context ctx, Context.LoopFactory lf) {
211                 if (peer==null) return;
212                 lf = lf.makeNext(count);
213                 lf.abortLoopIfTorpedoPresent();
214                 peer.recvToken(lf);
215                 lf.collectWord();
216                 peer.sendWord(lf);
217             }
218             public void reset(Context ctx, int phase) {
219
220                 // set this to true to get a more "fine grained" report of the shutdown process
221                 boolean extratokens = false;
222
223                 switch(phase) {
224                     case 0: {
225                         torpedoes.add(dock);
226                         break;
227                     }
228                     case 1: {
229                         Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
230                         if (peer != null) {
231                             for(int i=0; i<peer.getTokensToAbsorb(); i++) {
232                                 lf.recvToken();
233                                 if (extratokens) lf.sendToken(fleet.getShip("Debug",0).getDock("in").getDataDestination());
234                             }
235                         }
236                         lf.sendToken(fleet.getShip("Debug",0).getDock("in").getDataDestination());
237                         lf = lf.makeNext(0);
238                         lf.abortLoopIfTorpedoPresent();
239                         lf.collectWord();
240                         break;
241                     }
242                     case 2: {
243                         reset_count++;
244                         if (extratokens && peer != null) reset_count += peer.getTokensToAbsorb();
245                         break;
246                     }
247                     case 3: {
248                         torpedoes.add(dock);
249                         break;
250                     }
251                 }
252             }
253         }
254     }
255
256     private static BitVector bv(long l) { return new BitVector(/*FIXME fleet.getWordWidth()*/37).set(l); }
257     private static BitVector[] bv(long[] l) {
258         BitVector[] ret = new BitVector[l.length];
259         for(int i=0; i<ret.length; i++) ret[i] = bv(l[i]);
260         return ret;
261     }
262
263     /**
264      *  For every datum transmitted to in, pass it along to out and
265      *  deliver the constant at out.  Flow control in<->out is
266      *  maintained, but out is not flow-controlled, so be sure
267      *  that every datum sent there is consumed synchronously wiht
268      *  data items sent to out.
269      */
270     public class ForeverModule extends Module {
271         private BitVector bv;
272         public final OutPort out = new OutPort("out") {
273                 public void sendToken(Context.LoopFactory lf) { }
274                 public void recvWord(Context.LoopFactory lf) { }
275                 public void build(Context ctx) { }
276                 public void reset(Context ctx, int phase) { }
277                 public void setPeer(InPort peer) {
278                     this.peer = peer;
279                     DockInPort pip = ((DockInPort)peer);
280                     for(int i=0; i<pip.pattern.length; i++) {
281                         if (pip.pattern[i]==null)
282                             pip.pattern[i] = bv;
283                     }
284                 }
285             };
286         public ForeverModule(long l) { this(new BitVector(fleet.getWordWidth()).set(l)); }
287         public ForeverModule(final BitVector bv) { this.bv = bv; }
288     }
289
290     public class OnceModule extends Module {
291         private BitVector bv;
292         public final OutPort out = new OutPort("out") {
293                 public void sendToken(Context.LoopFactory lf) { }
294                 public void recvWord(Context.LoopFactory lf) { }
295                 public void build(Context ctx) { }
296                 public void reset(Context ctx, int phase) { }
297                 public void setPeer(InPort peer) {
298                     this.peer = peer;
299                     DockInPort pip = ((DockInPort)peer);
300                     BitVector[] pip_pattern = pip.pattern;
301                     BitVector[] temp = new BitVector[pip_pattern.length * 2];
302                     int j = 0;
303                     int i = 0;
304                     boolean done = false;
305                     // FIXME: if peer.count is already 1, this gets simpler and different
306                     for(i=0; i<temp.length; i++) {
307                         if (pip_pattern[j] != null) {
308                             temp[i] = pip_pattern[j];
309                         } else {
310                             if (done) break;
311                             done = true;
312                             temp[i] = bv;
313                         }
314                         j++;
315                         if (j >= pip_pattern.length) j = 0;
316                     }
317                     pip.pattern = new BitVector[i];
318                     System.arraycopy(temp, 0, pip.pattern, 0, i);
319                     pip.count = 1;
320                 }
321             };
322         public OnceModule(long l) { this(new BitVector(fleet.getWordWidth()).set(l)); }
323         public OnceModule(final BitVector bv) { this.bv = bv; }
324     }
325
326     public class DebugModule extends Module {
327         public final Ship ship = pool.allocateShip("Debug");
328         public final InPort in = new DockInPort("in", ship.getDock("in"));
329         // NOTE: shutdown needs to treat this specially
330         public DebugModule() { }
331     }
332
333     public class UnPunctuatorModule extends Module {
334         private final Ship    ship  = pool.allocateShip("Counter");
335         public  final OutPort out   = new DockOutPort("out", ship.getDock("out"));
336         public  final InPort  val   = new DockInPort("in1",  ship.getDock("in1"));
337         public  final InPort  count = new DockInPort("in2",  ship.getDock("in2"), 0, new BitVector[] { null, bv(1) });
338         public  final InPort  op    = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(6 /*PASS_C2_V1*/), bv(10 /*DROP_C2_V1*/) } );
339         public UnPunctuatorModule() { }
340     }
341
342     public class PunctuatorModule extends Module {
343         private final long    punc;
344         private final Ship    ship  = pool.allocateShip("Counter");
345         public  final OutPort out   = new DockOutPort("out", ship.getDock("out"));
346         public  final InPort  val   = new DockInPort("in1",  ship.getDock("in1"));
347         public  final InPort  op    = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(6 /*PASS_C2_V1*/), bv(7 /*PASS_C2_V2*/) } );
348         public  final InPort  count;
349         public PunctuatorModule(long punc) {
350             this.punc = punc;
351             this.count = new DockInPort("in2",  ship.getDock("in2"), 0, new BitVector[] { null, bv(1), bv(punc) });
352         }
353     }
354
355     public class AluModule extends Module {
356         public final Ship    ship = pool.allocateShip("Alu");
357         public final InPort  in1 = new DockInPort("in1",  ship.getDock("in1"));
358         public final InPort  in2 = new DockInPort("in2",  ship.getDock("in2"));
359         public final InPort  inOp = new DockInPort("inOp", ship.getDock("inOp"));
360         public final OutPort out  = new DockOutPort("out", ship.getDock("out"));
361         public AluModule() { }
362     }
363
364     public class DownCounterModule extends Module {
365         public final Ship    ship  = pool.allocateShip("Counter");
366         public final InPort  start = new DockInPort("in1",  ship.getDock("in1"));
367         public final InPort  incr  = new DockInPort("in2",  ship.getDock("in2"));
368         public final InPort  inOp  = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(12 /*COUNTDOWN*/) });
369         public final OutPort out   = new DockOutPort("out", ship.getDock("out"));
370         public DownCounterModule() { }
371     }
372
373     public class RepeatModule extends Module {
374         public final Ship    ship   = pool.allocateShip("Counter");
375         public final InPort  count  = new DockInPort("in1",  ship.getDock("in1"));
376         public final InPort  val    = new DockInPort("in2",  ship.getDock("in2"));
377         public final InPort  inOP   = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(1 /*REPEAT_C1_V2*/) });
378         public final OutPort out    = new DockOutPort("out", ship.getDock("out"));
379         public RepeatModule() { }
380     }
381
382     public class SortedMergeModule extends Module {
383         public final Ship    ship = pool.allocateShip("Alu");
384         public final InPort  in1  = new DockInPort("in1",  ship.getDock("in1"));
385         public final InPort  in2  = new DockInPort("in2",  ship.getDock("in2"));
386         public final InPort  inOp = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(9 /*MAXMERGE*/) });
387         public final OutPort out  = new DockOutPort("out", ship.getDock("out"));
388         public SortedMergeModule() { }
389     }
390
391     public class MemoryModule extends Module {
392         public final Ship    ship;
393         public final InPort  inCBD;
394         public final InPort  inAddrRead1;
395         public final InPort  inAddrRead2;
396         public final InPort  inAddrWrite;
397         public final InPort  inDataWrite;
398         public final OutPort outRead1;
399         public final OutPort outRead2;
400         public final OutPort outWrite;
401         public MemoryModule(Ship memoryShip) {
402             this.ship = memoryShip;
403             this.inCBD        = ship.getType().equals("Memory") ? new DockInPort("inCBD", ship.getDock("inCBD")) : null;
404             this.inAddrWrite  = new DockInPort("inAddrWrite", ship.getDock("inAddrWrite"));
405             this.inDataWrite  = new DockInPort("inDataWrite", ship.getDock("inDataWrite"));
406             this.inAddrRead1  = new InPort("inAddrRead1") {
407                     public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
408                     public void sendWord(Context.LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(0)); }
409                     public void build(Context ctx) { }
410                     public int getTokensToAbsorb() { return outRead1.peer.getTokensToAbsorb(); }
411                     public void reset(Context ctx, int phase) {
412                         switch(phase) {
413                             case 0:
414                                 torpedoes.add(ship.getDock("inAddrRead"));
415                                 break;
416                             case 2:
417                                 reset_count++;
418                                 Context.LoopFactory lf = ctx.new LoopFactory(ship.getDock("inAddrRead"), 1);
419                                 lf.sendToken(fleet.getShip("Debug",0).getDock("in").getDataDestination());
420                                 break;
421                         }
422                     }
423                 };
424             this.inAddrRead2  = new InPort("inAddrRead2") {
425                     public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
426                     public void sendWord(Context.LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(1)); }
427                     public void build(Context ctx) { }
428                     public int getTokensToAbsorb() { return outRead2.peer.getTokensToAbsorb(); }
429                     public void reset(Context ctx, int phase) { }
430                 };
431             this.outRead1 = new OutPort("outRead1") {
432                     public void sendToken(Context.LoopFactory lf) { inAddrRead1.peer.sendToken(lf); }
433                     public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
434                     public void build(Context ctx) { }
435                     public void reset(Context ctx, int phase) { }
436                 };
437             this.outRead2 = new OutPort("outRead2") {
438                     public void sendToken(Context.LoopFactory lf) { inAddrRead2.peer.sendToken(lf); }
439                     public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
440                     public void build(Context ctx) { }
441                     public void reset(Context ctx, int phase) { }
442                 };
443             this.outWrite = new DockOutPort("out", ship.getDock("out")) {
444                     protected void build(Context ctx, Context.LoopFactory lf) {
445                         lf = lf.makeNext(0);
446                         lf.abortLoopIfTorpedoPresent();
447                         lf.collectWord();
448                         
449                         lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO.add(FlagC));
450                         if (this.peer != null) {
451                             lf.setPredicate(Predicate.FlagB);
452                             lf.literal(77);
453                             lf.abortLoopIfTorpedoPresent();
454                             this.peer.recvToken(lf);
455                             this.peer.sendWord(lf);
456                         }
457                         
458                         lf.setPredicate(Predicate.NotFlagB);
459                         lf.abortLoopIfTorpedoPresent();
460                         lf.recvToken();
461                         lf.setFlags(FlagFunction.ZERO.add(NotFlagC).add(FlagB), FlagFunction.ZERO.add(FlagC).add(FlagB));
462                         if (outRead1.peer != null) {
463                             lf.setPredicate(Predicate.NotFlagB);
464                             outRead1.peer.sendWord(lf);
465                         }
466                         if (outRead2.peer != null) {
467                             lf.setPredicate(Predicate.NotFlagA);
468                             outRead2.peer.sendWord(lf);
469                         }
470                         lf.setPredicate(null);
471                     }
472                 };
473         }
474         public void build(Context ctx) {
475             super.build(ctx);
476             Context.LoopFactory lf;
477
478             lf = ctx.new LoopFactory(ship.getDock("inAddrRead"), 0);
479             lf.abortLoopIfTorpedoPresent();
480             lf.recvWord();
481             lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
482             lf.setPredicate(Predicate.NotFlagA);
483             lf.sendToken(ship.getDock("out").getDataDestination(), new BitVector(1).set(0));
484             lf.setPredicate(Predicate.FlagA);
485             lf.sendToken(ship.getDock("out").getDataDestination(), new BitVector(1).set(1));
486             lf.setPredicate(null);
487             lf.deliver();
488         }
489     }
490
491     public static void main(String[] s) throws Exception {
492         Fleet fleet = new Fpga();
493         Random random = new Random(System.currentTimeMillis());
494         long[] vals = new long[256];
495         for(int i=0; i<vals.length; i++) {
496             vals[i] = Math.abs(random.nextInt());
497         }
498
499         Ship mem1 = fleet.getShip("Memory", 0);
500         Ship mem2 = fleet.getShip("Memory", 1);
501
502         FleetProcess fp;
503         int stride = 1;
504         fp = null;
505
506         fp = fleet.run(new Instruction[0]);
507         Gadgets.writeMem(fp, mem1, 0, bv(vals));
508         int vals_length = vals.length;
509
510         // Disable readback/writeback inside the loop
511         vals = null;
512
513         while(stride < vals_length) {
514             
515             // reset the FleetProcess
516             //fp.terminate(); fp = null;
517
518             System.out.println("stride " + stride);
519
520             // if we reset the FleetProcess, restart it
521             if (fp==null) fp = fleet.run(new Instruction[0]);
522
523             // do the mergeSort
524             vals = mergeSort(fp, fleet, vals, vals_length, stride, mem1, mem2);
525
526             // verify the cleanup
527             //verifyClean(fp);
528
529             Ship mem = mem1; mem1=mem2; mem2=mem;
530
531             stride = stride * 2;
532             System.out.println();
533         }
534
535         BitVector[] bvs = new BitVector[vals_length];
536         Gadgets.readMem(fp, mem1, 0, bvs);
537         System.out.println("results:");
538         for(int i=0; i<vals_length; i++)
539             System.out.println(bvs[i].toLong());
540     }
541
542     public static void verifyClean(FleetProcess fp) {
543         Ship debug   = fp.getFleet().getShip("Debug", 0);
544         Dock debugIn = debug.getDock("in");
545
546         Context ctx;
547         Context.LoopFactory lf;
548
549         ctx = new Context(fp.getFleet());
550         lf = ctx.new LoopFactory(debugIn, 1);
551         lf.literal(12);
552         lf.deliver();
553         lf.literal(5);
554         lf.deliver();
555         ArrayList<Instruction> ai = new ArrayList<Instruction>();
556         ctx.emit(ai);
557         for(Instruction ins : ai) fp.sendInstruction(ins);
558         fp.flush();
559
560         System.out.println("checking debug.in");
561         if (fp.recvWord().toLong() != 12) throw new RuntimeException("debug dock not properly initialized");
562         if (fp.recvWord().toLong() != 5)  throw new RuntimeException("debug dock not properly initialized");
563
564         long k = 0;
565         for(Ship ship : fp.getFleet())
566             if (!"Debug".equals(ship.getType()))
567                 for (Dock dock : ship) {
568                     System.out.print("checking " + dock + "                     ");
569
570                     k = (k + 23) % 65535;
571                     ctx = new Context(fp.getFleet());
572
573                     boolean reverse = (k%2)==0;
574
575                     lf = ctx.new LoopFactory(debugIn, 4);
576                     lf.recvToken();
577                     lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
578                     lf.setPredicate(Predicate.NotFlagA);
579                     lf.literal(k);
580                     lf.setPredicate(Predicate.FlagA);
581                     lf.literal(k+1);
582                     lf.setPredicate(null);
583                     lf.deliver();
584
585                     lf = ctx.new LoopFactory(dock, 1);
586                     lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(reverse ? 1 : 0));
587                     lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(reverse ? 0 : 1));
588                     lf.sendToken(dock.getDataDestination(), new BitVector(1).set(reverse ? 1 : 0));
589                     lf.sendToken(dock.getDataDestination(), new BitVector(1).set(reverse ? 0 : 1));
590                     lf = lf.makeNext(2);
591                     lf.recvToken();
592                     lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
593                     lf.setPredicate(Predicate.NotFlagA);
594                     lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(0));
595                     lf.setPredicate(Predicate.FlagA);
596                     lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(1));
597                     lf.setPredicate(null);
598
599                     ai = new ArrayList<Instruction>();
600                     ctx.emit(ai);
601                     for(Instruction ins : ai) fp.sendInstruction(ins);
602                     fp.flush();
603
604                     long kk;
605                     for(int i=0; i<4; i++) {
606                         kk = fp.recvWord().toLong();
607                         System.out.print("\rchecking " + dock + " (got "+(i+1)+")");
608                         if (kk != ((reverse ^ (i%2!=0)) ? k+1 : k)) {
609                             System.out.println();
610                             throw new RuntimeException(dock+" not properly initialized ("+(i+1)+")");
611                         }
612                     }
613                     System.out.println();
614                 }
615     }
616
617     // FIXME: numbers seem to get duplicated when stride=2
618     public static long[] mergeSort(FleetProcess fp, Fleet fleet,
619                                    long[] vals, int vals_length, int stride_length,
620                                    Ship memoryShip1, Ship memoryShip2) throws Exception {
621
622         if (vals != null) {
623             BitVector[] mem = new BitVector[vals_length];
624             for(int i=0; i<mem.length; i++) mem[i] = new BitVector(fleet.getWordWidth()).set(vals[i]);
625             Gadgets.writeMem(fp, memoryShip1, 0, mem);
626         }
627
628         //////////////////////////////////////////////////////////////////////////////
629
630         Process proc = new Process(fleet);
631         DebugModule dm = proc.new DebugModule();
632
633         int end_of_data = vals_length;
634         int num_strides = end_of_data / (stride_length * 2);
635
636         MemoryModule mm  = proc.new MemoryModule(memoryShip1);
637         SortedMergeModule sm = proc.new SortedMergeModule();
638
639         // So far: we have four spare Counter ships; one can be used for resetting
640         for(int i=0; i<2; i++) {
641
642             RepeatModule r1 = proc.new RepeatModule();
643             DownCounterModule c0 = proc.new DownCounterModule();
644             DownCounterModule c1 = proc.new DownCounterModule();
645             AluModule alu = proc.new AluModule();
646
647             c0.start.connect(proc.new ForeverModule(stride_length).out);
648             c0.incr.connect(proc.new ForeverModule(1).out);
649
650             c1.start.connect(proc.new OnceModule(end_of_data + i*stride_length).out);
651             c1.incr.connect(proc.new OnceModule(stride_length*2).out);
652
653             r1.val.connect(c1.out);
654             r1.count.connect(proc.new ForeverModule(stride_length).out);
655
656             alu.in1.connect(r1.out);
657             alu.in2.connect(c0.out);
658             alu.inOp.connect(proc.new ForeverModule(2 /* ADD */).out);
659             alu.out.connect(i==0 ? mm.inAddrRead1 : mm.inAddrRead2);
660
661             PunctuatorModule punc = proc.new PunctuatorModule(-1);
662             punc.count.connect(proc.new ForeverModule(stride_length).out);
663             punc.val.connect(i==0 ? mm.outRead1 : mm.outRead2);
664             punc.out.connect(i==0 ? sm.in1 : sm.in2);
665         }
666
667         
668         UnPunctuatorModule unpunc = proc.new UnPunctuatorModule();
669         unpunc.val.connect(sm.out);
670         unpunc.count.connect(proc.new ForeverModule(2*stride_length).out);
671
672         DownCounterModule cw = proc.new DownCounterModule();
673         cw.start.connect(proc.new OnceModule(end_of_data).out);
674         cw.incr.connect(proc.new OnceModule(1).out);
675
676         MemoryModule mm2 = proc.new MemoryModule(memoryShip2);
677         mm2.inAddrWrite.connect(cw.out);
678         mm2.inDataWrite.connect(unpunc.out);
679         mm2.outWrite.connect(dm.in);
680  
681         //////////////////////////////////////////////////////////////////////////////
682
683         Context ctx = new Context(fp.getFleet());
684         ctx.setAutoflush(true);
685
686         ArrayList<Instruction> ai = new ArrayList<Instruction>();
687         proc.build(ctx);
688         ctx.emit(ai);
689         for(Instruction ins : ai) {
690             //System.out.println(ins);
691             fp.sendInstruction(ins);
692         }
693         fp.flush();
694
695         for(int i=0; i<vals_length; i++) {
696             System.out.print("\rreading back... " + i+"/"+vals_length+"  ");
697             System.out.print(" (prev result: " + fp.recvWord() + ")");
698         }
699         System.out.println("\rdone.                                                                    ");
700
701         //if (true) return ret;
702
703         Context ctx2 = new Context(fp.getFleet());
704         Dock debugIn = fleet.getShip("Debug",0).getDock("in");
705         Dock fred = debugIn;
706         fp.sendToken(debugIn.getInstructionDestination());
707
708         Context.LoopFactory lf = ctx2.new LoopFactory(debugIn, 0);
709         lf.literal(0);
710         lf.abortLoopIfTorpedoPresent();
711         lf.recvToken();
712         lf.deliver();
713
714         ctx2.emit(ai = new ArrayList<Instruction>());
715         for(Instruction ins : ai)
716             fp.sendInstruction(ins);
717         fp.flush();
718
719         int count = 0;
720
721         for(int phase=0; phase<=3; phase++) {
722             System.out.println("== phase "+phase+" ==================================================================");
723             ctx2 = new Context(fp.getFleet());
724             proc.reset(ctx2, phase);
725
726             final Semaphore sem = new Semaphore(0);
727             final FleetProcess fpf = fp;
728             final int phasef = phase;
729             new Thread() {
730                 public void run() {
731                     for(int ii=0; ii<reset_count; ii++) {
732                         System.out.print("\r phase "+phasef+" ==> " + (ii+1) + " / " + reset_count);
733                         fpf.recvWord();
734                     }
735                     sem.release();
736                 }}.start();
737
738             for(Dock dock : torpedoes) fp.sendToken(dock.getInstructionDestination());
739             ctx2.emit(ai = new ArrayList<Instruction>());
740             for(Instruction ins : ai) fp.sendInstruction(ins);
741             fp.flush();
742
743             sem.acquire();
744             System.out.println("flushed");
745
746             System.out.println();
747         }
748
749         fp.sendToken(debugIn.getInstructionDestination());
750         fp.flush();
751
752         System.out.println("verifying cleanup:");
753         //verifyClean(fp);
754
755         long[] ret = null;
756         if (vals != null) {
757             ret = new long[vals_length];
758             BitVector[] mem = new BitVector[vals_length];
759             Gadgets.readMem(fp, memoryShip2, 0, mem);
760             for(int i=0; i<ret.length; i++) ret[i] = mem[i].toLong();
761         }
762         return ret;
763     }
764
765     private BitVector[] longsToBitVectors(long[] initialValues) {
766         BitVector[] bv = new BitVector[initialValues.length];
767         for(int i=0; i<initialValues.length; i++)
768             bv[i] = new BitVector(fleet.getWordWidth()).set(initialValues[i]);
769         return bv;
770     }
771 }
772
773