anchor.diff:     rule move;
         if (out.notFull && in[arb.grant_id].notEmpty)
   	 action
  -	    $display("%s id %d from %d", name, id, arb.grant_id);
  +	    $display("%s id %d,%d from %d", name, id[0], id[1], arb.grant_id);
   	    out.enq(in[arb.grant_id].first());
   	    in[arb.grant_id].deq();
   	 endaction
      endrule
   endmodule
   
  -module mkNocNode#(Bit#(4) id, 
  -		  SerialFIFO#(DataMessage) west,
  -		  SerialFIFO#(DataMessage) east)(SerialFIFO#(DataMessage));
  +module mkDistribute#(Vector(n, Bit#(4)) id, String name, PipeOut#(a) in, Vector#(n, PipeIn#(a)) out)(Empty);
  +   rule move;
  +      $display("distrib %s[%d,%d] to [%d,%d] v %x",
  +	 name, id[0], id[1], in.first.address[0], in.first.address[1],
  +	 in.first.payload);
  +      if (in.address[0] < id[0]) 
  +	 move(in.first, out[0]);
  +      else if (in.address[0] > id[0]) 
  +	 move(in.first, out[1]);
  +      else /* in.address[0] == id[0] */
  +	 begin
  +	    if (in.address[1] < id[1]) 
  +	       move (in.first, out[2]);
  +	    else if (in.address[1] > id[1]) 
  +	       move (in.first, out[3]);
  +	    else
  +	       move(in.first, out[4]);
  +	 end
  +      end
   
  +   endrule
  +endmodule
  +
  +// This makes a FIFO which throws away data and is never ready to read
  +module mkDiscard(FIFOF#(DataMessage));
  +   interface
  +      method Action enq(DataMessage d);
  +      endmethod
  +      method Bool notFull;
  +         return True;
  +      endmethod
  +      method DataMessage first() = ?;
  +      method Bool notEmpty();
  +         return False;
  +      endmethod
  +      method Action deq;
  +	 if (False) noAction;
  +      endmethod
  +endmodule
  +
  +module mkNocNode#(Vector(dim, int) id, 
  +		  Vector(dim, PipeIn#(DataMessage)) upIn,
  +		  Vector(dim, PipeOut#(DataMessage)) upOut,
  +		  Vector(dim, PipeIn#(DataMessage)) downIn,
  +		  Vector(dim, PipeOut#(DataMessage)) downOut)
  +   (SerialFIFO#(DataMessage));
  +   Bit#(4) radix = (ValueOf(dim) * 2) + 1;
  +   
      // host Links
      FIFOF#(DataMessage) fifofromhost <- mkSizedFIFOF(4);
      FIFOF#(DataMessage) fifotohost <- mkSizedFIFOF(4);
  -   SerialFIFO#(DataMessage) host = SerialFIFO{in: toPipeIn(fifotohost),
  -				    out: toPipeOut(fifofromhost)}; 
  +   PipeIn#(DataMessage) tohost = toPipeIn(fifotohost);
  +   PipeOut#(DataMessage) fromhost = toPipeOut(fifofromhost); 
     
  +   // sources
  +   Vector#(radix, PipeOut#(DataMessage)) linkin;
  +   Vector#(radix, PipeOut#(DataMessage)) linkout;
  +   for (Bit#(4) x = 0; x < ValueOf(dim); x = x + 1)
  +      begin
  +	 linkin[(2*x) + 0] = upIn;
  +	 linkin[(2*x) + 1] = downIn;
  +	 linkout[(2*x) + 0] = upOut;
  +	 linkout[(2*x) + 1] = downOut;
  +      end
  +   linkin[radix - 1] = fromhost;
  +   linkout[radix - 1] = tohost;
  +   
      // buffers for crossbar switch
  +   Vector#(radix, Vector#(radix, FIFOF#(DataMessage))) xp;
      
  -   FIFOF#(DataMessage) he <- mkSizedFIFOF(4);
  -   FIFOF#(DataMessage) hw <- mkSizedFIFOF(4);
  -   FIFOF#(DataMessage) hh <- mkSizedFIFOF(4);
  +   for (Bit#(4) x = 0; x < radix; x = x + 1)
  +      for (Bit#(4) y = 0; y < radix; y = y + 1)
  +	 if (x != y) xp[x][y] <- mkSizedFIFOF(4);
  +
  +   for (Bit#(4) x = 0; x < (radix - 1); x = x + 1)
  +      xp[x][x] <- mkDiscard();
      
  -   FIFOF#(DataMessage) ew <- mkSizedFIFOF(4);
  -   FIFOF#(DataMessage) we <- mkSizedFIFOF(4);
  +   xp[radix - 1][radix - 1] < mkSizedFIFOF(4);
  +   
  +   
  +   // create distributors
  +   
  +   for (Bit#(4) x = 0; x < radix; x = x + 1)
  +      mkdistributor("n", id, linkin[x], map(toPipeOut, xp[x]));
   
  -   FIFOF#(DataMessage) eh <- mkSizedFIFOF(4);
  -   FIFOF#(DataMessage) wh <- mkSizedFIFOF(4);
  +   // create arbiters
  +   for (Bit#(4) y = 0; y < radix; y = y + 1)
  +      begin
  +	 Vector(radix, PipeOut#(DataMessage)) o = newVector;
  +	 for (Bit#(4) x = 0; x < radix; x = x + 1)
  +	    o[x] = xp[x][y];
  +	 mkNocArbitrate(id, o, linkout[y]);
  +      end
   
  -   // collate for inputs to host, east, west
  -   Vector#(3,PipeOut#(DataMessage)) vToHost = newVector;
  -   Vector#(2,PipeOut#(DataMessage)) vToEast = newVector;
  -   Vector#(2,PipeOut#(DataMessage)) vToWest = newVector;
  -   
  -   vToHost[0] = toPipeOut(hh);
  -   vToHost[1] = toPipeOut(eh);
  -   vToHost[2] = toPipeOut(wh);
  -   
  -   vToEast[0] = toPipeOut(he);
  -   vToEast[1] = toPipeOut(we);
  -   
  -   vToWest[0] = toPipeOut(hw);
  -   vToWest[1] = toPipeOut(ew);
  -   
  -   mkNocArbitrate(id, "toHost", vToHost, host.in);
  -   mkNocArbitrate(id, "toEast", vToEast, east.in);
  -   mkNocArbitrate(id, "toWest", vToWest, west.in);
  -   
  -   // sort host messages to proper queue
  -   
  -   rule fromhost (host.out.notEmpty);
  -      if (host.out.first.address < id)
  -	 begin
  -	    $display("id %d host to west", id);
  -	    move(host.out, toPipeIn(hw));
  -	 end
  -      else if (host.out.first.address == id)
  -	 begin
  -	    $display("id %d host to host", id);
  -	    move(host.out, toPipeIn(hh));
  -	 end
  -      else
  -	 begin
  -	    $display("id %d host to east", id);
  -	    move(host.out, toPipeIn(he));
  -	 end
  -   endrule
  -   
  -   // Handle arriving messages from East
  -   
  -   rule fromeast (east.out.notEmpty);
  -      if (east.out.first.address == id)
  -	 begin
  -	    $display("fromeast %d to host v %x", id, east.out.first);
  -	    move(east.out, toPipeIn(eh));
  -	 end
  -      else
  -	 begin
  -	    $display("fromeast %d to west v %x", id, east.out.first);
  -	    move(east.out, toPipeIn(ew));
  -	 end
  -   endrule
  -   
  -   // Handle arriving messages from West
  -
  -   rule fromwest (west.out.notEmpty);
  -      if (west.out.first.address == id)
  -	 begin
  -	    $display("fromwest %d to host v %x", id, west.out.first);
  -	    move(west.out, toPipeIn(wh));
  -	 end
  -      else
  -	 begin
  -	    $display("fromwest %d  to east v %x", id, west.out.first);
  -	    move(west.out, toPipeIn(we));
  -	 end
  -      endrule
  -      
     // interface wiring
   
      interface PipeIn in = toPipeIn(fifofromhost);
  
positive.code: endfunction
  
  
  module mkNocArbitrate#(Bit#(4) id, String name, Vector#(n, PipeOut#(a)) in, PipeIn#(a) out)(Empty);
     Arbiter_IFC#(n) arb <- mkArbiter(False);   
     for (Integer i = 0; i < valueOf(n); i = i + 1)
        rule send_request (out.notFull && in[i].notEmpty);
  
negative.code: import Arbiter::*;
  
  typedef struct {
     Vector(2, Bit#(4)) address;
     Bit#(32) payload;
     } DataMessage deriving(Bits);
  
  function Action move(PipeOut#(DataMessage) from, PipeIn#(DataMessage) to);
     return action
  	     $display("move %x", from.first);
  