1 package edu.berkeley.fleet.ir;
4 import edu.berkeley.fleet.two.*;
5 import edu.berkeley.fleet.api.*;
6 import edu.berkeley.fleet.fpga.*;
7 import edu.berkeley.fleet.api.Instruction.*;
8 import edu.berkeley.fleet.api.Instruction.Set;
9 import edu.berkeley.fleet.api.Instruction.Set.*;
10 import static edu.berkeley.fleet.api.Predicate.*;
11 import static edu.berkeley.fleet.util.BitManipulations.*;
15 - refactor the cleanup into the subclasses of Port (phase1, phase2, etc)
18 // does peer.recvWord() have to honor the currently-set predicate?
20 // public class ReplaceModule extends Module { }
21 // public class CountMergeModule extends Module { }
22 // public class SortMergeModule extends Module { }
23 // public class FanOutModule extends Module { }
24 // public class MemoryModule extends Module { }
25 // public class DoneModule extends Module { }
27 public class Process {
29 public static int reset_count = 0;
30 public static HashSet<Dock> torpedoes = new HashSet<Dock>();
32 public final Fleet fleet;
33 public final ShipPool pool;
35 public Process(Fleet fleet) {
37 this.pool = new ShipPool(fleet);
40 private HashSet<Module> modules = new HashSet<Module>();
42 public void build(Context ctx) {
43 for(Module mod : modules)
46 public void reset(Context ctx, int phase) {
49 for(Module mod : modules)
50 mod.reset(ctx, phase);
56 Process.this.modules.add(this);
59 private HashMap<String,Port> ports = new HashMap<String,Port>();
61 public InPort getInPort(String name) { return (InPort)ports.get(name); }
62 public OutPort getOutPort(String name) { return (OutPort)ports.get(name); }
64 public void build(Context ctx) { for(Port p : ports.values()) p.build(ctx); }
65 public void reset(Context ctx, int phase) { for(Port p : ports.values()) p.reset(ctx, phase); }
67 public abstract class Port {
68 public final String name;
69 public Port(String name) {
71 if (Module.this.ports.get(name)!=null) throw new RuntimeException();
72 Module.this.ports.put(name,this);
74 public abstract void build(Context ctx);
75 public abstract void reset(Context ctx, int phase);
78 public abstract class InPort extends Port {
80 public InPort(String name) { super(name); }
81 public void connect(OutPort peer) {
85 public void setPeer(OutPort peer) {
86 if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
90 /** this port's peer (an OutPort) invokes this to have "recvToken" or equivalent inserted */
91 public abstract void recvToken(Context.LoopFactory loopfactory_at_output_dock);
92 /** this port's peer (an OutPort) invokes this to have "sendWord" or equivalent inserted */
93 public abstract void sendWord(Context.LoopFactory loopfactory_at_output_dock);
96 public abstract class OutPort extends Port {
98 public OutPort(String name) { super(name); }
99 public void connect(InPort peer) {
103 public void setPeer(InPort peer) {
104 if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice");
108 /** this port's peer (an InPort) invokes this to have "sendToken" or equivalent inserted */
109 public abstract void sendToken(Context.LoopFactory loopfactory_at_input_dock);
110 /** this port's peer (an InPort) invokes this to have "recvWord" or equivalent inserted */
111 public abstract void recvWord(Context.LoopFactory loopfactory_at_input_dock);
114 public final class DockInPort extends InPort {
118 public DockInPort(String name, Dock dock) { this(name, dock, 0); }
119 public DockInPort(String name, Dock dock, int count) { this(name, dock, count, new BitVector[] { null }); }
120 public DockInPort(String name, Dock dock, int count, BitVector[] pattern) {
124 this.pattern = pattern;
126 public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
127 public void sendWord(Context.LoopFactory lf) { lf.sendWord(dock.getDataDestination()); }
128 public void build(Context ctx) { build(ctx, ctx.new LoopFactory(dock, 1)); }
129 // number-in-flight is considered a property of the input dock in a pair
130 //public int getInflight() { return 4; }
131 public int getInflight() { return 1; }
132 public void reset(Context ctx, int phase) {
133 if (dock.getShip().getType().equals("Debug")) {
144 Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
145 lf.sendToken(fleet.getShip("Debug",0).getDock("in").getDataDestination());
146 if (peer != null && peer instanceof DockOutPort) {
147 DockOutPort dop_peer = (DockOutPort)peer;
149 lf.abortLoopIfTorpedoPresent();
151 lf.sendToken(dop_peer.dock.getDataDestination());
156 if (peer != null && peer instanceof DockOutPort) {
163 protected void build(Context ctx, Context.LoopFactory lf) {
164 int inflight = (count != 0 && count < getInflight()) ? count : getInflight();
167 for(int i=0; i<inflight; i++) peer.sendToken(lf);
169 lf = lf.makeNext(count);
170 for(int i=0; i<pattern.length; i++) {
171 if (pattern[i]==null) {
172 lf.abortLoopIfTorpedoPresent();
177 lf.literal(pattern[i]);
178 lf.abortLoopIfTorpedoPresent();
184 // "torpedoable nop" to keep the dock in a receptive state
185 lf.abortLoopIfTorpedoPresent();
191 public final class DockOutPort extends OutPort {
192 public final Dock dock;
193 public final int count;
194 public DockOutPort(String name, Dock dock) { this(name, dock, 0); }
195 public DockOutPort(String name, Dock dock, int count) { super(name); this.dock = dock; this.count = count; }
196 public void sendToken(Context.LoopFactory lf) { lf.sendToken(dock.getDataDestination()); }
197 public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
198 public void build(Context ctx) { build(ctx, ctx.new LoopFactory(dock, 1)); }
199 protected void build(Context ctx, Context.LoopFactory lf) {
200 if (peer==null) return;
202 lf = lf.makeNext(count);
203 lf.abortLoopIfTorpedoPresent();
205 //lf.abortLoopIfTorpedoPresent(); // FIXME: do I need this twice?
210 public void reset(Context ctx, int phase) {
218 Context.LoopFactory lf = ctx.new LoopFactory(dock, 1);
219 if (peer instanceof DockInPort) {
220 DockInPort dip_peer = (DockInPort)peer;
221 for(int i=0; i<dip_peer.getInflight(); i++) {
224 //lf.sendToken(dip_peer.dock.getInstructionDestination());
226 lf.sendToken(fleet.getShip("Debug",0).getDock("in").getDataDestination());
228 lf.abortLoopIfTorpedoPresent();
241 private BitVector bv(long l) { return new BitVector(fleet.getWordWidth()).set(l); }
244 * For every datum transmitted to in, pass it along to out and
245 * deliver the constant at out. Flow control in<->out is
246 * maintained, but out is not flow-controlled, so be sure
247 * that every datum sent there is consumed synchronously wiht
248 * data items sent to out.
250 public class ForeverModule extends Module {
251 private BitVector bv;
252 public final OutPort out = new OutPort("out") {
253 public void sendToken(Context.LoopFactory lf) { }
254 public void recvWord(Context.LoopFactory lf) { }
255 public void build(Context ctx) { }
256 public void reset(Context ctx, int phase) { }
257 public void setPeer(InPort peer) {
259 DockInPort pip = ((DockInPort)peer);
260 for(int i=0; i<pip.pattern.length; i++) {
261 if (pip.pattern[i]==null)
266 public ForeverModule(long l) { this(new BitVector(fleet.getWordWidth()).set(l)); }
267 public ForeverModule(final BitVector bv) { this.bv = bv; }
270 public class OnceModule 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) {
279 DockInPort pip = ((DockInPort)peer);
280 BitVector[] pip_pattern = pip.pattern;
281 BitVector[] temp = new BitVector[pip_pattern.length * 2];
284 boolean done = false;
285 // FIXME: if peer.count is already 1, this gets simpler and different
286 for(i=0; i<temp.length; i++) {
287 if (pip_pattern[j] != null) {
288 temp[i] = pip_pattern[j];
295 if (j >= pip_pattern.length) j = 0;
297 pip.pattern = new BitVector[i];
298 System.arraycopy(temp, 0, pip.pattern, 0, i);
302 public OnceModule(long l) { this(new BitVector(fleet.getWordWidth()).set(l)); }
303 public OnceModule(final BitVector bv) { this.bv = bv; }
306 public class DebugModule extends Module {
307 public final Ship ship = pool.allocateShip("Debug");
308 public final InPort in = new DockInPort("in", ship.getDock("in"));
309 // NOTE: shutdown needs to treat this specially
310 public DebugModule() { }
313 public class UnPunctuatorModule extends Module {
314 private final Ship ship = pool.allocateShip("Counter");
315 public final OutPort out = new DockOutPort("out", ship.getDock("out"));
316 public final InPort val = new DockInPort("in1", ship.getDock("in1"));
317 public final InPort count = new DockInPort("in2", ship.getDock("in2"), 0, new BitVector[] { null, bv(1) });
318 public final InPort op = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(6 /*PASS_C2_V1*/), bv(10 /*DROP_C2_V1*/) } );
319 public UnPunctuatorModule() { }
322 public class PunctuatorModule extends Module {
323 private final long punc;
324 private final Ship ship = pool.allocateShip("Counter");
325 public final OutPort out = new DockOutPort("out", ship.getDock("out"));
326 public final InPort val = new DockInPort("in1", ship.getDock("in1"));
327 public final InPort op = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(6 /*PASS_C2_V1*/), bv(7 /*PASS_C2_V2*/) } );
328 public final InPort count;
329 public PunctuatorModule(long punc) {
331 this.count = new DockInPort("in2", ship.getDock("in2"), 0, new BitVector[] { null, bv(1), bv(punc) });
335 public class AluModule extends Module {
336 public final Ship ship = pool.allocateShip("Alu");
337 public final InPort in1 = new DockInPort("in1", ship.getDock("in1"));
338 public final InPort in2 = new DockInPort("in2", ship.getDock("in2"));
339 public final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"));
340 public final OutPort out = new DockOutPort("out", ship.getDock("out"));
341 public AluModule() { }
344 public class DownCounterModule extends Module {
345 public final Ship ship = pool.allocateShip("Counter");
346 public final InPort start = new DockInPort("in1", ship.getDock("in1"));
347 public final InPort incr = new DockInPort("in2", ship.getDock("in2"));
348 public final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(12 /*COUNTDOWN*/) });
349 public final OutPort out = new DockOutPort("out", ship.getDock("out"));
350 public DownCounterModule() { }
353 public class RepeatModule extends Module {
354 public final Ship ship = pool.allocateShip("Counter");
355 public final InPort count = new DockInPort("in1", ship.getDock("in1"));
356 public final InPort val = new DockInPort("in2", ship.getDock("in2"));
357 public final InPort inOP = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(1 /*REPEAT_C1_V2*/) });
358 public final OutPort out = new DockOutPort("out", ship.getDock("out"));
359 public RepeatModule() { }
362 public class SortedMergeModule extends Module {
363 public final Ship ship = pool.allocateShip("Alu");
364 public final InPort in1 = new DockInPort("in1", ship.getDock("in1"));
365 public final InPort in2 = new DockInPort("in2", ship.getDock("in2"));
366 public final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { bv(9 /*MAXMERGE*/) });
367 public final OutPort out = new DockOutPort("out", ship.getDock("out"));
368 public SortedMergeModule() { }
371 public class MemoryModule extends Module {
372 public final Ship ship;
373 public final InPort inAddrRead1;
374 public final InPort inAddrRead2;
375 //public final InPort inAddrWrite;
376 //public final InPort inDataWrite;
377 public final OutPort outRead1;
378 public final OutPort outRead2;
379 public MemoryModule(Ship memoryShip) {
380 this.ship = memoryShip;
381 this.inAddrRead1 = new InPort("inAddrRead1") {
382 public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
383 public void sendWord(Context.LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(0)); }
384 public void build(Context ctx) { }
385 public void reset(Context ctx, int phase) {
387 torpedoes.add(ship.getDock("inAddrRead"));
388 torpedoes.add(ship.getDock("out"));
392 this.inAddrRead2 = new InPort("inAddrRead2") {
393 public void recvToken(Context.LoopFactory lf) { lf.recvToken(); }
394 public void sendWord(Context.LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(1)); }
395 public void build(Context ctx) { }
396 public void reset(Context ctx, int phase) {
398 torpedoes.add(ship.getDock("inAddrRead"));
399 torpedoes.add(ship.getDock("out"));
403 this.outRead1 = new OutPort("outRead1") {
404 public void sendToken(Context.LoopFactory lf) { inAddrRead1.peer.sendToken(lf); }
405 public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
406 public void build(Context ctx) { }
407 public void reset(Context ctx, int phase) { }
409 this.outRead2 = new OutPort("outRead2") {
410 public void sendToken(Context.LoopFactory lf) { inAddrRead2.peer.sendToken(lf); }
411 public void recvWord(Context.LoopFactory lf) { lf.recvWord(); }
412 public void build(Context ctx) { }
413 public void reset(Context ctx, int phase) { }
416 public void build(Context ctx) {
418 Context.LoopFactory lf;
420 lf = ctx.new LoopFactory(ship.getDock("inAddrRead"), 0);
421 lf.abortLoopIfTorpedoPresent();
423 lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
424 lf.setPredicate(Predicate.NotFlagA);
425 lf.sendToken(ship.getDock("out").getDataDestination(), new BitVector(1).set(0));
426 lf.setPredicate(Predicate.FlagA);
427 lf.sendToken(ship.getDock("out").getDataDestination(), new BitVector(1).set(1));
428 lf.setPredicate(null);
431 lf = ctx.new LoopFactory(ship.getDock("out"), 0);
432 lf.abortLoopIfTorpedoPresent();
434 lf.abortLoopIfTorpedoPresent();
436 lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
437 if (outRead1.peer != null) {
438 lf.setPredicate(Predicate.NotFlagA);
439 outRead1.peer.sendWord(lf);
441 if (outRead2.peer != null) {
442 lf.setPredicate(Predicate.FlagA);
443 outRead2.peer.sendWord(lf);
445 lf.setPredicate(null);
449 public static void main(String[] s) throws Exception {
450 Fleet fleet = new Fpga();
451 Random random = new Random(System.currentTimeMillis());
452 long[] vals = new long[256];
453 for(int i=0; i<vals.length; i++) {
454 vals[i] = Math.abs(random.nextInt());
460 while(stride < vals.length) {
461 if (fp==null) fp = fleet.run(new Instruction[0]);
462 System.out.println("stride " + stride);
463 vals = mergeSort(fp, fleet, vals, stride);
465 //fp.terminate(); fp = null;
466 System.out.println();
467 System.out.println("results:");
468 for(int i=0; i<vals.length; i++)
469 System.out.println(vals[i]);
473 // won't verify that the switch fabric is empty, however
474 public static void verifyClean(FleetProcess fp) {
475 Ship debug = fp.getFleet().getShip("Debug", 0);
476 Dock debugIn = debug.getDock("in");
479 Context.LoopFactory lf;
481 ctx = new Context(fp.getFleet());
482 lf = ctx.new LoopFactory(debugIn, 1);
487 ArrayList<Instruction> ai = new ArrayList<Instruction>();
489 for(Instruction ins : ai) fp.sendInstruction(ins);
492 System.out.println("checking debug.in");
493 if (fp.recvWord().toLong() != 12) throw new RuntimeException("debug dock not properly initialized");
494 if (fp.recvWord().toLong() != 5) throw new RuntimeException("debug dock not properly initialized");
497 for(Ship ship : fp.getFleet())
498 if (!"Debug".equals(ship.getType()))
499 for (Dock dock : ship) {
500 System.out.println("checking " + dock);
502 k = (k + 23) % 65535;
503 ctx = new Context(fp.getFleet());
505 boolean reverse = (k%2)==0;
507 lf = ctx.new LoopFactory(debugIn, 2);
509 lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
510 lf.setPredicate(Predicate.NotFlagA);
512 lf.setPredicate(Predicate.FlagA);
514 lf.setPredicate(null);
517 lf = ctx.new LoopFactory(dock, 1);
518 lf.sendToken(dock.getDataDestination(), new BitVector(1).set(reverse ? 1 : 0));
519 lf.sendToken(dock.getDataDestination(), new BitVector(1).set(reverse ? 0 : 1));
522 lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO);
523 lf.setPredicate(Predicate.NotFlagA);
524 lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(0));
525 lf.setPredicate(Predicate.FlagA);
526 lf.sendToken(debugIn.getDataDestination(), new BitVector(1).set(1));
527 lf.setPredicate(null);
529 ai = new ArrayList<Instruction>();
531 for(Instruction ins : ai) fp.sendInstruction(ins);
535 kk = fp.recvWord().toLong();
536 if (kk != (reverse ? k+1 : k))
537 throw new RuntimeException(dock+" not properly initialized (1)");
538 kk = fp.recvWord().toLong();
539 if (kk != (reverse ? k : k+1))
540 throw new RuntimeException(dock+" not properly initialized (2)");
544 // FIXME: numbers seem to get duplicated when stride=2
545 public static long[] mergeSort(FleetProcess fp, Fleet fleet, long[] vals, int stride_length) throws Exception {
547 BitVector[] mem = new BitVector[vals.length];
548 for(int i=0; i<mem.length; i++) mem[i] = new BitVector(fleet.getWordWidth()).set(vals[i]);
550 Ship memoryShip = fleet.getShip("DRAM", 0);
551 Gadgets.writeMem(fp, memoryShip, 0, mem);
553 //////////////////////////////////////////////////////////////////////////////
555 Process proc = new Process(fleet);
556 DebugModule dm = proc.new DebugModule();
558 int end_of_data = vals.length;
559 int num_strides = end_of_data / (stride_length * 2);
561 MemoryModule mm = proc.new MemoryModule(memoryShip);
562 SortedMergeModule sm = proc.new SortedMergeModule();
565 for(int i=0; i<2; i++) {
567 Module.OutPort stride_length_1 = proc.new OnceModule(stride_length).out;
568 Module.OutPort stride_length_2 = proc.new OnceModule(stride_length).out;
569 Module.OutPort twice_stride_length_1 = proc.new OnceModule(stride_length*2).out;
570 Module.OutPort end_of_data_1 = proc.new OnceModule(end_of_data + i*stride_length).out;
572 Module.OutPort num_strides_1 = proc.new OnceModule(num_strides).out;
573 Module.OutPort num_strides_2 = proc.new OnceModule(num_strides).out;
575 RepeatModule r0 = proc.new RepeatModule();
576 RepeatModule r1 = proc.new RepeatModule();
577 RepeatModule r2 = proc.new RepeatModule();
578 DownCounterModule c0 = proc.new DownCounterModule();
579 DownCounterModule c1 = proc.new DownCounterModule();
580 ForeverModule fmm = proc.new ForeverModule(1);
581 ForeverModule fmm2 = proc.new ForeverModule(2); // 2=ADD
582 AluModule alu = proc.new AluModule();
584 stride_length_1.connect(r0.val);
585 num_strides_1.connect(r0.count);
586 r0.out.connect(c0.start);
587 fmm.out.connect(c0.incr);
588 c0.out.connect(alu.in2);
590 end_of_data_1.connect(c1.start);
591 twice_stride_length_1.connect(c1.incr);
592 c1.out.connect(r1.val);
593 stride_length_2.connect(r2.val);
594 num_strides_2.connect(r2.count);
595 r2.out.connect(r1.count);
596 r1.out.connect(alu.in1);
597 fmm2.out.connect(alu.inOp);
599 alu.out.connect(i==0 ? mm.inAddrRead1 : mm.inAddrRead2);
601 ForeverModule fm = proc.new ForeverModule(stride_length);
602 PunctuatorModule punc = proc.new PunctuatorModule(-1);
603 fm.out.connect(punc.count);
604 (i==0 ? mm.outRead1 : mm.outRead2).connect(punc.val);
605 punc.out.connect(i==0 ? sm.in1 : sm.in2);
608 ForeverModule fm = proc.new ForeverModule(2*stride_length);
609 UnPunctuatorModule unpunc = proc.new UnPunctuatorModule();
610 sm.out.connect(unpunc.val);
611 fm.out.connect(unpunc.count);
612 unpunc.out.connect(dm.in);
614 //////////////////////////////////////////////////////////////////////////////
616 Context ctx = new Context(fp.getFleet());
617 ctx.setAutoflush(true);
619 ArrayList<Instruction> ai = new ArrayList<Instruction>();
622 for(Instruction ins : ai) {
623 System.out.println(ins);
624 fp.sendInstruction(ins);
628 System.out.println("reading back...");
630 for(int i=0; i<vals.length; i++) {
632 BitVector bv = fp.recvWord();
633 System.out.println("\r"+bv + " " + bv.toLong() + " #read="+inc);
636 System.out.println("\rdone. ");
637 long[] ret = new long[vals.length];
638 for(int i=0; i<ret.length; i++) ret[i] = mem[ret.length-i-1].toLong();
640 //if (true) return ret;
642 Context ctx2 = new Context(fp.getFleet());
643 Dock debugIn = fleet.getShip("Debug",0).getDock("in");
645 fp.sendToken(debugIn.getInstructionDestination());
647 Context.LoopFactory lf = ctx2.new LoopFactory(debugIn, 0);
649 lf.abortLoopIfTorpedoPresent();
653 ctx2.emit(ai = new ArrayList<Instruction>());
654 for(Instruction ins : ai)
655 fp.sendInstruction(ins);
660 for(int phase=0; phase<=2; phase++) {
661 System.out.println("== phase "+phase+" ==================================================================");
662 ctx2 = new Context(fp.getFleet());
663 proc.reset(ctx2, phase);
664 for(Dock dock : torpedoes) fp.sendToken(dock.getInstructionDestination());
665 ctx2.emit(ai = new ArrayList<Instruction>());
666 for(Instruction ins : ai) fp.sendInstruction(ins);
668 System.out.println("flushed");
669 for(int ii=0; ii<reset_count; ii++)
670 System.out.print("\r phase "+phase+" ==> " + fp.recvWord().toLong() + " " + (ii+1) + " / " + reset_count);
671 System.out.println();
675 ctx2 = new Context(fp.getFleet());
676 ai = new ArrayList<Instruction>();
677 for(Ship ship : ctx.allocatedShips)
678 if (!ship.getType().equals("Debug"))
679 for(Dock dock : ship)
680 if (dock.isInputDock()) {
681 lf = ctx2.new LoopFactory(dock, 0);
687 fp.sendToken(debugIn.getInstructionDestination());
690 //System.out.println("verifying cleanup:");
695 private BitVector[] longsToBitVectors(long[] initialValues) {
696 BitVector[] bv = new BitVector[initialValues.length];
697 for(int i=0; i<initialValues.length; i++)
698 bv[i] = new BitVector(fleet.getWordWidth()).set(initialValues[i]);