handle write completions on status ring

handle write completions on status ring

// Copyright (c) 2013 Quanta Research Cambridge, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;
import StmtFSM::*;
import ClientServer::*;

import PortalMemory::*;
import Dma::*;
import GetPutF::*;

import RingTypes::*;
import RingBuffer::*;
import CopyEngine::*;
import EchoEngine::*;
import NopEngine::*;

interface RingRequest;
   method Action set(Bit#(1) cmd, Bit#(3) regist, Bit#(32) addr);
   method Action get(Bit#(1) cmd, Bit#(3) regist);
   method Action hwenable(Bit#(1) en);
   method Action doCommandIndirect(Bit#(32) addr);
   method Action doCommandImmediate(Bit#(64) data);
endinterface

interface RingIndication;
   method Action setResult(Bit#(1) cmd, Bit#(3) regist, Bit#(32) addr);
   method Action getResult(Bit#(1) cmd, Bit#(3) regist, Bit#(32) addr);
   method Action completion(Bit#(32) command, Bit#(32) tag);
endinterface

module mkRingRequest#(RingIndication indication,
		      DmaReadServer#(64) dma_read_chan,
		      DmaWriteServer#(64) dma_write_chan,
		      DmaReadServer#(64) cmd_read_chan,
		      DmaWriteServer#(64) status_write_chan )(RingRequest);

   ServerF#(Bit#(64), Bit#(64)) copyEngine <- mkCopyEngine(dma_read_chan, dma_write_chan);
   ServerF#(Bit#(64), Bit#(64)) nopEngine <- mkNopEngine();
   ServerF#(Bit#(64), Bit#(64)) echoEngine <- mkEchoEngine();

   RingBuffer cmdRing <- mkRingBuffer;
   RingBuffer statusRing <- mkRingBuffer;
   Reg#(Bool) hwenabled <- mkReg(False);
   Reg#(Bool) cmdBusy <- mkReg(False);
   Reg#(Bit#(64)) cmd <- mkReg(0);
   Reg#(Bit#(4)) ii <- mkReg(0);
   Reg#(Bit#(4)) respCtr <- mkReg(0);
   Reg#(Bit#(4)) dispCtr <- mkReg(0);
   Reg#(Bit#(6)) cmdFetchTag <- mkReg(0);
   Reg#(Bool) cmdFetchEn <- mkReg(False);

   let engineselect = pack(cmd)[63:56];
   function ServerF#(Bit#(64), Bit#(64)) cmdifc();
      if (engineselect == zeroExtend(pack(CmdNOP)))
	 return nopEngine;
      else if (engineselect == zeroExtend(pack(CmdCOPY)))
	 return copyEngine;
      else if (engineselect == zeroExtend(pack(CmdECHO)))
	 return echoEngine;
      else
	 return nopEngine;
   endfunction

   Stmt cmdFetch =
   seq
      $display("cmdFetch FSM TOP");
      while (True)
	 seq
	    if (hwenabled)
	       seq
	       if (cmdRing.bufferfirst != cmdRing.bufferlast)
		  seq
		     $display ("cmdFetch handle=%h address=%d burst=%h tag=%h", cmdRing.memhandle, cmdRing.bufferlast, 8, cmdFetchTag);
		     cmd_read_chan.readReq.put(
			DmaRequest{handle: cmdRing.memhandle,
			   address: cmdRing.bufferlast, burstLen: 8, tag: cmdFetchTag});
		     cmdRing.pop(64);
		     cmdFetchTag <= cmdFetchTag + 1;
		  endseq
	       endseq
	 endseq
   endseq;

   Stmt cmdDispatch =
   seq
      while (True) seq
	 $display("cmdDispatch FSM TOP");
	 action
	    let rv <- cmd_read_chan.readData.get();
	    cmd <= rv.data;
	    $display("cmdDispatch %h", cmd);
	    cmdifc.request.put(rv.data);
	 endaction
	 for (dispCtr <= 1; dispCtr < 8; dispCtr <= dispCtr + 1)
	    action
	       let rv <- cmd_read_chan.readData.get();
	       cmdifc.request.put(rv.data);
	    endaction
      endseq
   endseq;

   Stmt responseArbiter =
   seq
      while(True) seq
	 if (statusRing.notFull() && copyEngine.response.notEmpty())
	    seq
	       $display("responseArbiter copyEngine completion");
	       status_write_chan.writeReq.put(
		  DmaRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  action
		     let rv <- copyEngine.response.get();
		     status_write_chan.writeData.put(DmaData{data: rv, tag: 0});
		  endaction
	       statusRing.push(64);
	    endseq

	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    seq
	       $display("responseArbiter echoEngine completion");
	       status_write_chan.writeReq.put(
		  DmaRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  action
		     let rv <- echoEngine.response.get();
		     status_write_chan.writeData.put(DmaData{data: rv, tag: 0});
		  endaction
	       statusRing.push(64);
	    endseq

      endseq
   endseq;

   rule writeAck(Empty);
      let tag <- status_write_chan.writeDone.get();
      $display("status write done tag=%h", tag);
   endrule

   mkAutoFSM (cmdFetch);
   mkAutoFSM (cmdDispatch);
   mkAutoFSM (responseArbiter);

      // to start a command, doCommand fires off a memory read to the
      // specified address. when it comes back, the doCommandRule will
      // handle it
      method Action doCommandIndirect(Bit#(32) addr);
	 //cmd_read_chan.readReq.put(addr);
      endmethod

      method Action doCommandImmediate(Bit#(64) data);
      	 $display("doCommandImmediate %h", data);
      endmethod

      method Action set(Bit#(1) _cmd, Bit#(3) regist, Bit#(32) addr);
	 if (_cmd == 0)
	    cmdRing.configifc.set(regist, addr);
	 else
	    statusRing.configifc.set(regist, addr);
	 indication.setResult(_cmd, regist, addr);
      endmethod

      method Action get(Bit#(1) _cmd, Bit#(3) regist);
	 if (_cmd == 0)
	    indication.getResult(0, regist,
	       cmdRing.configifc.get(regist));
	 else
	    indication.getResult(0, regist,
	       statusRing.configifc.get(regist));
      endmethod

      method Action hwenable(Bit#(1) en);
	 $display ("hwenable set to %h", en);
	 hwenabled <= en == 1;
      endmethod

endmodule

// Copyright (c) 2013 Quanta Research Cambridge, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;
import StmtFSM::*;
import ClientServer::*;

import PortalMemory::*;
import Dma::*;
import GetPutF::*;

import RingTypes::*;
import RingBuffer::*;
import CopyEngine::*;
import EchoEngine::*;
import NopEngine::*;

interface RingRequest;
   method Action set(Bit#(1) cmd, Bit#(3) regist, Bit#(32) addr);
   method Action get(Bit#(1) cmd, Bit#(3) regist);
   method Action hwenable(Bit#(1) en);
   method Action doCommandIndirect(Bit#(32) addr);
   method Action doCommandImmediate(Bit#(64) data);
endinterface

interface RingIndication;
   method Action setResult(Bit#(1) cmd, Bit#(3) regist, Bit#(32) addr);
   method Action getResult(Bit#(1) cmd, Bit#(3) regist, Bit#(32) addr);
   method Action completion(Bit#(32) command, Bit#(32) tag);
endinterface

module mkRingRequest#(RingIndication indication,
		      DmaReadServer#(64) dma_read_chan,
		      DmaWriteServer#(64) dma_write_chan,
		      DmaReadServer#(64) cmd_read_chan,
		      DmaWriteServer#(64) status_write_chan )(RingRequest);

   ServerF#(Bit#(64), Bit#(64)) copyEngine <- mkCopyEngine(dma_read_chan, dma_write_chan);
   ServerF#(Bit#(64), Bit#(64)) nopEngine <- mkNopEngine();
   ServerF#(Bit#(64), Bit#(64)) echoEngine <- mkEchoEngine();

   RingBuffer cmdRing <- mkRingBuffer;
   RingBuffer statusRing <- mkRingBuffer;
   Reg#(Bool) hwenabled <- mkReg(False);
   Reg#(Bool) cmdBusy <- mkReg(False);
   Reg#(Bit#(64)) cmd <- mkReg(0);
   Reg#(Bit#(4)) ii <- mkReg(0);
   Reg#(Bit#(4)) respCtr <- mkReg(0);
   Reg#(Bit#(4)) dispCtr <- mkReg(0);
   Reg#(Bit#(6)) cmdFetchTag <- mkReg(0);
   Reg#(Bool) cmdFetchEn <- mkReg(False);

   let engineselect = pack(cmd)[63:56];
   function ServerF#(Bit#(64), Bit#(64)) cmdifc();
      if (engineselect == zeroExtend(pack(CmdNOP)))
	 return nopEngine;
      else if (engineselect == zeroExtend(pack(CmdCOPY)))
	 return copyEngine;
      else if (engineselect == zeroExtend(pack(CmdECHO)))
	 return echoEngine;
      else
	 return nopEngine;
   endfunction

   Stmt cmdFetch =
   seq
      $display("cmdFetch FSM TOP");
      while (True)
	 seq
	    if (hwenabled)
	       seq
	       if (cmdRing.bufferfirst != cmdRing.bufferlast)
		  seq
		     $display ("cmdFetch handle=%h address=%d burst=%h tag=%h", cmdRing.memhandle, cmdRing.bufferlast, 8, cmdFetchTag);
		     cmd_read_chan.readReq.put(
			DmaRequest{handle: cmdRing.memhandle,
			   address: cmdRing.bufferlast, burstLen: 8, tag: cmdFetchTag});
		     cmdRing.pop(64);
		     cmdFetchTag <= cmdFetchTag + 1;
		  endseq
	       endseq
	 endseq
   endseq;

   Stmt cmdDispatch =
   seq
      while (True) seq
	 $display("cmdDispatch FSM TOP");
	 action
	    let rv <- cmd_read_chan.readData.get();
	    cmd <= rv.data;
	    $display("cmdDispatch %h", cmd);
	    //cmdifc.request.put(rv.data);
	 endaction
	 for (dispCtr <= 1; dispCtr < 8; dispCtr <= dispCtr + 1)
	    action
	       let rv <- cmd_read_chan.readData.get();
	       //cmdifc.request.put(rv.data);
	    endaction
      endseq
   endseq;

   Stmt cmdCompletion =
   seq
      while(True) seq
	 while(!(hwenabled && statusRing.notFull())) noAction;
      endseq
   endseq;

   Stmt responseArbiter =
   seq
      while(True) seq
	 if (statusRing.notFull() && copyEngine.response.notEmpty())
	    seq
	       $display("responseArbiter copyEngine completion");
	       status_write_chan.writeReq.put(
		  DmaRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  action
		     let rv <- copyEngine.response.get();
		     status_write_chan.writeData.put(DmaData{data: rv, tag: 0});
		  endaction
	       statusRing.push(64);
	    endseq

	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    seq
	       $display("responseArbiter echoEngine completion");
	       status_write_chan.writeReq.put(
		  DmaRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  action
		     let rv <- echoEngine.response.get();
		     status_write_chan.writeData.put(DmaData{data: rv, tag: 0});
		  endaction
	       statusRing.push(64);
	    endseq

      endseq
   endseq;

   mkAutoFSM (cmdFetch);
   mkAutoFSM (cmdDispatch);
   mkAutoFSM (cmdCompletion);
   mkAutoFSM (responseArbiter);

      // to start a command, doCommand fires off a memory read to the
      // specified address. when it comes back, the doCommandRule will
      // handle it
      method Action doCommandIndirect(Bit#(32) addr);
	 //cmd_read_chan.readReq.put(addr);
      endmethod

      method Action doCommandImmediate(Bit#(64) data);
      	 $display("doCommandImmediate %h", data);
      endmethod

      method Action set(Bit#(1) _cmd, Bit#(3) regist, Bit#(32) addr);
	 if (_cmd == 0)
	    cmdRing.configifc.set(regist, addr);
	 else
	    statusRing.configifc.set(regist, addr);
	 indication.setResult(_cmd, regist, addr);
      endmethod

      method Action get(Bit#(1) _cmd, Bit#(3) regist);
	 if (_cmd == 0)
	    indication.getResult(0, regist,
	       cmdRing.configifc.get(regist));
	 else
	    indication.getResult(0, regist,
	       statusRing.configifc.get(regist));
      endmethod

      method Action hwenable(Bit#(1) en);
	 $display ("hwenable set to %h", en);
	 hwenabled <= en == 1;
      endmethod

endmodule


sweep to use radix

sweep to use radix

// Copyright (c) 2014 Quanta Research Cambridge, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Connectable::*;
import SerialFIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
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);
	     to.enq(from.first);
	     from.deq();
	  endaction;
endfunction

module mkNocArbitrate#(Vector#(n, 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);
	 arb.clients[i].request();
      endrule

   rule move;
      if (out.notFull && in[arb.grant_id].notEmpty)
	 action
	    $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 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);
   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;

   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();

   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]));

   // 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

  // interface wiring

   interface PipeIn in = toPipeIn(fifofromhost);
   interface PipeOut out = toPipeOut(fifotohost);

endmodule

// Copyright (c) 2014 Quanta Research Cambridge, Inc.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Connectable::*;
import SerialFIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import Arbiter::*;

typedef struct {
   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);
	     to.enq(from.first);
	     from.deq();
	  endaction;
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);
	 arb.clients[i].request();
      endrule

   rule move;
      if (out.notFull && in[arb.grant_id].notEmpty)
	 action
	    $display("%s id %d from %d", name, id, 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));

   // host Links
   FIFOF#(DataMessage) fifofromhost <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) fifotohost <- mkSizedFIFOF(4);
   SerialFIFO#(DataMessage) host = SerialFIFO{in: toPipeIn(fifotohost),
				    out: toPipeOut(fifofromhost)};

   // buffers for crossbar switch

   FIFOF#(DataMessage) he <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) hw <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) hh <- mkSizedFIFOF(4);

   FIFOF#(DataMessage) ew <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) we <- mkSizedFIFOF(4);

   FIFOF#(DataMessage) eh <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) wh <- mkSizedFIFOF(4);

   // 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);
   interface PipeOut out = toPipeOut(fifotohost);

endmodule


compiles standalone now

compiles standalone now

// Copyright (c) 2014 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/*
 * Implementation of:
 *    simple stack for a type
 *
 * Single cycle push and pop, provided that consecutive pops aren't
 * too far apart
 */

import BRAM::*;

interface StackReg#(numeric type stackSize, type pctype, type argstype, type varstype);
   method Action doreturn();
   method Action docall(pctype jumpto, pctype returnto, argtype args);
   method Action nextpc(pctype jumpto);
   method Bit#(16) setjmp();
   method Action longjump(Bit#(16) where);
   interface Reg#(pctype) pc;
   interface Reg#(argstype) args;
   interface Reg#(varstype) vars;
endinterface

module mkStackReg#(int stackSize, pctype initialpc)(StackReg#(stackSize, pctype, argstype, varstype))
   provisos(Log#(stackSize, addressBits),
      Literal#(pctype),
      Literal#(argstype),
      Literal#(varstype),
      Bits#(pctype, a__),
      Bits#(argstype, b__),
      Bits#(varstype, c__));

   BRAM1Port#(Bit#(addressBits), pctype) pcstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), argstype) argsstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), varstype) varsstack  <- mkBRAM1Server(defaultValue);
   Reg#(pctype) pctop <- mkReg(initialpc);
   Reg#(pctype) pcnext <- mkReg(?);
   Reg#(argstype) argstop <- mkReg(?);
   Reg#(argstype) argsnext <- mkReg(?);
   Reg#(varstype) varstop <- mkReg(?);
   Reg#(varstype) varsnext <- mkReg(?);
   Reg#(Bit#(addressBits)) fp <- mkReg(0);

   rule poppc;
     let v = ?;
      v <- pcstack.portA.response.get();
      pcnext <= v;
   endrule

   rule popargs;
     let v = ?;
      v <- argsstack.portA.response.get();
      argsnext <= v;
   endrule

   rule popvars;
     let v = ?;
      v <- varsstack.portA.response.get();
      varsnext <= v;
   endrule

   method Action docall(pctype jumpto, pctype returnto, argtype args);
      fp <= min(fp+1, maxBound);
      pcstack.portA.request.put(BRAMRequest{write: True,
	 responseOnWrite: False,
	 address: fp, datain: pcnext});
      argsstack.portA.request.put(BRAMRequest{write: True,
	 responseOnWrite: False,
	 address: fp, datain: argsnext});
      varsstack.portA.request.put(BRAMRequest{write: True,
	 responseOnWrite: False,
	 address: fp, datain: varsnext});
      pcnext <= returnto;
      pctop <= jumpto;
      argsnext <= argstop;
      varsnext <= varstop;
   endmethod

   method Action doreturn();
      fp <= max(fp-1, 0);
      pcstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: 0});
      argsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: 0});
      varsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: 0});
      pctop <= pcnext;
      argstop <= argsnext;
      varstop <= varsnext;
   endmethod

   method Action nextpc(pctype jumpto);
      pctop <= jumpto;
   endmethod

   method Bit#(16) setjmp();
      return 0;
   endmethod

   method Action longjump(Bit#(16) where);
   // set fp <= where and pop? something like that
   endmethod

interface pc = pctop;
interface args = argstop;
interface vars = varstop;

endmodule

// Copyright (c) 2014 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/*
 * Implementation of:
 *    simple stack for a type
 *
 * Single cycle push and pop, provided that consecutive pops aren't
 * too far apart
 */

import BRAM::*;

interface StackReg#(numeric type stackSize, type pctype, type argstype, type varstype);
   method Action doreturn();
   method Action docall(pctype jumpto, pctype returnto, argtype args);
   interface Reg#(argstype) args;
   interface Reg#(varstype) vars;
endinterface

module mkStackReg#(int stackSize, pctype initialpc)(StackReg#(stackSize, pctype, argstype, varstype))
   provisos(Log#(stackSize, addressBits),
      Literal#(pctype),
      Literal#(argstype),
      Literal#(varstype),
      Bits#(pctype, a__),
      Bits#(argstype, b__),
      Bits#(varstype, c__));

   BRAM1Port#(Bit#(addressBits), pctype) pcstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), argstype) argsstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), varstype) varsstack  <- mkBRAM1Server(defaultValue);
   Reg#(pctype) pctop <- mkReg(initialpc);
   Reg#(pctype) pcnext <- mkReg(?);
   Reg#(argstype) argstop <- mkReg(?);
   Reg#(argstype) argsnext <- mkReg(?);
   Reg#(varstype) varstop <- mkReg(?);
   Reg#(varstype) varsnext <- mkReg(?);
   Reg#(Bit#(addressBits)) fp <- mkReg(0);

   rule poppc;
     let v = ?;
      v <- pcstack.portA.response.get();
      pcnext <= v;
   endrule

   rule popargs;
     let v = ?;
      v <- argsstack.portA.response.get();
      argsnext <= v;
   endrule

   rule popvars;
     let v = ?;
      v <- varsstack.portA.response.get();
      varsnext <= v;
   endrule

   method Action docall(pctype jumpto, pctype returnto, argtype args);
      fp <= min(fp+1, maxBound);
      pcstack.portA.request.put(BRAMRequest{write: True,
	 responseOnWrite: False,
	 address: fp, datain: pcnext});
      argsstack.portA.request.put(BRAMRequest{write: True,
	 responseOnWrite: False,
	 address: fp, datain: argsnext});
      varsstack.portA.request.put(BRAMRequest{write: True,
	 responseOnWrite: False,
	 address: fp, datain: varsnext});
      pcnext <= returnto;
      pctop <= jumpto;
      argsnext <= argstop;
      varsnext <= varstop;
   endmethod

   method Action doreturn();
      fp <= max(fp-1, 0);
      pcstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: 0});
      argsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: 0});
      varsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: 0});
      pctop <= pcnext;
      argstop <= argsnext;
      varstop <= varsnext;
   endmethod

interface args = argstop;
interface vars = varstop;

endmodule


Removed some guards from SPI device interface

// Copyright (c) 2017 Massachusetts Institute of Technology

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

// For information about SPI, check wikipedia:
//   https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

(* always_ready, always_enabled *)
interface SPIMasterPins;
    // serial clock
    (* prefix = "", result = "sclk" *)
    method Bit#(1) sclk;
    // master-out slave-in
    (* prefix = "", result = "mosi" *)
    method Bit#(1) mosi;
    // master-in slave-out
    (* prefix = "" *)
    method Action miso((* port = "miso" *)Bit#(1) x);
    // active-low chip select
    (* prefix = "", result = "ncs" *)
    method Bit#(1) ncs;
endinterface

interface SPIMaster;
    // configuration
    method Action setSclkDiv(Bit#(16) d);
    method Action setNcs(Bit#(1) new_ncs);
    method Action setCpol(Bit#(1) new_cpol); // idle value of clock
    method Action setCpha(Bit#(1) new_cpha); // which clock transition captures data
                                             // cpha = 0 => odd transitions (1st, 3rd, etc.)
                                             // cpha = 1 => even transitions (2nd, 4th, etc.)
    // status
    method Bool isChipSelectEnabled();
    // data
    method Action put(Bit#(8) x);
    method ActionValue#(Bit#(8)) get();
    // pins
    (* prefix = "" *)
    interface SPIMasterPins pins;
endinterface

module mkSPIMaster(SPIMaster);
    let clock <- exposeCurrentClock();
    // registers for the interface pins
    Reg#(Bit#(1)) sclkReg <- mkReg(0);
    Reg#(Bit#(16)) sclkDiv <- mkReg(1);
    Wire#(Bit#(1)) misoWire <- mkDWire(0);
    Reg#(Bit#(1)) misoReg <- mkReg(0);
    Reg#(Bit#(1)) ncsReg <- mkReg(1);
    // MSB gets shifted out
    Reg#(Bit#(8)) shiftReg <- mkReg(0);

    // SPI configuration
    Reg#(Bit#(1)) cpol <- mkReg(0);
    Reg#(Bit#(1)) cpha <- mkReg(0);

    // 17 ticks per SPI cycle, between each tick is a clock transition
    Reg#(Bool) running <- mkReg(False);
    Reg#(Bool) resultReady <- mkReg(False);
    Reg#(Bit#(5)) tickCount <- mkReg(0);
    // sclkReg determines how many mini ticks make up a tick
    Reg#(Bit#(16)) miniTickCount <- mkReg(0);

    (* fire_when_enabled, no_implicit_conditions *)
    rule run(running);
        let nextMiniTickCount = miniTickCount + 1;
        if ((nextMiniTickCount == sclkDiv) || sclkDiv == 0) begin
            miniTickCount <= 0;
            if (tickCount == 16) begin
                // done
                running <= False;
                resultReady <= True;
                tickCount <= 0;
            end else begin
                // tick clock
                sclkReg <= ~sclkReg;
                // increment tickCount
                tickCount <= tickCount + 1;
                // either capture input or shift output
                if (tickCount[0] == cpha) begin
                    // capture input
                    misoReg <= misoWire;
                end else begin
                    // shift output
                    if (tickCount == 0) begin
                        // but never on the first tick
                    end else begin
                        shiftReg <= {shiftReg[6:0], misoReg};
                    end
                end
            end
        end else begin
            miniTickCount <= nextMiniTickCount;
        end
    endrule

    method Action setSclkDiv(Bit#(16) d);
        sclkDiv <= d;
    endmethod
    method Action setNcs(Bit#(1) new_ncs);
        ncsReg <= new_ncs;
    endmethod
    method Action setCpol(Bit#(1) new_cpol);
        cpol <= new_cpol;
    endmethod
    method Action setCpha(Bit#(1) new_cpha);
        cpha <= new_cpha;
    endmethod

    method Bool isChipSelectEnabled();
        return ncsReg == 0;
    endmethod

    method Action put(Bit#(8) x) if (!running);
        resultReady <= False;
        running <= True;
        tickCount <= 0;
        miniTickCount <= 0;
        shiftReg <= x;
    endmethod
    method ActionValue#(Bit#(8)) get() if (resultReady);
        resultReady <= False;
        return shiftReg;
    endmethod

    interface SPIMasterPins pins;
        method Bit#(1) sclk;
            return sclkReg;
        endmethod
        method Bit#(1) mosi;
            return running ? shiftReg[7] : 1;
        endmethod
        method Action miso(Bit#(1) x);
            misoWire <= x;
        endmethod
        method Bit#(1) ncs;
            return ncsReg;
        endmethod
    endinterface
endmodule

// Copyright (c) 2017 Massachusetts Institute of Technology

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

// For information about SPI, check wikipedia:
//   https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

(* always_ready, always_enabled *)
interface SPIMasterPins;
    // serial clock
    (* prefix = "", result = "sclk" *)
    method Bit#(1) sclk;
    // master-out slave-in
    (* prefix = "", result = "mosi" *)
    method Bit#(1) mosi;
    // master-in slave-out
    (* prefix = "" *)
    method Action miso((* port = "miso" *)Bit#(1) x);
    // active-low chip select
    (* prefix = "", result = "ncs" *)
    method Bit#(1) ncs;
endinterface

interface SPIMaster;
    // configuration
    method Action setSclkDiv(Bit#(16) d);
    method Action setNcs(Bit#(1) new_ncs);
    method Action setCpol(Bit#(1) new_cpol); // idle value of clock
    method Action setCpha(Bit#(1) new_cpha); // which clock transition captures data
                                             // cpha = 0 => odd transitions (1st, 3rd, etc.)
                                             // cpha = 1 => even transitions (2nd, 4th, etc.)
    // status
    method Bool isChipSelectEnabled();
    // data
    method Action put(Bit#(8) x);
    method ActionValue#(Bit#(8)) get();
    // pins
    (* prefix = "" *)
    interface SPIMasterPins pins;
endinterface

module mkSPIMaster(SPIMaster);
    let clock <- exposeCurrentClock();
    // registers for the interface pins
    Reg#(Bit#(1)) sclkReg <- mkReg(0);
    Reg#(Bit#(16)) sclkDiv <- mkReg(1);
    Wire#(Bit#(1)) misoWire <- mkDWire(0);
    Reg#(Bit#(1)) misoReg <- mkReg(0);
    Reg#(Bit#(1)) ncsReg <- mkReg(1);
    // MSB gets shifted out
    Reg#(Bit#(8)) shiftReg <- mkReg(0);

    // SPI configuration
    Reg#(Bit#(1)) cpol <- mkReg(0);
    Reg#(Bit#(1)) cpha <- mkReg(0);

    // 17 ticks per SPI cycle, between each tick is a clock transition
    Reg#(Bool) running <- mkReg(False);
    Reg#(Bool) resultReady <- mkReg(False);
    Reg#(Bit#(5)) tickCount <- mkReg(0);
    // sclkReg determines how many mini ticks make up a tick
    Reg#(Bit#(16)) miniTickCount <- mkReg(0);

    (* fire_when_enabled, no_implicit_conditions *)
    rule run(running);
        let nextMiniTickCount = miniTickCount + 1;
        if ((nextMiniTickCount == sclkDiv) || sclkDiv == 0) begin
            miniTickCount <= 0;
            if (tickCount == 16) begin
                // done
                running <= False;
                resultReady <= True;
                tickCount <= 0;
            end else begin
                // tick clock
                sclkReg <= ~sclkReg;
                // increment tickCount
                tickCount <= tickCount + 1;
                // either capture input or shift output
                if (tickCount[0] == cpha) begin
                    // capture input
                    misoReg <= misoWire;
                end else begin
                    // shift output
                    if (tickCount == 0) begin
                        // but never on the first tick
                    end else begin
                        shiftReg <= {shiftReg[6:0], misoReg};
                    end
                end
            end
        end else begin
            miniTickCount <= nextMiniTickCount;
        end
    endrule

    method Action setSclkDiv(Bit#(16) d) if (ncsReg == 1);
        sclkDiv <= d;
    endmethod
    method Action setNcs(Bit#(1) new_ncs);
        ncsReg <= new_ncs;
    endmethod
    method Action setCpol(Bit#(1) new_cpol) if (ncsReg == 1);
        cpol <= new_cpol;
    endmethod
    method Action setCpha(Bit#(1) new_cpha) if (ncsReg == 1);
        cpha <= new_cpha;
    endmethod

    method Bool isChipSelectEnabled();
        return ncsReg == 0;
    endmethod

    method Action put(Bit#(8) x) if (!running);
        resultReady <= False;
        running <= True;
        tickCount <= 0;
        miniTickCount <= 0;
        shiftReg <= x;
    endmethod
    method ActionValue#(Bit#(8)) get() if (resultReady);
        resultReady <= False;
        return shiftReg;
    endmethod

    interface SPIMasterPins pins;
        method Bit#(1) sclk;
            return sclkReg;
        endmethod
        method Bit#(1) mosi;
            return running ? shiftReg[7] : 1;
        endmethod
        method Action miso(Bit#(1) x);
            misoWire <= x;
        endmethod
        method Bit#(1) ncs;
            return ncsReg;
        endmethod
    endinterface
endmodule