From: megacz Date: Mon, 6 Apr 2009 18:41:48 +0000 (-0700) Subject: major refactoring of edu.berkeley.fleet.dataflow X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=8c0ded5d44a56e0970895ad1b347130dc529ba25;p=fleet.git major refactoring of edu.berkeley.fleet.dataflow --- diff --git a/src/edu/berkeley/fleet/dataflow/AluNode.java b/src/edu/berkeley/fleet/dataflow/AluNode.java index b5fa765..47aeae0 100644 --- a/src/edu/berkeley/fleet/dataflow/AluNode.java +++ b/src/edu/berkeley/fleet/dataflow/AluNode.java @@ -12,4 +12,8 @@ public class AluNode extends Node { public final OutPort out = new DockOutPort("out", ship.getDock("out")); public AluNode(DataFlowGraph dfg) { super(dfg); } + public AluNode(DataFlowGraph dfg, String opcode) { + super(dfg); + inOp.connect(new ForeverNode(dfg, ((Node.DockInPort)inOp).getConstant(opcode)).out); + } } diff --git a/src/edu/berkeley/fleet/dataflow/DataFlowGraph.java b/src/edu/berkeley/fleet/dataflow/DataFlowGraph.java index 9ab17f6..7916538 100644 --- a/src/edu/berkeley/fleet/dataflow/DataFlowGraph.java +++ b/src/edu/berkeley/fleet/dataflow/DataFlowGraph.java @@ -5,29 +5,35 @@ import edu.berkeley.fleet.api.*; import java.util.*; import java.net.*; -public class DataFlowGraph { +/** + * A dataflow graph. + */ +public class DataFlowGraph implements Iterable { public final Fleet fleet; public final ShipPool pool; - private HashSet nodes = new HashSet(); - public DataFlowGraph(Fleet fleet) { this(fleet, new ShipPool(fleet)); } + /** + * Use LinkedHashSet to get a predictable/repeatable iteration + * order, which leads to predictable/repeatable code + */ + private LinkedHashSet nodes = new LinkedHashSet(); + public DataFlowGraph(Fleet fleet, ShipPool pool) { this.fleet = fleet; this.pool = pool; } + public Iterator iterator() { return nodes.iterator(); } public void addNode(Node node) { this.nodes.add(node); } - public void build(Context ctx) { - for(Node mod : nodes) - mod.build(ctx); - } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { - int ret = 0; - for(Node mod : nodes) - ret += mod.reset(ctx, phase, ackDestination, sendTorpedoesTo); - return ret; + public CodeBag build(CodeBag cb) { + boolean oldAutoflush = cb.getAutoflush(); + cb.setAutoflush(true); + for(Node mod : nodes) mod.build(cb); + // this breaks stuff, but it shouldn't! + //cb.setAutoflush(oldAutoflush); + return cb; } } diff --git a/src/edu/berkeley/fleet/dataflow/DebugNode.java b/src/edu/berkeley/fleet/dataflow/DebugNode.java index 1c6e842..af734ea 100644 --- a/src/edu/berkeley/fleet/dataflow/DebugNode.java +++ b/src/edu/berkeley/fleet/dataflow/DebugNode.java @@ -3,6 +3,7 @@ import java.util.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; +/** Items supplied to the "in" port will appear at the debug output of the Fleet */ public class DebugNode extends Node { private final Ship ship = dfg.pool.allocateShip("Debug"); public final InPort in = new DockInPort("in", ship.getDock("in")); diff --git a/src/edu/berkeley/fleet/dataflow/DiscardNode.java b/src/edu/berkeley/fleet/dataflow/DiscardNode.java new file mode 100644 index 0000000..f931e27 --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/DiscardNode.java @@ -0,0 +1,37 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; +import edu.berkeley.fleet.api.Instruction.Set.FlagFunction; + +public class DiscardNode extends Node { + + private final Ship ship = dfg.pool.allocateShip("Counter"); + private final InPort op = new DockInPort("op", ship.getDock("inOp"), "PASS_C2_V1"); + public final InPort in = new DockInPort("val", ship.getDock("in1")); + public final InPort count = new DockInPort("count", ship.getDock("in2")); + + public final OutPort out = new DockOutPort("out", ship.getDock("out")) { + protected void build(CodeBag ctx, LoopFactory lf) { + + lf = lf.makeNext(0); + + lf.abortLoopIfTorpedoPresent(); + lf.collectWord(); + lf.setFlags(FlagFunction.ZERO.add(Predicate.FlagC), FlagFunction.ZERO); + + lf.setPredicate(Predicate.FlagA); + lf.abortLoopIfTorpedoPresent(); + peer.recvToken(lf); + peer.sendWord(lf); + lf.setPredicate(null); + + } + }; + + public DiscardNode(DataFlowGraph dfg) { + super(dfg); + } + +} + diff --git a/src/edu/berkeley/fleet/dataflow/DoneNode.java b/src/edu/berkeley/fleet/dataflow/DoneNode.java new file mode 100644 index 0000000..7c966cf --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/DoneNode.java @@ -0,0 +1,213 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; +import edu.berkeley.fleet.api.Instruction.Set.FlagFunction; + +/** + * This class contains all of the shutdown and cleanup logic. + */ +public class DoneNode extends Node { + + private final Ship counter = dfg.pool.allocateShip("Counter"); + private final Program program; + private CodeBag shutdownCodeBag = null; + + public final InPort in = new InPort("in") { + private Dock dock = counter.getDock("out"); + public void recvToken(LoopFactory lf) { } + public void sendWord(LoopFactory lf) { lf.sendToken(dock); } + public int getInflight() { return 1; } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } + public void build(CodeBag ctx) { build(ctx, ctx.loopFactory(dock, 1)); } + protected void build(CodeBag ctx, LoopFactory lf) { + lf.recvToken(); + lf.literal(getShutdownCodeBag()); + lf.sendWord(program.getCBDDestination()); + } + }; + + public DoneNode(DataFlowGraph dfg, Program program) { + super(dfg); + this.program = program; + } + + public Destination getDestinationToSendNextCodeBagDescriptorTo() { + return counter.getDock("in1").getDataDestination(); + } + + private static final int PHASES = 4; + + private CodeBag getShutdownCodeBag() { + if (shutdownCodeBag!=null) return shutdownCodeBag; + + CodeBag[] cb = new CodeBag[PHASES]; + for(int phase=0; phase + lf.literal("DROP_C1_V2"); + lf.deliver(); + lf.literal("PASS_C1_V1"); + lf.deliver(); + lf.abort(); + + lf = ctx_counter.loopFactory(counter.getDock("in1"), 0); + lf.sendToken(counter.getDock("out")); // ready-> + lf.literal(expected_tokens); + lf.deliver(); + lf.literal(1); + lf.deliver(); + if (phase + lf.setPredicate(null); + lf.setFlags(FlagFunction.ONE, FlagFunction.ZERO); + lf.abortLoopIfTorpedoPresent(); + lf.recvWord(); + lf.deliver(); + + lf = ctx_counter.loopFactory(counter.getDock("out"), 1); + lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO); + lf.literal(ctx_reset); + lf = lf.makeNext(0); + lf.setPredicate(Predicate.NotFlagA); + lf.recvToken(); + lf.recvToken(); + lf.recvToken(); + lf.sendWord(program.getCBDDestination()); + lf.setFlags(FlagFunction.ONE, FlagFunction.ZERO); + lf.setPredicate(null); + lf.collectWord(); + lf.sendTorpedo(counter.getDock("in2")); + lf.recvToken(); + lf.sendWord(program.getCBDDestination()); + lf.abort(); + + cb[phase].seal(); + ctx_reset.seal(); + } + return (shutdownCodeBag = cb[0]); + } + + // Reset ////////////////////////////////////////////////////////////////////////////// + + static int doReset(CodeBag ctx, + int phase, + Dock dock, + Port self, + Port peer, + Destination ackDestination, + boolean peerUsed) { + int ret = 0; + + switch(phase) { + + // Phase 0: torpedo every output dock, put it in + // collecting mode. Cannot combine with phase 1, + // because until output docks are in vacuum mode we + // cannot be sure that the tokens to the input docks + // will eventually succeed. This may cause the + // instructions sent after the tokens to back up into + // the switch fabric. + case 0: { + if (!dock.isInputDock()) { + ctx.sendTorpedo(dock); + LoopFactory lf = ctx.loopFactory(dock, 1); + lf.sendToken(ackDestination); + lf = lf.makeNext(0); + lf.abortLoopIfTorpedoPresent(); + lf.collectWord(); + ret++; + } + break; + } + + // [wait for all output docks to confirm that they've been torpedoed] + // Phase 1: torpedo every input dock (causing them to flush), put it in loopback mode + case 1: { + if (dock.isInputDock()) { + ctx.sendTorpedo(dock); + LoopFactory lf = ctx.loopFactory(dock, 1); + lf.sendToken(ackDestination); + + // FIXME: this won't work right for ports that + // get "shared" by two senders (for example, + // inAddrRead1/2) + + if (peerUsed && peer!=null) { + lf = lf.makeNext(0); + lf.abortLoopIfTorpedoPresent(); + ((OutPort)peer).recvWord(lf); + ((OutPort)peer).sendToken(lf); + } + ret++; + } + break; + } + + // [wait for all input docks to confirm that they've been torpedoed and have flushed] + // Phase 2: torpedo every output dock, have it absorb tokens + case 2: { + if (!dock.isInputDock()) { + ctx.sendTorpedo(dock); + LoopFactory lf = ctx.loopFactory(dock, 1); + for(int i=0; i<((OutPort)self).getTokensToAbsorb(); i++) + lf.recvToken(); + lf.sendToken(ackDestination); + ret++; + } + break; + } + + // [wait for all output docks to confirm that they've absorbed enough tokens] + // Phase 3: torpedo every input dock, await confirmation, and we're done + case 3: { + if (dock.isInputDock()) { + if (peerUsed && peer!=null) { + ctx.sendTorpedo(dock); + } + LoopFactory lf = ctx.loopFactory(dock, 1); + lf.sendToken(ackDestination); + ret++; + } + break; + } + } + return ret; + } +} diff --git a/src/edu/berkeley/fleet/dataflow/DownCounterNode.java b/src/edu/berkeley/fleet/dataflow/DownCounterNode.java index a17daef..61efbc9 100644 --- a/src/edu/berkeley/fleet/dataflow/DownCounterNode.java +++ b/src/edu/berkeley/fleet/dataflow/DownCounterNode.java @@ -3,11 +3,14 @@ import java.util.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; +/** + * Takes a starting value at "start" and a (positive) decrement + * amount at "incr" and counts down; the first value emitted will be + * (start-incr). + */ public class DownCounterNode extends Node { private final Ship ship = dfg.pool.allocateShip("Counter"); - private final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { - ship.getDock("inOp").getConstant("COUNT") }); - + private final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"), "COUNT"); public final InPort start = new DockInPort("start", ship.getDock("in1")); public final InPort incr = new DockInPort("incr", ship.getDock("in2")); public final OutPort out = new DockOutPort("out", ship.getDock("out")); diff --git a/src/edu/berkeley/fleet/dataflow/DropNode.java b/src/edu/berkeley/fleet/dataflow/DropNode.java new file mode 100644 index 0000000..a1da02a --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/DropNode.java @@ -0,0 +1,24 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; + +/** + * Discards all items provided; does not require any ships. + */ +public class DropNode extends Node { + + public final InPort in = new InPort("in") { + // FIXME: I'm still not sure if this screws up the protocol somewhere + public void recvToken(LoopFactory loopfactory_at_output_dock) { } + public void sendWord(LoopFactory loopfactory_at_output_dock) { } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } + public void build(CodeBag ctx) { } + }; + + public DropNode(DataFlowGraph dfg) { + super(dfg); + } + +} + diff --git a/src/edu/berkeley/fleet/dataflow/FifoNode.java b/src/edu/berkeley/fleet/dataflow/FifoNode.java new file mode 100644 index 0000000..7c984f8 --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/FifoNode.java @@ -0,0 +1,14 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; + +/** A simple FIFO */ +public class FifoNode extends Node { + private final Ship ship = dfg.pool.allocateShip("Fifo"); + + public final InPort in = new DockInPort("in", ship.getDock("in")); + public final OutPort out = new DockOutPort("out", ship.getDock("out")); + + public FifoNode(DataFlowGraph dfg) { super(dfg); } +} diff --git a/src/edu/berkeley/fleet/dataflow/ForeverNode.java b/src/edu/berkeley/fleet/dataflow/ForeverNode.java index e801b4f..556ff5f 100644 --- a/src/edu/berkeley/fleet/dataflow/ForeverNode.java +++ b/src/edu/berkeley/fleet/dataflow/ForeverNode.java @@ -14,8 +14,8 @@ public class ForeverNode extends Node { public final OutPort out = new OutPort("out") { public void sendToken(LoopFactory lf) { } public void recvWord(LoopFactory lf) { } - public void build(Context ctx) { } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { return 0; } + public void build(CodeBag ctx) { } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } public void setPeer(InPort peer) { this.peer = peer; DockInPort pip = ((DockInPort)peer); diff --git a/src/edu/berkeley/fleet/dataflow/Lut3Node.java b/src/edu/berkeley/fleet/dataflow/Lut3Node.java new file mode 100644 index 0000000..c2eb366 --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/Lut3Node.java @@ -0,0 +1,16 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; + +public class Lut3Node extends Node { + private final Ship ship = dfg.pool.allocateShip("Lut3"); + + public final InPort in1 = new DockInPort("in1", ship.getDock("in1")); + public final InPort in2 = new DockInPort("in2", ship.getDock("in2")); + public final InPort in3 = new DockInPort("in3", ship.getDock("in3")); + public final InPort inLut = new DockInPort("inLut", ship.getDock("inLut")); + public final OutPort out = new DockOutPort("out", ship.getDock("out")); + + public Lut3Node(DataFlowGraph dfg) { super(dfg); } +} diff --git a/src/edu/berkeley/fleet/dataflow/MemoryNode.java b/src/edu/berkeley/fleet/dataflow/MemoryNode.java index f0f3cad..a892672 100644 --- a/src/edu/berkeley/fleet/dataflow/MemoryNode.java +++ b/src/edu/berkeley/fleet/dataflow/MemoryNode.java @@ -2,6 +2,7 @@ package edu.berkeley.fleet.dataflow; import java.util.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; +import edu.berkeley.fleet.fpga.*; import edu.berkeley.fleet.api.Instruction.*; import edu.berkeley.fleet.api.Instruction.Set; import edu.berkeley.fleet.api.Instruction.Set.*; @@ -21,49 +22,74 @@ public class MemoryNode extends Node { public MemoryNode(DataFlowGraph dfg, Ship memoryShip) { super(dfg); this.ship = memoryShip; + + // ugly hack + if (ship.getType().equals("Dvi")) { + new DockInPort("inPixelX", ship.getDock("inPixelX"), 0, new BitVector[] { null }); + new DockInPort("inPixelY", ship.getDock("inPixelY"), 0, new BitVector[] { null }); + new DockInPort("inPixelValue", ship.getDock("inPixelValue"), 0, new BitVector[] { null }); + } + this.inCBD = ship.getType().equals("Memory") ? new DockInPort("inCBD", ship.getDock("inCBD")) : null; - this.inAddrWrite = new DockInPort("inAddrWrite", ship.getDock("inAddrWrite")); this.inDataWrite = new DockInPort("inDataWrite", ship.getDock("inDataWrite")); + this.inAddrWrite = new InPort("inAddrWrite") { + public void recvToken(LoopFactory lf) { lf.recvToken(); } + public void sendWord(LoopFactory lf) { lf.sendWord(ship.getDock("inAddrWrite").getDataDestination()); } + public void build(CodeBag ctx) { + LoopFactory lf = ctx.loopFactory(ship.getDock("inAddrWrite"), 0); + lf.abortLoopIfTorpedoPresent(); + lf.recvWord(); + lf.deliver(); + } + public int getTokensToAbsorb() { return outWrite.peer.getTokensToAbsorb(); } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { + return DoneNode.doReset(ctx, phase, ship.getDock("inAddrWrite"), this, null, ackDestination, false); + } + }; this.inAddrRead1 = new InPort("inAddrRead1") { public void recvToken(LoopFactory lf) { lf.recvToken(); } public void sendWord(LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(0)); } - public void build(Context ctx) { } + public void build(CodeBag ctx) { } public int getTokensToAbsorb() { return outRead1.peer.getTokensToAbsorb(); } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { - return doReset(ctx, phase, ship.getDock("inAddrRead"), null, ackDestination, sendTorpedoesTo, false); + public int reset(CodeBag ctx, int phase, Destination ackDestination) { + return DoneNode.doReset(ctx, phase, ship.getDock("inAddrRead"), this, null, ackDestination, false); } }; this.inAddrRead2 = new InPort("inAddrRead2") { public void recvToken(LoopFactory lf) { lf.recvToken(); } public void sendWord(LoopFactory lf) { lf.sendWord(ship.getDock("inAddrRead").getDataDestination(), new BitVector(1).set(1)); } - public void build(Context ctx) { } + public void build(CodeBag ctx) { } public int getTokensToAbsorb() { return outRead2.peer.getTokensToAbsorb(); } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { return 0; } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } }; this.outRead1 = new OutPort("outRead1") { public void sendToken(LoopFactory lf) { inAddrRead1.peer.sendToken(lf); } public void recvWord(LoopFactory lf) { lf.recvWord(); } - public void build(Context ctx) { } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { return 0; } + public int getNumInitialTokens() { return Math.max(1,Node.CAPACITY/2); } + public void build(CodeBag ctx) { } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } }; this.outRead2 = new OutPort("outRead2") { public void sendToken(LoopFactory lf) { inAddrRead2.peer.sendToken(lf); } public void recvWord(LoopFactory lf) { lf.recvWord(); } - public void build(Context ctx) { } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { return 0; } + public int getNumInitialTokens() { return Math.max(1,Node.CAPACITY/2); } + public void build(CodeBag ctx) { } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } }; this.outWrite = new DockOutPort("out", ship.getDock("out")) { - protected void build(Context ctx, LoopFactory lf) { + public void sendToken(LoopFactory lf) { inAddrWrite.peer.sendToken(lf); } + public void recvWord(LoopFactory lf) { lf.recvWord(); } + public int getTokensToAbsorb() { return 0; } + protected void build(CodeBag ctx, LoopFactory lf) { lf = lf.makeNext(0); lf.abortLoopIfTorpedoPresent(); lf.collectWord(); - lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO.add(FlagC)); + lf.setFlags(FlagFunction.ONE, FlagFunction.ZERO.add(FlagC)); if (this.peer != null) { lf.setPredicate(Predicate.FlagB); lf.literal(77); lf.abortLoopIfTorpedoPresent(); - this.peer.recvToken(lf); this.peer.sendWord(lf); } @@ -83,11 +109,11 @@ public class MemoryNode extends Node { } }; } - public void build(Context ctx) { + public void build(CodeBag ctx) { super.build(ctx); LoopFactory lf; - lf = new LoopFactory(ctx, ship.getDock("inAddrRead"), 0); + lf = ctx.loopFactory(ship.getDock("inAddrRead"), 0); lf.abortLoopIfTorpedoPresent(); lf.recvWord(); lf.setFlags(FlagFunction.ZERO.add(FlagC), FlagFunction.ZERO); @@ -98,4 +124,59 @@ public class MemoryNode extends Node { lf.setPredicate(null); lf.deliver(); } + + + + public static void clearMem(FleetProcess fp, + Ship memory, + ShipPool pool, + long offset, + long count) throws RuntimeException { + + DataFlowGraph dfg = new DataFlowGraph(fp.getFleet(), pool); + + MemoryNode mem = new MemoryNode(dfg, memory); + UnPunctuatorNode discard = new UnPunctuatorNode(dfg, true); + discard.count.connect(new OnceNode(dfg, (int)(count)).out); + DebugNode debug = new DebugNode(dfg); + DownCounterNode c1 = new DownCounterNode(dfg); + c1.start.connect(new OnceNode(dfg, count).out); + c1.incr.connect(new OnceNode(dfg, 1).out); + mem.inAddrWrite.connect(c1.out); + mem.inDataWrite.connect(new ForeverNode(dfg, 0).out); + mem.outWrite.connect(discard.val); + discard.out.connect(debug.in); + + CodeBag ctx = new CodeBag(fp.getFleet()); + dfg.build(ctx); + ctx.dispatch(fp, true); + System.out.println("waiting..."); + fp.recvWord(); + System.out.println("... done"); + + // FIXME: cleanup? + } + + public static void main(String[] s) throws Exception { + Fleet fleet = new Fpga(); + FleetProcess fp; + ShipPool pool = new ShipPool(fleet); + Ship mem1 = pool.allocateShip("Memory"); + Ship mem2 = pool.allocateShip("Memory"); + Ship mem3 = pool.allocateShip("Memory"); + + fp = fleet.run(new Instruction[0]); + clearMem(fp, mem1, new ShipPool(fleet), 0, 16 * 1024); + fp.terminate(); + + fp = fleet.run(new Instruction[0]); + clearMem(fp, mem2, new ShipPool(fleet), 0, 16 * 1024); + fp.terminate(); + + fp = fleet.run(new Instruction[0]); + clearMem(fp, mem3, new ShipPool(fleet), 0, 16 * 1024); + fp.terminate(); + } + + } diff --git a/src/edu/berkeley/fleet/dataflow/MergeSort.java b/src/edu/berkeley/fleet/dataflow/MergeSort.java index 9a8c70e..057db66 100644 --- a/src/edu/berkeley/fleet/dataflow/MergeSort.java +++ b/src/edu/berkeley/fleet/dataflow/MergeSort.java @@ -1,227 +1,452 @@ package edu.berkeley.fleet.dataflow; import java.util.*; +import java.io.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; import edu.berkeley.fleet.fpga.*; -import java.util.*; +//import org.ibex.graphics.*; public class MergeSort { - public static long[] mergeSort(FleetProcess fp, Fleet fleet, ShipPool pool, - long[] vals, int vals_length, int stride_length, - Ship memoryShip1, Ship memoryShip2) throws Exception { - - if (vals != null) { - BitVector[] mem = new BitVector[vals_length]; - for(int i=0; i sendTorpedoesTo = new HashSet(); - Context ctx_reset = new Context(fp.getFleet()); - int expected_tokens = proc.reset(ctx_reset, phase, ackDestination, sendTorpedoesTo); - - Context ctx_debug = new Context(fp.getFleet()); - lf = new LoopFactory(ctx_debug, debugIn, 0); - lf.literal(0); - lf.abortLoopIfTorpedoPresent(); - lf.recvToken(); - lf.deliver(); - - Context ctx_count = new Context(fp.getFleet()); - lf = new LoopFactory(ctx_count, counter.getDock("inOp"), 1); - lf.literal("DROP_C1_V2"); - lf.deliver(); - lf.literal(5); - lf.deliver(); - lf = new LoopFactory(ctx_count, counter.getDock("in1"), 1); - lf.literal(expected_tokens-1); - lf.deliver(); - lf.literal(1); - lf.deliver(); - lf = new LoopFactory(ctx_count, counter.getDock("in2"), 0); - lf.abortLoopIfTorpedoPresent(); - lf.recvWord(); - lf.deliver(); - lf = new LoopFactory(ctx_count, counter.getDock("out"), 1); - lf.collectWord(); - lf.sendToken(counter.getDock("in2").getInstructionDestination()); // HACK: we don't check to make sure this hits - lf.sendToken(debugIn.getDataDestination()); - - Program program = new Program(codeMemoryShip); - CodeBag cb = program.makeCodeBag(ctx_count); - program.install(fp); - MemoryUtils.putMemoryShipInDispatchMode(fp, codeMemoryShip); - program.run(fp, cb); - fp.flush(); - - ctx_debug.dispatch(fp, true); - //ctx_count.dispatch(fp, true); // HACK: we don't check to make sure that this is "firmly in place" - for(Dock dock : sendTorpedoesTo) fp.sendToken(dock.getInstructionDestination()); - ctx_reset.dispatch(fp, true); - System.out.println("flushed"); - - fp.recvWord(); - fp.sendToken(debugIn.getInstructionDestination()); - System.out.println("phase done"); - - MemoryUtils.removeMemoryShipFromDispatchMode(fp, codeMemoryShip); - System.out.println(); + public CodeBag build(DataFlowGraph dfg, + CodeBag ctx, + int vals_length, int stride_length, + long base1, + long base2, + CodeBag next) throws Exception { + + for(int i=0; i= vals_length) break; + int pixel = (x>=p.width) ? 0 : p.data[p.width*y+x]; + long r = (pixel>>0) & 0xff; + long g = (pixel>>8) & 0xff; + long b = (pixel>>16) & 0xff; + r >>= 2; + g >>= 2; + b >>= 2; + //r = ~(-1L<<6); + //g = ~(-1L<<6); + //b = ~(-1L<<6); + bvs[(int)index] = new BitVector(fleet.getWordWidth()).set( r | (g<<6) | (b<<12) | (index<<18) ); + index++; + } + */ + for(; index bvs[i+1].toLong()) + System.out.println("sort failure at "+i+":\n "+bvs[i]+"\n "+bvs[i+1]); + } + */ + fp.terminate(); + return ret; } + static int offset = 40; + + //static int offset = 32; + //static int offset = 544*2; + //static int offset = 544; + + public long main(FleetProcess fp, int vals_length) throws Exception { + + long base_read = offset; + //long base_write = offset+((vals_length/544)+1)*544; + //long base_write = offset; + long base_write = vals_length + offset; + + int stride = 1; + ArrayList codeBags = new ArrayList(); + codeBags.add(new CodeBag(dfg.fleet, program)); + for(; ;) { + CodeBag cb = codeBags.get(codeBags.size()-1); + //System.out.println("cb="+i+", stride="+stride); + boolean last = /*(base_write==offset) && */ (stride*2 >= vals_length); + CodeBag next; + if (last) { + next = program.getEndProgramCodeBag(); + } else { + next = new CodeBag(dfg.fleet, program); + codeBags.add(codeBags.size(), next); + } + build(dfg, cb, vals_length, stride, base_read, base_write, next); + cb.seal(); + long base = base_read; base_read=base_write; base_write=base; + //i++; + if (last) break; + if ((stride*2) < vals_length) stride *= 2; + } + System.out.println("done building codebags; installing..."); + System.out.println("cb.length=="+codeBags.size()); + + Ship button = pool.allocateShip("Button"); + CodeBag cb = new CodeBag(dfg.fleet, program); + LoopFactory lf = cb.loopFactory(button.getDock("out"), 1); + lf.collectWord(); + lf.literal(codeBags.get(0).getDescriptor()); + lf.sendWord(program.getCBDDestination()); + cb.seal(); + + // FIXME + return program.run(fp, cb, new ShipPool(fp.getFleet())); + } + + public static void randomizeMemory(FleetProcess fp, ShipPool pool_, Ship memory, long start, long length, boolean randomize) { + ShipPool pool = new ShipPool(pool_); + Ship mem = pool.allocateShip("Memory"); + Program prog = new Program(mem); + + DataFlowGraph dfg = new DataFlowGraph(fp.getFleet(), pool); + DownCounterNode dcn = new DownCounterNode(dfg); + dcn.start.connectOnce(length); + dcn.incr.connectOnce(1); + + AluNode alu = new AluNode(dfg, "ADD"); + alu.in1.connectForever(start); + alu.in2.connect(dcn.out); + + MemoryNode mn = new MemoryNode(dfg, memory); + mn.inAddrWrite.connect(alu.out); + + AluNode aluAnd = new AluNode(dfg, "AND"); + if (randomize) { + aluAnd.in1.connect(new RandomNode(dfg).out); + } else { + //aluAnd.in1.connectForever( ~(-1L<<36) ); + aluAnd.in1.connectForever( 0 ); + } + aluAnd.in2.connectForever( ~(-1<<18) ); + mn.inDataWrite.connect(aluAnd.out); + + UnPunctuatorNode discard = new UnPunctuatorNode(dfg, true); + discard.count.connectOnce(length); + discard.val.connect(mn.outWrite); + DoneNode done = new DoneNode(dfg, prog); + discard.out.connect(done.in); + + CodeBag cb = new CodeBag(fp.getFleet(), prog); + dfg.build(cb); + cb.seal(); + + CodeBag cb2 = new CodeBag(fp.getFleet(), prog); + Ship button = fp.getFleet().getShip("Button",0); + + LoopFactory lf = cb2.loopFactory(button.getDock("out"), 1); + //lf.collectWord(); + lf.literal(prog.getEndProgramCodeBag().getDescriptor()); + lf.sendWord(done.getDestinationToSendNextCodeBagDescriptorTo()); + lf.literal(cb.getDescriptor()); + lf.sendWord(prog.getCBDDestination()); + cb2.seal(); + + System.out.println("dispatching randomization codebag..."); + prog.run(fp, cb2, pool); + System.out.println(" randomization done."); + pool.releaseAll(); + } } diff --git a/src/edu/berkeley/fleet/dataflow/Node.java b/src/edu/berkeley/fleet/dataflow/Node.java index b4bb13a..f090050 100644 --- a/src/edu/berkeley/fleet/dataflow/Node.java +++ b/src/edu/berkeley/fleet/dataflow/Node.java @@ -15,6 +15,8 @@ import static edu.berkeley.fleet.util.BitManipulations.*; public class Node { + public static int CAPACITY = 4; + public final DataFlowGraph dfg; public Node(DataFlowGraph dfg) { this.dfg = dfg; @@ -22,10 +24,10 @@ public class Node { } private HashMap ports = new HashMap(); - public void build(Context ctx) { for(Port p : ports.values()) p.build(ctx); } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { + public void build(CodeBag ctx) { for(Port p : ports.values()) p.build(ctx); } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { int ret = 0; - for(Port p : ports.values()) ret += p.reset(ctx, phase, ackDestination, sendTorpedoesTo); + for(Port p : ports.values()) ret += p.reset(ctx, phase, ackDestination); return ret; } @@ -36,8 +38,8 @@ public class Node { if (Node.this.ports.get(name)!=null) throw new RuntimeException(); Node.this.ports.put(name,this); } - public abstract void build(Context ctx); - public abstract int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo); + public abstract void build(CodeBag ctx); + public abstract int reset(CodeBag ctx, int phase, Destination ackDestination); public String toString() { return Node.this+"."+name; } } @@ -48,6 +50,10 @@ public class Node { this.setPeer(peer); peer.setPeer(this); } + + public void connectOnce(long val) { connect(new OnceNode(dfg, val).out); } + public void connectForever(long val) { connect(new ForeverNode(dfg, val).out); } + public void setPeer(OutPort peer) { if (this.peer!=null) throw new RuntimeException("cannot call setPeer() twice"); this.peer = peer; @@ -59,6 +65,7 @@ public class Node { public abstract void sendWord(LoopFactory loopfactory_at_output_dock); public int getTokensToAbsorb() { return 0; } + public int getMaxInFlight() { return 0; } } public abstract class OutPort extends Port { @@ -73,17 +80,29 @@ public class Node { this.peer = peer; } + public int getNumInitialTokens() { + return peer.getMaxInFlight(); + } + /** this port's peer (an InPort) invokes this to have "sendToken" or equivalent inserted */ public abstract void sendToken(LoopFactory loopfactory_at_input_dock); /** this port's peer (an InPort) invokes this to have "recvWord" or equivalent inserted */ public abstract void recvWord(LoopFactory loopfactory_at_input_dock); + + public int getTokensToAbsorb() { + if (peer==null) return 0; + return peer.getTokensToAbsorb(); + } } public final class DockInPort extends InPort { final Dock dock; int count; BitVector[] pattern; + public boolean sticky = false; public DockInPort(String name, Dock dock) { this(name, dock, 0); } + public DockInPort(String name, Dock dock, String constant) { + this(name, dock, 0, new BitVector[] { dock.getConstant(constant) }); } public DockInPort(String name, Dock dock, int count) { this(name, dock, count, new BitVector[] { null }); } public DockInPort(String name, Dock dock, int count, BitVector[] pattern) { super(name); @@ -93,26 +112,51 @@ public class Node { } public void recvToken(LoopFactory lf) { lf.recvToken(); } public void sendWord(LoopFactory lf) { lf.sendWord(dock.getDataDestination()); } - public void build(Context ctx) { build(ctx, new LoopFactory(ctx, dock, 1)); } - // number-in-flight is considered a property of the input dock in a pair - public int getInflight() { return 4; } - //public int getInflight() { return 1; } - public int getTokensToAbsorb() { return getInflight(); } + public void build(CodeBag ctx) { build(ctx, ctx.loopFactory(dock, 1)); } + + // this is the input dock's upper limit on how many data items + // may be in flight; the output dock to which it is connected + // also has a say + public int getMaxInFlight() { return CAPACITY; } + + public int getTokensToAbsorb() { return sticky ? 0 : peer==null ? 0 : peer.getNumInitialTokens(); } private boolean peerUsed() { + if (sticky) return false; if (peer==null) return false; for(int i=0; i sendTorpedoesTo) { - return doReset(ctx, phase, dock, peer, ackDestination, sendTorpedoesTo, peerUsed()); + public int reset(CodeBag ctx, int phase, Destination ackDestination) { + return DoneNode.doReset(ctx, phase, dock, this, peer, ackDestination, peerUsed()); } - protected void build(Context ctx, LoopFactory lf) { - int inflight = (count != 0 && count < getInflight()) ? count : getInflight(); + protected void build(CodeBag ctx, LoopFactory lf) { + /* + if (sticky) { + if (count != 0) throw new RuntimeException("expected count==0, but count=="+count); + lf = lf.makeNext(1, true); + lf.recvWord(); + } + */ + if (sticky) { + if (count != 0) throw new RuntimeException("expected count==0, but count=="+count); + lf = lf.makeNext(1, true); + lf.setFlags(FlagFunction.ZERO, FlagFunction.ZERO); + } - if (peer!=null) + if (peer!=null) { + int inflight = (count != 0 && count < peer.getNumInitialTokens()) ? count : peer.getNumInitialTokens(); for(int i=0; i sendTorpedoesTo) { - return doReset(ctx, phase, dock, peer, ackDestination, sendTorpedoesTo, true); + public int reset(CodeBag ctx, int phase, Destination ackDestination) { + return DoneNode.doReset(ctx, phase, dock, this, peer, ackDestination, true); } } @@ -169,93 +213,4 @@ public class Node { return ret; } - // Reset ////////////////////////////////////////////////////////////////////////////// - - int doReset(Context ctx, - int phase, - Dock dock, - Port peer, - Destination ackDestination, - HashSet sendTorpedoesTo, - boolean peerUsed) { - int ret = 0; - if (dock.getShip().getType().equals("Debug")) return ret; - - switch(phase) { - - // Phase 0: torpedo every output dock, put it in - // collecting mode. Cannot combine with phase 1, - // because until output docks are in vacuum mode we - // cannot be sure that the tokens to the input docks - // will eventually succeed. This may cause the - // instructions sent after the tokens to back up into - // the switch fabric. - case 0: { - if (!dock.isInputDock()) { - sendTorpedoesTo.add(dock); - LoopFactory lf = new LoopFactory(ctx, dock, 1); - lf.sendToken(ackDestination); - lf = lf.makeNext(0); - lf.abortLoopIfTorpedoPresent(); - lf.collectWord(); - ret++; - } - break; - } - - // [wait for all output docks to confirm that they've been torpedoed] - // Phase 1: torpedo every input dock (causing them to flush), put it in loopback mode - case 1: { - if (dock.isInputDock()) { - sendTorpedoesTo.add(dock); - LoopFactory lf = new LoopFactory(ctx, dock, 1); - lf.sendToken(ackDestination); - - // FIXME: this won't work right for ports that - // get "shared" by two senders (for example, - // inAddrRead1/2) - - if (peerUsed && peer!=null) { - lf = lf.makeNext(0); - lf.abortLoopIfTorpedoPresent(); - ((OutPort)peer).recvWord(lf); - ((OutPort)peer).sendToken(lf); - } - ret++; - } - break; - } - - // [wait for all input docks to confirm that they've been torpedoed and have flushed] - // Phase 2: torpedo every output dock, have it absorb tokens - case 2: { - if (!dock.isInputDock()) { - sendTorpedoesTo.add(dock); - LoopFactory lf = new LoopFactory(ctx, dock, 1); - if (peer != null) - for(int i=0; i<((InPort)peer).getTokensToAbsorb(); i++) - lf.recvToken(); - lf.sendToken(ackDestination); - ret++; - } - break; - } - - // [wait for all output docks to confirm that they've absorbed enough tokens] - // Phase 3: torpedo every input dock, await confirmation, and we're done - case 3: { - if (dock.isInputDock()) { - if (peerUsed && peer!=null) { - sendTorpedoesTo.add(dock); - } - LoopFactory lf = new LoopFactory(ctx, dock, 1); - lf.sendToken(ackDestination); - ret++; - } - break; - } - } - return ret; - } - } diff --git a/src/edu/berkeley/fleet/dataflow/OnceNode.java b/src/edu/berkeley/fleet/dataflow/OnceNode.java index 1a95654..1d4d2aa 100644 --- a/src/edu/berkeley/fleet/dataflow/OnceNode.java +++ b/src/edu/berkeley/fleet/dataflow/OnceNode.java @@ -8,8 +8,8 @@ public class OnceNode extends Node { public final OutPort out = new OutPort("out") { public void sendToken(LoopFactory lf) { } public void recvWord(LoopFactory lf) { } - public void build(Context ctx) { } - public int reset(Context ctx, int phase, Destination ackDestination, HashSet sendTorpedoesTo) { return 0; } + public void build(CodeBag ctx) { } + public int reset(CodeBag ctx, int phase, Destination ackDestination) { return 0; } public void setPeer(InPort peer) { this.peer = peer; DockInPort pip = ((DockInPort)peer); diff --git a/src/edu/berkeley/fleet/dataflow/ParameterNode.java b/src/edu/berkeley/fleet/dataflow/ParameterNode.java new file mode 100644 index 0000000..365a114 --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/ParameterNode.java @@ -0,0 +1,58 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; + +// derived from OnceNode +public class ParameterNode extends Node { + + private boolean forever; + + public void set(CodeBag ctx, long l) { + set(ctx, new BitVector(ctx.fleet.getWordWidth()).set(l)); + } + public void set(CodeBag ctx, BitVector bv) { + ctx.sendWord(bv, ((DockInPort)out.peer).dock.getDataDestination()); + } + + public final OutPort out = new OutPort("out") { + public void sendToken(LoopFactory lf) { } + public void recvWord(LoopFactory lf) { if (!forever) lf.recvWord(); } + public void build(CodeBag ctx) { } + public int reset(CodeBag ctx, int phase, + Destination ackDestination) { + return 0; } + public void setPeer(InPort peer) { + this.peer = peer; + DockInPort pip = ((DockInPort)peer); + BitVector[] pip_pattern = pip.pattern; + + if (forever) { + pip.sticky = true; + return; + } + + BitVector[] temp = new BitVector[pip_pattern.length * 2]; + int j = 0; + int i = 0; + boolean done = false; + // FIXME: if peer.count is already 1, this gets simpler and different + for(i=0; i= pip_pattern.length) j = 0; + } + pip.pattern = new BitVector[i]; + System.arraycopy(temp, 0, pip.pattern, 0, i); + pip.count = 1; + } + }; + public ParameterNode(DataFlowGraph dfg) { this(dfg, false); } + public ParameterNode(DataFlowGraph dfg, boolean forever) { super(dfg); this.forever = forever; } +} diff --git a/src/edu/berkeley/fleet/dataflow/PunctuatorNode.java b/src/edu/berkeley/fleet/dataflow/PunctuatorNode.java index cee58ae..dab8d4a 100644 --- a/src/edu/berkeley/fleet/dataflow/PunctuatorNode.java +++ b/src/edu/berkeley/fleet/dataflow/PunctuatorNode.java @@ -2,21 +2,38 @@ package edu.berkeley.fleet.dataflow; import java.util.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; +import edu.berkeley.fleet.api.Instruction.Set.FlagFunction; +/** + * Takes an item from "count", passes that many items from "val" to + * "out", and then supplies one instance of "punc" at "out". + */ public class PunctuatorNode extends Node { private final long punc; - private final Ship ship = dfg.pool.allocateShip("Counter"); - private final InPort op = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { - ship.getDock("inOp").getConstant("PASS_C2_V1"), - ship.getDock("inOp").getConstant("PASS_C2_V2") } ); - public final InPort count; - public final OutPort out = new DockOutPort("out", ship.getDock("out")); + private final Ship ship = dfg.pool.allocateShip("Counter"); + private final InPort op = new DockInPort("inOp", ship.getDock("inOp"), "PASS_C2_V1"); public final InPort val = new DockInPort("val", ship.getDock("in1")); + public final OutPort out = new DockOutPort("out", ship.getDock("out")) { + protected void build(CodeBag ctx, LoopFactory lf) { + lf = lf.makeNext(0); + lf.abortLoopIfTorpedoPresent(); + peer.recvToken(lf); + lf.collectWord(); + peer.sendWord(lf); + + lf.literal(punc); + lf.setFlags(FlagFunction.ZERO.add(Predicate.FlagC), FlagFunction.ZERO); + lf.setPredicate(Predicate.FlagA); + peer.recvToken(lf); + peer.sendWord(lf); + lf.setPredicate(null); + } + }; public PunctuatorNode(DataFlowGraph dfg, long punc) { super(dfg); this.punc = punc; - this.count = new DockInPort("in2", ship.getDock("in2"), 0, new BitVector[] { null, bv(1), bv(punc) }); + this.count = new DockInPort("in2", ship.getDock("in2")); } } diff --git a/src/edu/berkeley/fleet/dataflow/RandomNode.java b/src/edu/berkeley/fleet/dataflow/RandomNode.java new file mode 100644 index 0000000..9143cf2 --- /dev/null +++ b/src/edu/berkeley/fleet/dataflow/RandomNode.java @@ -0,0 +1,10 @@ +package edu.berkeley.fleet.dataflow; +import java.util.*; +import edu.berkeley.fleet.loops.*; +import edu.berkeley.fleet.api.*; + +public class RandomNode extends Node { + private final Ship ship = dfg.pool.allocateShip("Random"); + public final OutPort out = new DockOutPort("out", ship.getDock("out")); + public RandomNode(DataFlowGraph dfg) { super(dfg); } +} diff --git a/src/edu/berkeley/fleet/dataflow/RepeatNode.java b/src/edu/berkeley/fleet/dataflow/RepeatNode.java index 2cc54db..f17586a 100644 --- a/src/edu/berkeley/fleet/dataflow/RepeatNode.java +++ b/src/edu/berkeley/fleet/dataflow/RepeatNode.java @@ -3,14 +3,16 @@ import java.util.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; +/** + * Takes a count from "count" and an item from "val" and emits + * count-many copies of val at "out". + */ public class RepeatNode extends Node { private final Ship ship = dfg.pool.allocateShip("Counter"); - private final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"), 0, new BitVector[] { - ship.getDock("inOp").getConstant("REPEAT_C1_V2") }); - - public final InPort count = new DockInPort("count", ship.getDock("in1")); - public final InPort val = new DockInPort("val", ship.getDock("in2")); - public final OutPort out = new DockOutPort("out", ship.getDock("out")); + private final InPort inOp = new DockInPort("inOp", ship.getDock("inOp"), "REPEAT_C1_V2"); + public final InPort count = new DockInPort("count", ship.getDock("in1")); + public final InPort val = new DockInPort("val", ship.getDock("in2")); + public final OutPort out = new DockOutPort("out", ship.getDock("out")); public RepeatNode(DataFlowGraph dfg) { super(dfg); } } diff --git a/src/edu/berkeley/fleet/dataflow/UnPunctuatorNode.java b/src/edu/berkeley/fleet/dataflow/UnPunctuatorNode.java index 038b388..62bf886 100644 --- a/src/edu/berkeley/fleet/dataflow/UnPunctuatorNode.java +++ b/src/edu/berkeley/fleet/dataflow/UnPunctuatorNode.java @@ -2,16 +2,35 @@ package edu.berkeley.fleet.dataflow; import java.util.*; import edu.berkeley.fleet.loops.*; import edu.berkeley.fleet.api.*; +import edu.berkeley.fleet.api.Instruction.Set.FlagFunction; +/** + * Takes an item from the "count" port, then passes/drops through count-1 + * items from "val" to "out" and drops/passes the count-th item. + */ public class UnPunctuatorNode extends Node { private final Ship ship = dfg.pool.allocateShip("Counter"); - private final InPort op = new DockInPort("op", ship.getDock("inOp"), 0, new BitVector[] { - ship.getDock("inOp").getConstant("PASS_C2_V1"), - ship.getDock("inOp").getConstant("DROP_C2_V1") } ); - - public final OutPort out = new DockOutPort("out", ship.getDock("out")); + private final InPort op = new DockInPort("op", ship.getDock("inOp"), "PASS_C2_V1"); public final InPort val = new DockInPort("val", ship.getDock("in1")); - public final InPort count = new DockInPort("count", ship.getDock("in2"), 0, new BitVector[] { null, bv(1) }); + public final InPort count = new DockInPort("count", ship.getDock("in2")); + public final OutPort out = new DockOutPort("out", ship.getDock("out")) { + protected void build(CodeBag ctx, LoopFactory lf) { + lf = lf.makeNext(0); + lf.abortLoopIfTorpedoPresent(); + lf.collectWord(); + lf.setFlags(FlagFunction.ZERO.add(Predicate.FlagC), FlagFunction.ZERO); + lf.setPredicate(passPunctuationInsteadOfValues ? Predicate.FlagA : Predicate.NotFlagA); + lf.abortLoopIfTorpedoPresent(); + peer.recvToken(lf); + peer.sendWord(lf); + lf.setPredicate(null); + } + }; - public UnPunctuatorNode(DataFlowGraph dfg) { super(dfg); } + private boolean passPunctuationInsteadOfValues; + public UnPunctuatorNode(DataFlowGraph dfg) { this(dfg, false); } + public UnPunctuatorNode(DataFlowGraph dfg, boolean passPunctuationInsteadOfValues) { + super(dfg); + this.passPunctuationInsteadOfValues = passPunctuationInsteadOfValues; + } }