increase trace buffer size

increase trace buffer size

// Copyright (c) 2016 Connectal Project

// 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 BRAM::*;
import BuildVector::*;
import Clocks::*;
import Connectable::*;
import FIFOF::*;
import GetPut::*;
import Probe::*;
import Vector::*;

import AddressGenerator::*;
import AxiBits::*;
import ConnectalClocks::*;
import ConnectalConfig::*;
import DefaultValue::*;
import HostInterface::*;
import MemReadEngine::*;
import MemTypes::*;
import PhysMemSlaveFromBram::*;
import Pipe::*;
import TraceMemClient::*;
import XilinxCells::*;
import MPEngine::*;

import AxiPcieRootPort::*;
import NvmeIfc::*;
import NvmePins::*;

`ifndef TOP_SOURCES_PORTAL_CLOCK
import ConnectalBramFifo::*;
`else
import BRAMFIFO::*;
module mkDualClockBramFIFOF#(Clock clock1, Reset reset1, Clock clock2, Reset reset2)(FIFOF#(a))
   provisos (Bits#(a, asz), Add#(1, a__, asz));
   FIFOF#(a) fifo <- mkSizedBRAMFIFOF(512, clocked_by clock1, reset_by reset1);
   return fifo;
endmodule
`endif

interface Nvme;
   interface NvmeRequest request;
   interface MemServerPortalRequest bramRequest;
   interface NvmeTrace trace;
   interface NvmePins pins;
   interface Vector#(2, MemReadClient#(DataBusWidth)) dmaReadClient;
   interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaWriteClient;
`ifdef TOP_SOURCES_PORTAL_CLOCK
   interface Clock portalClockSource;
`endif
endinterface

module mkNvme#(NvmeIndication ind, NvmeTrace trace, MemServerPortalIndication bramIndication)(Nvme);
   let clock <- exposeCurrentClock;
   let reset <- exposeCurrentReset;
   let refclk_p <- mkB2C1();
   let refclk_n <- mkB2C1();
   let pcie_clk_100mhz_buf <- mkClockIBUFDS_GTE2(
`ifdef ClockDefaultParam
       defaultValue,
`endif
      True, refclk_p.c, refclk_n.c);
`ifndef TOP_SOURCES_PORTAL_CLOCK
   let axiClockB2C    <- mkB2C1();
   let axiCtlClockB2C <- mkB2C1();
   let axiClock = axiClockB2C.c;
   let axiCtlClock = axiCtlClockB2C.c;
   let axiReset <- mkSyncReset(10, reset, axiClock);
   let axiCtlReset <- mkSyncReset(10, reset, axiCtlClock);
`else
   let axiClock = clock;
   let axiCtlClock = clock;
   let axiReset = reset;
   let axiCtlReset = reset;
`endif

   let axiRootPort <- mkAPRP(pcie_clk_100mhz_buf, reset, axiClock, axiReset, axiCtlClock, axiCtlReset);
`ifndef TOP_SOURCES_PORTAL_CLOCK
   let axiClockC2B <- mkC2B(axiRootPort.axi.aclk_out);
   let axiCtlClockC2B <- mkC2B(axiRootPort.axi.ctl_aclk_out);
   rule rl_connect_clocks;
      axiClockB2C.inputclock(axiClockC2B.o);
      axiCtlClockB2C.inputclock(axiClockC2B.o);
   endrule
`endif

   FIFOF#(Bit#(32)) dfifoCtl <- mkFIFOF();
   Axi4SlaveBits#(32,DataBusWidth,4,Empty) axiRootPortSlave    = toAxi4SlaveBits(axiRootPort.s_axi);
   Axi4SlaveLiteBits#(32,32)     axiRootPortSlaveCtl = toAxi4SlaveBits(axiRootPort.s_axi_ctl);
   PhysMemSlave#(32,DataBusWidth)          axiRootPortMemSlave    <- mkPhysMemSlave(axiRootPortSlave, clocked_by axiClock, reset_by axiReset);
   PhysMemSlave#(32,32)          axiRootPortMemSlaveCtl <- mkPhysMemSlave(axiRootPortSlaveCtl, clocked_by axiCtlClock, reset_by axiCtlReset);

   FIFOF#(PhysMemRequest#(32,DataBusWidth)) araddrFifo <- mkFIFOF();
   FIFOF#(PhysMemRequest#(32,DataBusWidth)) awaddrFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           rdataFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           wdataFifo <- mkFIFOF();
   FIFOF#(Bit#(6))                           doneFifo <- mkFIFOF();

   let araddrCnx <- mkConnection(toGet(araddrFifo), axiRootPortMemSlave.read_server.readReq);
   let awaddrCnx <- mkConnection(toGet(awaddrFifo), axiRootPortMemSlave.write_server.writeReq);
   let rdataCnx  <- mkConnection(axiRootPortMemSlave.read_server.readData, toPut(rdataFifo));
   let wdataCnx  <- mkConnection(toGet(wdataFifo), axiRootPortMemSlave.write_server.writeData);
   let doneCnx   <- mkConnection(axiRootPortMemSlave.write_server.writeDone, toPut(doneFifo));

   rule rl_rdata;
      let rdata <- toGet(rdataFifo).get();
      ind.readDone(rdata.data);
   endrule

   rule rl_writeDone;
      let tag <- toGet(doneFifo).get();
      ind.writeDone();
   endrule

   FIFOF#(PhysMemRequest#(32,32)) araddrFifoCtl <- mkFIFOF();
   FIFOF#(PhysMemRequest#(32,32)) awaddrFifoCtl <- mkFIFOF();
   FIFOF#(MemData#(32))           rdataFifoCtl <- mkFIFOF();
   FIFOF#(MemData#(32))           wdataFifoCtl <- mkFIFOF();
   FIFOF#(Bit#(6))                doneFifoCtl <- mkFIFOF();

   let araddrCtlCnx <- mkConnection(toGet(araddrFifoCtl), axiRootPortMemSlaveCtl.read_server.readReq);
   let awaddrCtlCnx <- mkConnection(toGet(awaddrFifoCtl), axiRootPortMemSlaveCtl.write_server.writeReq);
   let rdataCtlCnx  <- mkConnection(axiRootPortMemSlaveCtl.read_server.readData, toPut(rdataFifoCtl));
   let wdataCtlCnx  <- mkConnection(toGet(wdataFifoCtl), axiRootPortMemSlaveCtl.write_server.writeData);
   let doneCtlCnx   <- mkConnection(axiRootPortMemSlaveCtl.write_server.writeDone, toPut(doneFifoCtl));

   rule rl_rdata_ctl;
      let rdata <- toGet(rdataFifoCtl).get();
      ind.readDone(extend(rdata.data));
   endrule

   rule rl_writeDone_ctl;
      let tag <- toGet(doneFifoCtl).get();
      ind.writeDone();
   endrule

   Axi4MasterBits#(32,DataBusWidth,MemTagSize,Empty) m_axi_mm = toAxi4MasterBits(axiRootPort.m_axi);
   let getObjId = (interface GetObjId;
		   method SGLId objId(Bit#(32) addr); return extend(addr[31:24]); endmethod
		   method Bit#(MemOffsetSize) addr(Bit#(32) axiAddr); return extend(axiAddr[23:0]); endmethod
		   endinterface);
   let memReadClient  <- mkMemReadClient(getObjId, m_axi_mm);
   let memWriteClient <- mkMemWriteClient(getObjId, m_axi_mm);

   FIFOF#(Tuple4#(DmaChannel,Bool,MemRequest,Bit#(32))) traceFifo <- mkSizedBRAMFIFOF(128);
   PipeIn#(Tuple4#(DmaChannel,Bool,MemRequest,Bit#(32))) tracePipe = toPipeIn(traceFifo);
   FIFOF#(Tuple4#(DmaChannel,Bool,MemData#(DataBusWidth),Bit#(32))) traceDataFifo <- mkSizedBRAMFIFOF(2048);
   PipeIn#(Tuple4#(DmaChannel,Bool,MemData#(DataBusWidth),Bit#(32))) traceDataPipe = toPipeIn(traceDataFifo);
   FIFOF#(Tuple2#(DmaChannel,Bit#(32)))                              traceDoneFifo <- mkSizedBRAMFIFOF(128);
   PipeIn#(Tuple2#(DmaChannel,Bit#(32)))                             traceDonePipe = toPipeIn(traceDoneFifo);

   rule rl_trace1;
      match { .chan, .write, .req, .timestamp } <- toGet(traceFifo).get();
      trace.traceDmaRequest(chan, write, truncate(req.sglId), extend(req.offset), extend(req.burstLen), extend(req.tag), timestamp);
   endrule
   rule rl_trace_data;
      match { .chan, .write, .md, .timestamp } <- toGet(traceDataFifo).get();
      trace.traceDmaData(chan, write, md.data, md.last, extend(md.tag), timestamp);
   endrule
   rule rl_trace_done;
      match { .chan, .timestamp } <- toGet(traceDoneFifo).get();
      trace.traceDmaDone(chan, 0, timestamp);
   endrule

   let traceReadClient <- mkTraceReadClient(tracePipe,traceDataPipe,DMA_TX,memReadClient);
   let traceWriteClient <- mkTraceWriteClient(tracePipe,traceDataPipe,traceDonePipe,DMA_RX,memWriteClient);
   let traceClient = (interface MemClient#(DataBusWidth);
			 interface readClient = traceReadClient;
			 interface writeClient = traceWriteClient;
		      endinterface);

   let splitter <- mkSplitMemServer();
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency = 2;
   bramConfig.memorySize = 1024;
   BRAM2Port#(Bit#(32),Bit#(DataBusWidth)) bram <- mkBRAM2Server(bramConfig);
   MemServer#(DataBusWidth)            bramMemA <- mkMemServerFromBram(bram.portA);
   PhysMemSlave#(32,DataBusWidth)      bramMemB <- mkPhysMemSlaveFromBram(bram.portB);
   MemServerPortal          bramMemServerPortal <- mkPhysMemSlavePortal(bramMemB,bramIndication);

   MemReadEngine#(DataBusWidth,DataBusWidth,2,1) re <- mkMemReadEngine();
   MPEngine#(DataBusWidth,DataBusWidth)    mpEngine <- mkMPStreamEngine(splitter.data, re.readServers[0]);

   let traceMemCnx <- mkConnection(traceClient, splitter.server);
   let bramMemCnx  <- mkConnection(splitter.bramClient, bramMemA);
   // rule rl_data;
   //    let md <- toGet(splitter.data).get();
   //    trace.traceData(md.data, md.last, extend(md.tag));
   // endrule
   rule rl_locdone;
      let loc <- toGet(mpEngine.locdone).get();
      ind.strstrLoc(pack(loc));
   endrule

   interface MemServerPortalRequest bramRequest = bramMemServerPortal.request;
   interface NvmeRequest request;

      method Action status();
        ind.status(axiRootPort.mmcm.lock());
      endmethod

      method Action read32(Bit#(32) addr);
	 araddrFifo.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
      endmethod
      method Action write32(Bit#(32) addr, Bit#(32) value);
	 awaddrFifo.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
	 wdataFifo.enq(MemData {data: extend(value), tag: 0, last: True});
      endmethod
      method Action read(Bit#(32) addr);
	 araddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
      endmethod
      method Action write(Bit#(32) addr, Bit#(DataBusWidth) value);
	 awaddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
	 wdataFifo.enq(MemData {data: value, tag: 0, last: True});
      endmethod

      method Action readCtl(Bit#(32) addr);
	 araddrFifoCtl.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
      endmethod
      method Action writeCtl(Bit#(32) addr, Bit#(DataBusWidth) value);
	 awaddrFifoCtl.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
	 wdataFifoCtl.enq(MemData {data: truncate(value), tag: 0, last: True});
      endmethod
      method Action setSearchString(Bit#(32) needleSglId, Bit#(32) mpNextSglId, Bit#(32) needleLen);
	 mpEngine.setsearch.enq(tuple3(needleSglId, mpNextSglId, needleLen));
      endmethod
      method Action startSearch(Bit#(32) haystackLen);
	 mpEngine.setsearch.enq(tuple3(/* unused */maxBound, haystackLen, /* unused */0));
      endmethod
   endinterface
   interface Clock portalClockSource = axiRootPort.axi.aclk_out;
   interface NvmePins pins;
      interface deleteme_unused_clock = clock;
      interface pcie_sys_reset_n = reset;
      interface pcie = axiRootPort.pci;
      method Action pcie_refclk(Bit#(1) p, Bit#(1) n);
         refclk_p.inputclock(p);
         refclk_n.inputclock(n);
      endmethod
   endinterface
   interface Vector dmaReadClient = vec(splitter.busClient.readClient, re.dmaClient);
   interface Vector dmaWriteClient = vec(splitter.busClient.writeClient);
endmodule

instance ToAxi4SlaveBits#(Axi4SlaveBits#(32,DataBusWidth,4,Empty), AprpS_axi);
   function Axi4SlaveBits#(32,DataBusWidth,4,Empty) toAxi4SlaveBits(AprpS_axi s);
      return (interface Axi4SlaveBits#(32,DataBusWidth,4,Empty);
	 method araddr = compose(s.araddr, extend);
	 method arburst = s.arburst;
	 //method arcache = s.arcache;
	 method arid = s.arid;
	 method arlen = s.arlen;
	 //method arlock = s.arlock;
	 //method arprot = s.arprot;
	 //method arqos = s.arqos;
	 method arready = s.arready;
	 method arsize = s.arsize;
	 method arvalid = s.arvalid;

	 method awaddr = compose(s.awaddr, extend);
	 method awburst = s.awburst;
	 //method awcache = s.awcache;
	 method awid = s.awid;
	 method awlen = s.awlen;
	 //method awlock = s.awlock;
	 //method awprot = s.awprot;
	 //method awqos = s.awqos;
	 method awready = s.awready;
	 method awsize = s.awsize;
	 method awvalid = s.awvalid;

	 method bid = s.bid;
	 method bready = s.bready;
	 method bresp = s.bresp;
	 method bvalid = s.bvalid;
	 method rdata = s.rdata;
	 method rid = s.rid;
	 method rlast = s.rlast;
	 method rready = s.rready;
	 method rresp = s.rresp;
	 method rvalid = s.rvalid;
	 method wdata = s.wdata;
	 method wlast = s.wlast;
	 method wready = s.wready;
	 method wvalid = s.wvalid;
	 method wstrb = s.wstrb;
	 endinterface);
   endfunction
endinstance

instance ToAxi4SlaveBits#(Axi4SlaveLiteBits#(32,32), AprpS_axi_ctl);
   function Axi4SlaveLiteBits#(32,32) toAxi4SlaveBits(AprpS_axi_ctl s);
      return (interface Axi4SlaveLiteBits#(32,32);
	 method araddr = compose(s.araddr, extend);
	 method arready = s.arready;
	 method arvalid = s.arvalid;

	 method awaddr = compose(s.awaddr, extend);
	 method awready = s.awready;
	 method awvalid = s.awvalid;

	 method bready = s.bready;
	 method bresp = s.bresp;
	 method bvalid = s.bvalid;
	 method rdata = s.rdata;
	 method rready = s.rready;
	 method rresp = s.rresp;
	 method rvalid = s.rvalid;
	 method wdata = s.wdata;
	 method wready = s.wready;
	 method Action      wvalid(Bit#(1) v);
	    s.wvalid(v);
	    s.wstrb(pack(replicate(v)));
	 endmethod
	 endinterface);
   endfunction
endinstance

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AprpM_axi);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AprpM_axi m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
	   method araddr = m.araddr;
	   method arburst = m.arburst;
	   method arcache = m.arcache;
	   method arlen = m.arlen;
	   method arlock = extend(m.arlock);
	   method arready = m.arready;
	   method arsize = m.arsize;
	   method arvalid = m.arvalid;
	   method Bit#(1) aresetn(); return 1; endmethod
	   method Bit#(tagWidth)     arid(); return 0; endmethod
	   method arprot = m.arprot;
	   method arqos = 0;
	   method awaddr = m.awaddr;
	   method awburst = m.awburst;
	   method awcache = m.awcache;
	   method Bit#(tagWidth)     awid(); return 0; endmethod
	   method awlen = m.awlen;
	   method awlock = extend(m.awlock);
	   method awprot = m.awprot;
	   method awready = m.awready;
	   method Bit#(4)     awqos(); return 0; endmethod
	   method awsize = m.awsize;
	   method awvalid = m.awvalid;
	   method Action      bid(Bit#(tagWidth) v); endmethod
	   method bready = m.bready;
	   method bresp = m.bresp;
	   method bvalid = m.bvalid;
	   method rdata = m.rdata;
	   method Action      rid(Bit#(tagWidth) v); endmethod
	   method rlast = m.rlast;
	   method rready = m.rready;
	   method rresp = m.rresp;
	   method rvalid = m.rvalid;
	   method wdata = m.wdata;
	   method Bit#(tagWidth)     wid(); return 0; endmethod
	   method wlast = m.wlast;
	   method wready = m.wready;
	   method wstrb = m.wstrb;
	   method wvalid = m.wvalid;
	 interface extra = ?;
	 endinterface);
   endfunction
endinstance

interface SplitMemServer;
   interface MemServer#(DataBusWidth) server;
   interface MemClient#(DataBusWidth) busClient;
   interface MemClient#(DataBusWidth) bramClient;
   interface PipeOut#(MemData#(DataBusWidth)) data;
endinterface

module mkSplitMemServer(SplitMemServer);
   let readReqFifo   <- mkFIFOF();
   let readDataFifo  <- mkFIFOF();
   let writeReqFifo  <- mkFIFOF();
   let writeDataFifo <- mkFIFOF();
   let writeDoneFifo <- mkFIFOF();

   let busReadReqFifo   <- mkFIFOF();
   let busReadDataFifo  <- mkSizedBRAMFIFOF(16);
   let busWriteReqFifo  <- mkFIFOF();
   let busWriteDataFifo <- mkSizedBRAMFIFOF(16);
   let busWriteDoneFifo <- mkFIFOF();

   let bramReadReqFifo   <- mkFIFOF();
   let bramReadDataFifo  <- mkSizedBRAMFIFOF(16);
   let bramWriteReqFifo  <- mkFIFOF();
   let bramWriteDataFifo <- mkSizedBRAMFIFOF(16);
   let bramWriteDoneFifo <- mkFIFOF();

   let doneFifo <- mkFIFOF();

   let dataFifo <- mkSizedBRAMFIFOF(4096);

   AddressGenerator#(24,DataBusWidth) readAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(24,DataBusWidth) writeAddrGenerator <- mkAddressGenerator();

   let readReqObj <- mkProbe();
   let readReqDest <- mkProbe();
   let readReqOffset <- mkProbe();
   let readDataDest <- mkProbe();
   let readDataData <- mkProbe();
   let readDataLast <- mkProbe();
   let readBeatAddr <- mkProbe();
   let readBeatByteCount <- mkProbe();
   let readBeatLast <- mkProbe();
   let busReadDataData <- mkProbe();
   let busReadDataLast <- mkProbe();
   let writeReqObj <- mkProbe();
   let writeReqDest <- mkProbe();
   let writeReqOffset <- mkProbe();
   let writeDataDest <- mkProbe();
   let writeDataData <- mkProbe();
   let writeDataLast <- mkProbe();
   let writeBeatAddr <- mkProbe();
   let writeBeatByteCount <- mkProbe();
   let writeBeatLast <- mkProbe();
   let writeDoneTag <- mkProbe();
   let writeDoneDest <- mkProbe();

   rule rl_rd_req;
      MemRequest req <- toGet(readReqFifo).get();
      let dest = req.sglId[5:4];
      if (dest == 2)
	 bramReadReqFifo.enq(req);
      else
	 busReadReqFifo.enq(req);
      readAddrGenerator.request.put(PhysMemRequest { addr: truncate(req.offset), burstLen: req.burstLen, tag: extend(dest) });

      readReqObj <= req.sglId;
      readReqDest <= dest;
      readReqOffset <= req.offset[31:0];
   endrule

   rule rl_rd_data;
      let addrBeat <- readAddrGenerator.addrBeat.get();
      let dest = addrBeat.tag[1:0];
      MemData#(DataBusWidth) md;
      if (dest == 2)
	 md <- toGet(bramReadDataFifo).get();
      else
	 md <- toGet(busReadDataFifo).get();
      readDataFifo.enq(md);

      readDataDest <= dest;
      readDataData <= md.data;
      readDataLast <= md.last;
      readBeatAddr <= addrBeat.addr[15:0];
      readBeatByteCount <= addrBeat.bc;
      readBeatLast <= addrBeat.last;
   endrule

   rule rl_wr_req;
      MemRequest req <- toGet(writeReqFifo).get();
      Bit#(2) dest = req.sglId[5:4];
      if (dest == 2)
	 bramWriteReqFifo.enq(req);
      else if (dest == 3) begin
	 // no need to send the request
      end else
	 busWriteReqFifo.enq(req);
      writeAddrGenerator.request.put(PhysMemRequest { addr: truncate(req.offset), burstLen: req.burstLen, tag: extend(dest) });

      writeReqObj <= req.sglId;
      writeReqDest <= dest;
      writeReqOffset <= req.offset[31:0];
   endrule

   rule rl_wr_data;
      let addrBeat <- writeAddrGenerator.addrBeat.get();
      let dest = addrBeat.tag[1:0];
      MemData#(DataBusWidth) md <- toGet(writeDataFifo).get();
      if (dest == 2)
	 bramWriteDataFifo.enq(md);
      else if (dest == 3)
	 dataFifo.enq(md);
      else
	 busWriteDataFifo.enq(md);
      if (addrBeat.last)
	 doneFifo.enq(tuple2(dest, md.tag));
      else if (md.last)
	 doneFifo.enq(tuple2(dest, maxBound));

      writeDataDest <= dest;
      writeDataData <= md.data;
      writeDataLast <= md.last;
      writeBeatAddr <= addrBeat.addr[15:0];
      writeBeatByteCount <= addrBeat.bc;
      writeBeatLast <= addrBeat.last;

   endrule

   rule rl_wr_done;
      match { .dest, .tag } <- toGet(doneFifo).get();
      Bit#(MemTagSize) doneTag;
      if (dest == 2)
	 doneTag <- toGet(bramWriteDoneFifo).get();
      else if (dest == 3)
	 doneTag = 0;
      else
	 doneTag <- toGet(busWriteDoneFifo).get();
      writeDoneFifo.enq(doneTag);

      writeDoneTag <= doneTag;
      writeDoneDest <= dest;
   endrule

   interface MemServer server;
      interface MemReadServer readServer;
	 interface readReq  = toPut(readReqFifo);
	 interface readData = toGet(readDataFifo);
      endinterface
      interface MemWriteServer writeServer;
	 interface writeReq  = toPut(writeReqFifo);
	 interface writeData = toPut(writeDataFifo);
	 interface writeDone = toGet(writeDoneFifo);
      endinterface
   endinterface
   interface MemClient busClient;
      interface MemReadClient readClient;
	 interface readReq  = toGet(busReadReqFifo);
	 interface Put readData;
	    method Action put(MemData#(DataBusWidth) md);
	       busReadDataFifo.enq(md);
	       busReadDataData <= md.data;
	       busReadDataLast <= md.last;
	    endmethod
	 endinterface
      endinterface
      interface MemWriteClient writeClient;
	 interface writeReq  = toGet(busWriteReqFifo);
	 interface writeData = toGet(busWriteDataFifo);
	 interface writeDone = toPut(busWriteDoneFifo);
      endinterface
   endinterface
   interface MemClient bramClient;
      interface MemReadClient readClient;
	 interface readReq  = toGet(bramReadReqFifo);
	 interface readData = toPut(bramReadDataFifo);
      endinterface
      interface MemWriteClient writeClient;
	 interface writeReq  = toGet(bramWriteReqFifo);
	 interface writeData = toGet(bramWriteDataFifo);
	 interface writeDone = toPut(bramWriteDoneFifo);
      endinterface
   endinterface
   interface PipeOut data = toPipeOut(dataFifo);
endmodule

interface MemServerPortal;
   interface MemServerPortalRequest request;
endinterface

module mkPhysMemSlavePortal#(PhysMemSlave#(32,DataBusWidth) ms, MemServerPortalIndication ind)(MemServerPortal);

   FIFOF#(PhysMemRequest#(32,DataBusWidth)) araddrFifo <- mkFIFOF();
   FIFOF#(PhysMemRequest#(32,DataBusWidth)) awaddrFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           rdataFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           wdataFifo <- mkFIFOF();
   FIFOF#(Bit#(6))                doneFifo <- mkFIFOF();

   let araddrCnx <- mkConnection(toGet(araddrFifo), ms.read_server.readReq);
   let awaddrCnx <- mkConnection(toGet(awaddrFifo), ms.write_server.writeReq);
   let rdataCnx  <- mkConnection(ms.read_server.readData, toPut(rdataFifo));
   let wdataCnx  <- mkConnection(toGet(wdataFifo), ms.write_server.writeData);
   let doneCnx   <- mkConnection(ms.write_server.writeDone, toPut(doneFifo));

   rule rl_rdata;
      let rdata <- toGet(rdataFifo).get();
      ind.readDone(rdata.data);
   endrule

   rule rl_writeDone;
      let tag <- toGet(doneFifo).get();
      ind.writeDone();
   endrule

   interface MemServerPortalRequest request;
      method Action read(Bit#(32) addr);
	 araddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
      endmethod
      method Action write(Bit#(32) addr, Bit#(DataBusWidth) value);
	 awaddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
	 wdataFifo.enq(MemData {data: value, tag: 0, last: True});
      endmethod
   endinterface
endmodule

// Copyright (c) 2016 Connectal Project

// 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 BRAM::*;
import BuildVector::*;
import Clocks::*;
import Connectable::*;
import FIFOF::*;
import GetPut::*;
import Probe::*;
import Vector::*;

import AddressGenerator::*;
import AxiBits::*;
import ConnectalClocks::*;
import ConnectalConfig::*;
import DefaultValue::*;
import HostInterface::*;
import MemReadEngine::*;
import MemTypes::*;
import PhysMemSlaveFromBram::*;
import Pipe::*;
import TraceMemClient::*;
import XilinxCells::*;
import MPEngine::*;

import AxiPcieRootPort::*;
import NvmeIfc::*;
import NvmePins::*;

`ifndef TOP_SOURCES_PORTAL_CLOCK
import ConnectalBramFifo::*;
`else
import BRAMFIFO::*;
module mkDualClockBramFIFOF#(Clock clock1, Reset reset1, Clock clock2, Reset reset2)(FIFOF#(a))
   provisos (Bits#(a, asz), Add#(1, a__, asz));
   FIFOF#(a) fifo <- mkSizedBRAMFIFOF(512, clocked_by clock1, reset_by reset1);
   return fifo;
endmodule
`endif

interface Nvme;
   interface NvmeRequest request;
   interface MemServerPortalRequest bramRequest;
   interface NvmeTrace trace;
   interface NvmePins pins;
   interface Vector#(2, MemReadClient#(DataBusWidth)) dmaReadClient;
   interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaWriteClient;
`ifdef TOP_SOURCES_PORTAL_CLOCK
   interface Clock portalClockSource;
`endif
endinterface

module mkNvme#(NvmeIndication ind, NvmeTrace trace, MemServerPortalIndication bramIndication)(Nvme);
   let clock <- exposeCurrentClock;
   let reset <- exposeCurrentReset;
   let refclk_p <- mkB2C1();
   let refclk_n <- mkB2C1();
   let pcie_clk_100mhz_buf <- mkClockIBUFDS_GTE2(
`ifdef ClockDefaultParam
       defaultValue,
`endif
      True, refclk_p.c, refclk_n.c);
`ifndef TOP_SOURCES_PORTAL_CLOCK
   let axiClockB2C    <- mkB2C1();
   let axiCtlClockB2C <- mkB2C1();
   let axiClock = axiClockB2C.c;
   let axiCtlClock = axiCtlClockB2C.c;
   let axiReset <- mkSyncReset(10, reset, axiClock);
   let axiCtlReset <- mkSyncReset(10, reset, axiCtlClock);
`else
   let axiClock = clock;
   let axiCtlClock = clock;
   let axiReset = reset;
   let axiCtlReset = reset;
`endif

   let axiRootPort <- mkAPRP(pcie_clk_100mhz_buf, reset, axiClock, axiReset, axiCtlClock, axiCtlReset);
`ifndef TOP_SOURCES_PORTAL_CLOCK
   let axiClockC2B <- mkC2B(axiRootPort.axi.aclk_out);
   let axiCtlClockC2B <- mkC2B(axiRootPort.axi.ctl_aclk_out);
   rule rl_connect_clocks;
      axiClockB2C.inputclock(axiClockC2B.o);
      axiCtlClockB2C.inputclock(axiClockC2B.o);
   endrule
`endif

   FIFOF#(Bit#(32)) dfifoCtl <- mkFIFOF();
   Axi4SlaveBits#(32,DataBusWidth,4,Empty) axiRootPortSlave    = toAxi4SlaveBits(axiRootPort.s_axi);
   Axi4SlaveLiteBits#(32,32)     axiRootPortSlaveCtl = toAxi4SlaveBits(axiRootPort.s_axi_ctl);
   PhysMemSlave#(32,DataBusWidth)          axiRootPortMemSlave    <- mkPhysMemSlave(axiRootPortSlave, clocked_by axiClock, reset_by axiReset);
   PhysMemSlave#(32,32)          axiRootPortMemSlaveCtl <- mkPhysMemSlave(axiRootPortSlaveCtl, clocked_by axiCtlClock, reset_by axiCtlReset);

   FIFOF#(PhysMemRequest#(32,DataBusWidth)) araddrFifo <- mkFIFOF();
   FIFOF#(PhysMemRequest#(32,DataBusWidth)) awaddrFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           rdataFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           wdataFifo <- mkFIFOF();
   FIFOF#(Bit#(6))                           doneFifo <- mkFIFOF();

   let araddrCnx <- mkConnection(toGet(araddrFifo), axiRootPortMemSlave.read_server.readReq);
   let awaddrCnx <- mkConnection(toGet(awaddrFifo), axiRootPortMemSlave.write_server.writeReq);
   let rdataCnx  <- mkConnection(axiRootPortMemSlave.read_server.readData, toPut(rdataFifo));
   let wdataCnx  <- mkConnection(toGet(wdataFifo), axiRootPortMemSlave.write_server.writeData);
   let doneCnx   <- mkConnection(axiRootPortMemSlave.write_server.writeDone, toPut(doneFifo));

   rule rl_rdata;
      let rdata <- toGet(rdataFifo).get();
      ind.readDone(rdata.data);
   endrule

   rule rl_writeDone;
      let tag <- toGet(doneFifo).get();
      ind.writeDone();
   endrule

   FIFOF#(PhysMemRequest#(32,32)) araddrFifoCtl <- mkFIFOF();
   FIFOF#(PhysMemRequest#(32,32)) awaddrFifoCtl <- mkFIFOF();
   FIFOF#(MemData#(32))           rdataFifoCtl <- mkFIFOF();
   FIFOF#(MemData#(32))           wdataFifoCtl <- mkFIFOF();
   FIFOF#(Bit#(6))                doneFifoCtl <- mkFIFOF();

   let araddrCtlCnx <- mkConnection(toGet(araddrFifoCtl), axiRootPortMemSlaveCtl.read_server.readReq);
   let awaddrCtlCnx <- mkConnection(toGet(awaddrFifoCtl), axiRootPortMemSlaveCtl.write_server.writeReq);
   let rdataCtlCnx  <- mkConnection(axiRootPortMemSlaveCtl.read_server.readData, toPut(rdataFifoCtl));
   let wdataCtlCnx  <- mkConnection(toGet(wdataFifoCtl), axiRootPortMemSlaveCtl.write_server.writeData);
   let doneCtlCnx   <- mkConnection(axiRootPortMemSlaveCtl.write_server.writeDone, toPut(doneFifoCtl));

   rule rl_rdata_ctl;
      let rdata <- toGet(rdataFifoCtl).get();
      ind.readDone(extend(rdata.data));
   endrule

   rule rl_writeDone_ctl;
      let tag <- toGet(doneFifoCtl).get();
      ind.writeDone();
   endrule

   Axi4MasterBits#(32,DataBusWidth,MemTagSize,Empty) m_axi_mm = toAxi4MasterBits(axiRootPort.m_axi);
   let getObjId = (interface GetObjId;
		   method SGLId objId(Bit#(32) addr); return extend(addr[31:24]); endmethod
		   method Bit#(MemOffsetSize) addr(Bit#(32) axiAddr); return extend(axiAddr[23:0]); endmethod
		   endinterface);
   let memReadClient  <- mkMemReadClient(getObjId, m_axi_mm);
   let memWriteClient <- mkMemWriteClient(getObjId, m_axi_mm);

   FIFOF#(Tuple4#(DmaChannel,Bool,MemRequest,Bit#(32))) traceFifo <- mkSizedBRAMFIFOF(128);
   PipeIn#(Tuple4#(DmaChannel,Bool,MemRequest,Bit#(32))) tracePipe = toPipeIn(traceFifo);
   FIFOF#(Tuple4#(DmaChannel,Bool,MemData#(DataBusWidth),Bit#(32))) traceDataFifo <- mkSizedBRAMFIFOF(1024);
   PipeIn#(Tuple4#(DmaChannel,Bool,MemData#(DataBusWidth),Bit#(32))) traceDataPipe = toPipeIn(traceDataFifo);
   FIFOF#(Tuple2#(DmaChannel,Bit#(32)))                              traceDoneFifo <- mkSizedBRAMFIFOF(1024);
   PipeIn#(Tuple2#(DmaChannel,Bit#(32)))                             traceDonePipe = toPipeIn(traceDoneFifo);

   rule rl_trace1;
      match { .chan, .write, .req, .timestamp } <- toGet(traceFifo).get();
      trace.traceDmaRequest(chan, write, truncate(req.sglId), extend(req.offset), extend(req.burstLen), extend(req.tag), timestamp);
   endrule
   rule rl_trace_data;
      match { .chan, .write, .md, .timestamp } <- toGet(traceDataFifo).get();
      trace.traceDmaData(chan, write, md.data, md.last, extend(md.tag), timestamp);
   endrule
   rule rl_trace_done;
      match { .chan, .timestamp } <- toGet(traceDoneFifo).get();
      trace.traceDmaDone(chan, 0, timestamp);
   endrule

   let traceReadClient <- mkTraceReadClient(tracePipe,traceDataPipe,DMA_TX,memReadClient);
   let traceWriteClient <- mkTraceWriteClient(tracePipe,traceDataPipe,traceDonePipe,DMA_RX,memWriteClient);
   let traceClient = (interface MemClient#(DataBusWidth);
			 interface readClient = traceReadClient;
			 interface writeClient = traceWriteClient;
		      endinterface);

   let splitter <- mkSplitMemServer();
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency = 2;
   bramConfig.memorySize = 1024;
   BRAM2Port#(Bit#(32),Bit#(DataBusWidth)) bram <- mkBRAM2Server(bramConfig);
   MemServer#(DataBusWidth)            bramMemA <- mkMemServerFromBram(bram.portA);
   PhysMemSlave#(32,DataBusWidth)      bramMemB <- mkPhysMemSlaveFromBram(bram.portB);
   MemServerPortal          bramMemServerPortal <- mkPhysMemSlavePortal(bramMemB,bramIndication);

   MemReadEngine#(DataBusWidth,DataBusWidth,2,1) re <- mkMemReadEngine();
   MPEngine#(DataBusWidth,DataBusWidth)    mpEngine <- mkMPStreamEngine(splitter.data, re.readServers[0]);

   let traceMemCnx <- mkConnection(traceClient, splitter.server);
   let bramMemCnx  <- mkConnection(splitter.bramClient, bramMemA);
   // rule rl_data;
   //    let md <- toGet(splitter.data).get();
   //    trace.traceData(md.data, md.last, extend(md.tag));
   // endrule
   rule rl_locdone;
      let loc <- toGet(mpEngine.locdone).get();
      ind.strstrLoc(pack(loc));
   endrule

   interface MemServerPortalRequest bramRequest = bramMemServerPortal.request;
   interface NvmeRequest request;

      method Action status();
        ind.status(axiRootPort.mmcm.lock());
      endmethod

      method Action read32(Bit#(32) addr);
	 araddrFifo.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
      endmethod
      method Action write32(Bit#(32) addr, Bit#(32) value);
	 awaddrFifo.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
	 wdataFifo.enq(MemData {data: extend(value), tag: 0, last: True});
      endmethod
      method Action read(Bit#(32) addr);
	 araddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
      endmethod
      method Action write(Bit#(32) addr, Bit#(DataBusWidth) value);
	 awaddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
	 wdataFifo.enq(MemData {data: value, tag: 0, last: True});
      endmethod

      method Action readCtl(Bit#(32) addr);
	 araddrFifoCtl.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
      endmethod
      method Action writeCtl(Bit#(32) addr, Bit#(DataBusWidth) value);
	 awaddrFifoCtl.enq(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
	 wdataFifoCtl.enq(MemData {data: truncate(value), tag: 0, last: True});
      endmethod
      method Action setSearchString(Bit#(32) needleSglId, Bit#(32) mpNextSglId, Bit#(32) needleLen);
	 mpEngine.setsearch.enq(tuple3(needleSglId, mpNextSglId, needleLen));
      endmethod
      method Action startSearch(Bit#(32) haystackLen);
	 mpEngine.setsearch.enq(tuple3(/* unused */maxBound, haystackLen, /* unused */0));
      endmethod
   endinterface
   interface Clock portalClockSource = axiRootPort.axi.aclk_out;
   interface NvmePins pins;
      interface deleteme_unused_clock = clock;
      interface pcie_sys_reset_n = reset;
      interface pcie = axiRootPort.pci;
      method Action pcie_refclk(Bit#(1) p, Bit#(1) n);
         refclk_p.inputclock(p);
         refclk_n.inputclock(n);
      endmethod
   endinterface
   interface Vector dmaReadClient = vec(splitter.busClient.readClient, re.dmaClient);
   interface Vector dmaWriteClient = vec(splitter.busClient.writeClient);
endmodule

instance ToAxi4SlaveBits#(Axi4SlaveBits#(32,DataBusWidth,4,Empty), AprpS_axi);
   function Axi4SlaveBits#(32,DataBusWidth,4,Empty) toAxi4SlaveBits(AprpS_axi s);
      return (interface Axi4SlaveBits#(32,DataBusWidth,4,Empty);
	 method araddr = compose(s.araddr, extend);
	 method arburst = s.arburst;
	 //method arcache = s.arcache;
	 method arid = s.arid;
	 method arlen = s.arlen;
	 //method arlock = s.arlock;
	 //method arprot = s.arprot;
	 //method arqos = s.arqos;
	 method arready = s.arready;
	 method arsize = s.arsize;
	 method arvalid = s.arvalid;

	 method awaddr = compose(s.awaddr, extend);
	 method awburst = s.awburst;
	 //method awcache = s.awcache;
	 method awid = s.awid;
	 method awlen = s.awlen;
	 //method awlock = s.awlock;
	 //method awprot = s.awprot;
	 //method awqos = s.awqos;
	 method awready = s.awready;
	 method awsize = s.awsize;
	 method awvalid = s.awvalid;

	 method bid = s.bid;
	 method bready = s.bready;
	 method bresp = s.bresp;
	 method bvalid = s.bvalid;
	 method rdata = s.rdata;
	 method rid = s.rid;
	 method rlast = s.rlast;
	 method rready = s.rready;
	 method rresp = s.rresp;
	 method rvalid = s.rvalid;
	 method wdata = s.wdata;
	 method wlast = s.wlast;
	 method wready = s.wready;
	 method wvalid = s.wvalid;
	 method wstrb = s.wstrb;
	 endinterface);
   endfunction
endinstance

instance ToAxi4SlaveBits#(Axi4SlaveLiteBits#(32,32), AprpS_axi_ctl);
   function Axi4SlaveLiteBits#(32,32) toAxi4SlaveBits(AprpS_axi_ctl s);
      return (interface Axi4SlaveLiteBits#(32,32);
	 method araddr = compose(s.araddr, extend);
	 method arready = s.arready;
	 method arvalid = s.arvalid;

	 method awaddr = compose(s.awaddr, extend);
	 method awready = s.awready;
	 method awvalid = s.awvalid;

	 method bready = s.bready;
	 method bresp = s.bresp;
	 method bvalid = s.bvalid;
	 method rdata = s.rdata;
	 method rready = s.rready;
	 method rresp = s.rresp;
	 method rvalid = s.rvalid;
	 method wdata = s.wdata;
	 method wready = s.wready;
	 method Action      wvalid(Bit#(1) v);
	    s.wvalid(v);
	    s.wstrb(pack(replicate(v)));
	 endmethod
	 endinterface);
   endfunction
endinstance

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AprpM_axi);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AprpM_axi m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
	   method araddr = m.araddr;
	   method arburst = m.arburst;
	   method arcache = m.arcache;
	   method arlen = m.arlen;
	   method arlock = extend(m.arlock);
	   method arready = m.arready;
	   method arsize = m.arsize;
	   method arvalid = m.arvalid;
	   method Bit#(1) aresetn(); return 1; endmethod
	   method Bit#(tagWidth)     arid(); return 0; endmethod
	   method arprot = m.arprot;
	   method arqos = 0;
	   method awaddr = m.awaddr;
	   method awburst = m.awburst;
	   method awcache = m.awcache;
	   method Bit#(tagWidth)     awid(); return 0; endmethod
	   method awlen = m.awlen;
	   method awlock = extend(m.awlock);
	   method awprot = m.awprot;
	   method awready = m.awready;
	   method Bit#(4)     awqos(); return 0; endmethod
	   method awsize = m.awsize;
	   method awvalid = m.awvalid;
	   method Action      bid(Bit#(tagWidth) v); endmethod
	   method bready = m.bready;
	   method bresp = m.bresp;
	   method bvalid = m.bvalid;
	   method rdata = m.rdata;
	   method Action      rid(Bit#(tagWidth) v); endmethod
	   method rlast = m.rlast;
	   method rready = m.rready;
	   method rresp = m.rresp;
	   method rvalid = m.rvalid;
	   method wdata = m.wdata;
	   method Bit#(tagWidth)     wid(); return 0; endmethod
	   method wlast = m.wlast;
	   method wready = m.wready;
	   method wstrb = m.wstrb;
	   method wvalid = m.wvalid;
	 interface extra = ?;
	 endinterface);
   endfunction
endinstance

interface SplitMemServer;
   interface MemServer#(DataBusWidth) server;
   interface MemClient#(DataBusWidth) busClient;
   interface MemClient#(DataBusWidth) bramClient;
   interface PipeOut#(MemData#(DataBusWidth)) data;
endinterface

module mkSplitMemServer(SplitMemServer);
   let readReqFifo   <- mkFIFOF();
   let readDataFifo  <- mkFIFOF();
   let writeReqFifo  <- mkFIFOF();
   let writeDataFifo <- mkFIFOF();
   let writeDoneFifo <- mkFIFOF();

   let busReadReqFifo   <- mkFIFOF();
   let busReadDataFifo  <- mkSizedBRAMFIFOF(16);
   let busWriteReqFifo  <- mkFIFOF();
   let busWriteDataFifo <- mkSizedBRAMFIFOF(16);
   let busWriteDoneFifo <- mkFIFOF();

   let bramReadReqFifo   <- mkFIFOF();
   let bramReadDataFifo  <- mkSizedBRAMFIFOF(16);
   let bramWriteReqFifo  <- mkFIFOF();
   let bramWriteDataFifo <- mkSizedBRAMFIFOF(16);
   let bramWriteDoneFifo <- mkFIFOF();

   let doneFifo <- mkFIFOF();

   let dataFifo <- mkSizedBRAMFIFOF(4096);

   AddressGenerator#(24,DataBusWidth) readAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(24,DataBusWidth) writeAddrGenerator <- mkAddressGenerator();

   let readReqObj <- mkProbe();
   let readReqDest <- mkProbe();
   let readReqOffset <- mkProbe();
   let readDataDest <- mkProbe();
   let readDataData <- mkProbe();
   let readDataLast <- mkProbe();
   let readBeatAddr <- mkProbe();
   let readBeatByteCount <- mkProbe();
   let readBeatLast <- mkProbe();
   let busReadDataData <- mkProbe();
   let busReadDataLast <- mkProbe();
   let writeReqObj <- mkProbe();
   let writeReqDest <- mkProbe();
   let writeReqOffset <- mkProbe();
   let writeDataDest <- mkProbe();
   let writeDataData <- mkProbe();
   let writeDataLast <- mkProbe();
   let writeBeatAddr <- mkProbe();
   let writeBeatByteCount <- mkProbe();
   let writeBeatLast <- mkProbe();
   let writeDoneTag <- mkProbe();
   let writeDoneDest <- mkProbe();

   rule rl_rd_req;
      MemRequest req <- toGet(readReqFifo).get();
      let dest = req.sglId[5:4];
      if (dest == 2)
	 bramReadReqFifo.enq(req);
      else
	 busReadReqFifo.enq(req);
      readAddrGenerator.request.put(PhysMemRequest { addr: truncate(req.offset), burstLen: req.burstLen, tag: extend(dest) });

      readReqObj <= req.sglId;
      readReqDest <= dest;
      readReqOffset <= req.offset[31:0];
   endrule

   rule rl_rd_data;
      let addrBeat <- readAddrGenerator.addrBeat.get();
      let dest = addrBeat.tag[1:0];
      MemData#(DataBusWidth) md;
      if (dest == 2)
	 md <- toGet(bramReadDataFifo).get();
      else
	 md <- toGet(busReadDataFifo).get();
      readDataFifo.enq(md);

      readDataDest <= dest;
      readDataData <= md.data;
      readDataLast <= md.last;
      readBeatAddr <= addrBeat.addr[15:0];
      readBeatByteCount <= addrBeat.bc;
      readBeatLast <= addrBeat.last;
   endrule

   rule rl_wr_req;
      MemRequest req <- toGet(writeReqFifo).get();
      Bit#(2) dest = req.sglId[5:4];
      if (dest == 2)
	 bramWriteReqFifo.enq(req);
      else if (dest == 3) begin
	 // no need to send the request
      end else
	 busWriteReqFifo.enq(req);
      writeAddrGenerator.request.put(PhysMemRequest { addr: truncate(req.offset), burstLen: req.burstLen, tag: extend(dest) });

      writeReqObj <= req.sglId;
      writeReqDest <= dest;
      writeReqOffset <= req.offset[31:0];
   endrule

   rule rl_wr_data;
      let addrBeat <- writeAddrGenerator.addrBeat.get();
      let dest = addrBeat.tag[1:0];
      MemData#(DataBusWidth) md <- toGet(writeDataFifo).get();
      if (dest == 2)
	 bramWriteDataFifo.enq(md);
      else if (dest == 3)
	 dataFifo.enq(md);
      else
	 busWriteDataFifo.enq(md);
      if (addrBeat.last)
	 doneFifo.enq(tuple2(dest, md.tag));
      else if (md.last)
	 doneFifo.enq(tuple2(dest, maxBound));

      writeDataDest <= dest;
      writeDataData <= md.data;
      writeDataLast <= md.last;
      writeBeatAddr <= addrBeat.addr[15:0];
      writeBeatByteCount <= addrBeat.bc;
      writeBeatLast <= addrBeat.last;

   endrule

   rule rl_wr_done;
      match { .dest, .tag } <- toGet(doneFifo).get();
      Bit#(MemTagSize) doneTag;
      if (dest == 2)
	 doneTag <- toGet(bramWriteDoneFifo).get();
      else if (dest == 3)
	 doneTag = 0;
      else
	 doneTag <- toGet(busWriteDoneFifo).get();
      writeDoneFifo.enq(doneTag);

      writeDoneTag <= doneTag;
      writeDoneDest <= dest;
   endrule

   interface MemServer server;
      interface MemReadServer readServer;
	 interface readReq  = toPut(readReqFifo);
	 interface readData = toGet(readDataFifo);
      endinterface
      interface MemWriteServer writeServer;
	 interface writeReq  = toPut(writeReqFifo);
	 interface writeData = toPut(writeDataFifo);
	 interface writeDone = toGet(writeDoneFifo);
      endinterface
   endinterface
   interface MemClient busClient;
      interface MemReadClient readClient;
	 interface readReq  = toGet(busReadReqFifo);
	 interface Put readData;
	    method Action put(MemData#(DataBusWidth) md);
	       busReadDataFifo.enq(md);
	       busReadDataData <= md.data;
	       busReadDataLast <= md.last;
	    endmethod
	 endinterface
      endinterface
      interface MemWriteClient writeClient;
	 interface writeReq  = toGet(busWriteReqFifo);
	 interface writeData = toGet(busWriteDataFifo);
	 interface writeDone = toPut(busWriteDoneFifo);
      endinterface
   endinterface
   interface MemClient bramClient;
      interface MemReadClient readClient;
	 interface readReq  = toGet(bramReadReqFifo);
	 interface readData = toPut(bramReadDataFifo);
      endinterface
      interface MemWriteClient writeClient;
	 interface writeReq  = toGet(bramWriteReqFifo);
	 interface writeData = toGet(bramWriteDataFifo);
	 interface writeDone = toPut(bramWriteDoneFifo);
      endinterface
   endinterface
   interface PipeOut data = toPipeOut(dataFifo);
endmodule

interface MemServerPortal;
   interface MemServerPortalRequest request;
endinterface

module mkPhysMemSlavePortal#(PhysMemSlave#(32,DataBusWidth) ms, MemServerPortalIndication ind)(MemServerPortal);

   FIFOF#(PhysMemRequest#(32,DataBusWidth)) araddrFifo <- mkFIFOF();
   FIFOF#(PhysMemRequest#(32,DataBusWidth)) awaddrFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           rdataFifo <- mkFIFOF();
   FIFOF#(MemData#(DataBusWidth))           wdataFifo <- mkFIFOF();
   FIFOF#(Bit#(6))                doneFifo <- mkFIFOF();

   let araddrCnx <- mkConnection(toGet(araddrFifo), ms.read_server.readReq);
   let awaddrCnx <- mkConnection(toGet(awaddrFifo), ms.write_server.writeReq);
   let rdataCnx  <- mkConnection(ms.read_server.readData, toPut(rdataFifo));
   let wdataCnx  <- mkConnection(toGet(wdataFifo), ms.write_server.writeData);
   let doneCnx   <- mkConnection(ms.write_server.writeDone, toPut(doneFifo));

   rule rl_rdata;
      let rdata <- toGet(rdataFifo).get();
      ind.readDone(rdata.data);
   endrule

   rule rl_writeDone;
      let tag <- toGet(doneFifo).get();
      ind.writeDone();
   endrule

   interface MemServerPortalRequest request;
      method Action read(Bit#(32) addr);
	 araddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
      endmethod
      method Action write(Bit#(32) addr, Bit#(DataBusWidth) value);
	 awaddrFifo.enq(PhysMemRequest { addr: addr, burstLen: fromInteger(valueOf(TDiv#(DataBusWidth,8))), tag: 0 });
	 wdataFifo.enq(MemData {data: value, tag: 0, last: True});
      endmethod
   endinterface
endmodule


use mapM and zip with mkXsimSink and mkXsimSource

// Copyright (c) 2015 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 Vector            :: *;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import BlueNoC::*;
import BnocPortal::*;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

import "BVI" XsimSource =
module mkXsimSourceBVI#(Bit#(32) portal, Bool src_rdy, MsgBeat#(4) beat)(Empty);
    port portal = portal;
    port src_rdy = src_rdy;
    port beat = beat;
endmodule
module mkXsimSource#(MsgSource#(4) indication, Integer i)(Empty);
   mkXsimSourceBVI(fromInteger(i), indication.src_rdy, indication.beat());
   rule ind_dst_rdy;
      indication.dst_rdy(True);
   endrule
endmodule

interface MsgSinkR#(numeric type bytes_per_beat);
   method Bool src_rdy();
   method MsgBeat#(4) beat();
endinterface

import "BVI" XsimSink =
module mkXsimSinkBVI#(Bit#(32) portal, Bool dst_rdy)(MsgSinkR#(4));
    port portal = portal;
    port dst_rdy = dst_rdy;
    method src_rdy src_rdy();
    method beat beat();
    schedule (src_rdy, beat) CF (src_rdy, beat);
endmodule
module mkXsimSink#(MsgSink#(4) request, Integer portalIndex)(MsgSinkR#(4));
   let sink <- mkXsimSinkBVI(fromInteger(portalIndex), request.dst_rdy);
   rule req_src_rdy;
      request.src_rdy(sink.src_rdy);
   endrule
   rule req_beat;
      request.beat(sink.beat);
   endrule
endmodule

module mkXsimTop(Empty);
   Clock derivedClock <- exposeCurrentClock;
   Reset derivedReset <- exposeCurrentReset;

   Reg#(Bool) dumpstarted <- mkReg(False);
   rule startdump if (!dumpstarted);
      //$dumpfile("dump.vcd");
      //$dumpvars;
      dumpstarted <= True;
   endrule
   XsimHost host <- mkXsimHost(derivedClock, derivedReset);
   //BluenocTop#(1,1) top <- mkBluenocTop(
   //BluenocTop#(numRequests, numIndications) top <- mkBluenocTop(
   let top <- mkBluenocTop(
`ifdef IMPORT_HOSTIF
       host
`endif
       );

   mapM_(uncurry(mkXsimSource), zip(top.indications, genVector()));
   mapM_(uncurry(mkXsimSink), zip(top.requests, genVector()));
endmodule

// Copyright (c) 2015 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 Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import BlueNoC::*;
import BnocPortal::*;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

import "BVI" XsimSource =
module mkXsimSource#(Bit#(32) portal, Bool src_rdy, MsgBeat#(4) beat)(Empty);
    port portal = portal;
    port src_rdy = src_rdy;
    port beat = beat;
endmodule

interface MsgSinkR#(numeric type bytes_per_beat);
   method Bool src_rdy();
   method MsgBeat#(4) beat();
endinterface

import "BVI" XsimSink =
module mkXsimSink#(Bit#(32) portal, Bool dst_rdy)(MsgSinkR#(4));
    port portal = portal;
    port dst_rdy = dst_rdy;
    method src_rdy src_rdy();
    method beat beat();
    schedule (src_rdy, beat) CF (src_rdy, beat);
endmodule

module mkXsimTop(Empty);
   Clock derivedClock <- exposeCurrentClock;
   Reset derivedReset <- exposeCurrentReset;

   Reg#(Bool) dumpstarted <- mkReg(False);
   rule startdump if (!dumpstarted);
      //$dumpfile("dump.vcd");
      //$dumpvars;
      dumpstarted <= True;
   endrule
   XsimHost host <- mkXsimHost(derivedClock, derivedReset);
   //BluenocTop#(1,1) top <- mkBluenocTop(
   //BluenocTop#(numRequests, numIndications) top <- mkBluenocTop(
   let top <- mkBluenocTop(
`ifdef IMPORT_HOSTIF
       host
`endif
       );

   for(Integer i = 0; i < top.indications.length; i=i+1) begin
       mkXsimSource(i, top.indications[i].src_rdy, top.indications[i].beat);
       rule ind_dst_rdy;
           top.indications[i].dst_rdy(True);
       endrule
   end
   for(Integer i = 0; i < top.requests.length; i=i+1) begin
       MsgSinkR#(4) sink <- mkXsimSink(i, top.requests[i].dst_rdy);
       rule req_src_rdy;
           top.requests[i].src_rdy(sink.src_rdy);
       endrule
       rule req_beat;
           top.requests[i].beat(sink.beat);
       endrule
   end
endmodule


add synth boundary on mkProgram

add synth boundary on mkProgram

// Copyright (c) 2016 Cornell University.

// 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 Library::*;
import ConnectalTypes::*;
import Control::*;
import SynthBuilder::*;
`include "SynthBuilder.defines"

`include "Debug.defines"
//`include "TieOff.defines"
//`TIEOFF_PIPEOUT("program ", MetadataRequest)

interface Program#(numeric type nrx, numeric type ntx, numeric type nhs, numeric type nextra);
   interface Vector#(TAdd#(TAdd#(nrx, nhs), nextra), PipeIn#(MetadataRequest)) prev;
   interface Vector#(TAdd#(TAdd#(nrx, nhs), nextra), PipeOut#(MetadataRequest)) next;
   method Action set_verbosity (int verbosity);
`include "APIDefGenerated.bsv" // for table api
endinterface

module mkProgram(Program#(nrx, ntx, nhs, nextra))
   provisos(Add#(b__, TLog#(TAdd#(TAdd#(nrx, nhs), nextra)), 9) // introduced by truncate
           ,Pipe::FunnelPipesPipelined#(1, TAdd#(TAdd#(nrx, nhs), nextra), StructDefines::MetadataRequest, 2)
           ,NumAlias#(TLog#(TAdd#(TAdd#(nrx, nhs), nextra)), wpi)
           ,NumAlias#(TAdd#(TAdd#(nrx, nhs), nextra), npi)
           );
   `PRINT_DEBUG_MSG

   // N-to-1 arbitration
   Vector#(npi, FIFOF#(MetadataRequest)) funnel_ff <- replicateM(mkFIFOF);
   function PipeIn#(MetadataRequest) metaPipeIn(Integer i);
      return toPipeIn(funnel_ff[i]);
   endfunction
   function PipeOut#(MetadataRequest) metaPipeOut(Integer i);
      return toPipeOut(funnel_ff[i]);
   endfunction
   FunnelPipe#(1, npi, MetadataRequest, 2) metaPipe <- mkFunnelPipesPipelined(genWith(metaPipeOut));

   Ingress ingress <- mkIngress();
   mkConnection(metaPipe[0], ingress.prev);

   Egress egress <- mkEgress();
   mkConnection(ingress.next, egress.prev);

   FIFOF#(Tuple2#(Bit#(wpi), MetadataRequest)) writeData <- mkFIFOF;
   UnFunnelPipe#(1, npi, MetadataRequest, 2) demux <- mkUnFunnelPipesPipelined(vec(toPipeOut(writeData)));
   messageM("unFunnel " + printType(typeOf(demux)));

   // use egress_port value to pick outgoing port
   // truncate egress_port to fit number of ports on board
   rule egress_demux;
      let v = egress.next.first;
      egress.next.deq;
      if (v.meta.standard_metadata.ingress_port matches tagged Valid .prt) begin
         let tpl = tuple2(truncate(prt), v);
         writeData.enq(tpl);
      end
      else begin
         dbprint(3, $format("invalid ingress_port"));
      end
   endrule

   interface prev = genWith(metaPipeIn);
   interface next = demux;
   method Action set_verbosity (int verbosity);
      cf_verbosity <= verbosity;
      ingress.set_verbosity(verbosity);
      egress.set_verbosity(verbosity);
   endmethod
`include "ProgDeclGenerated.bsv"
endmodule

`SynthBuildModule(mkProgram, Program#(4,4,1,2), mkProgram_4_4_1_2)
`SynthBuildModule(mkProgram, Program#(4,4,1,5), mkProgram_4_4_1_5)

// Copyright (c) 2016 Cornell University.

// 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 Library::*;
import ConnectalTypes::*;
import Control::*;

`include "Debug.defines"
//`include "TieOff.defines"
//`TIEOFF_PIPEOUT("program ", MetadataRequest)

interface Program#(numeric type nrx, numeric type ntx, numeric type nhs, numeric type nextra);
   interface Vector#(TAdd#(TAdd#(nrx, nhs), nextra), PipeIn#(MetadataRequest)) prev;
   interface Vector#(TAdd#(TAdd#(nrx, nhs), nextra), PipeOut#(MetadataRequest)) next;
   method Action set_verbosity (int verbosity);
`include "APIDefGenerated.bsv" // for table api
endinterface

module mkProgram(Program#(nrx, ntx, nhs, nextra))
   provisos(Add#(b__, TLog#(TAdd#(TAdd#(nrx, nhs), nextra)), 9) // introduced by truncate
           ,Pipe::FunnelPipesPipelined#(1, TAdd#(TAdd#(nrx, nhs), nextra), StructDefines::MetadataRequest, 2)
           ,NumAlias#(TLog#(TAdd#(TAdd#(nrx, nhs), nextra)), wpi)
           ,NumAlias#(TAdd#(TAdd#(nrx, nhs), nextra), npi)
           );
   `PRINT_DEBUG_MSG

   // N-to-1 arbitration
   Vector#(npi, FIFOF#(MetadataRequest)) funnel_ff <- replicateM(mkFIFOF);
   function PipeIn#(MetadataRequest) metaPipeIn(Integer i);
      return toPipeIn(funnel_ff[i]);
   endfunction
   function PipeOut#(MetadataRequest) metaPipeOut(Integer i);
      return toPipeOut(funnel_ff[i]);
   endfunction
   FunnelPipe#(1, npi, MetadataRequest, 2) metaPipe <- mkFunnelPipesPipelined(genWith(metaPipeOut));

   Ingress ingress <- mkIngress();
   mkConnection(metaPipe[0], ingress.prev);

   Egress egress <- mkEgress();
   mkConnection(ingress.next, egress.prev);

   FIFOF#(Tuple2#(Bit#(wpi), MetadataRequest)) writeData <- mkFIFOF;
   UnFunnelPipe#(1, npi, MetadataRequest, 2) demux <- mkUnFunnelPipesPipelined(vec(toPipeOut(writeData)));
   messageM("unFunnel " + printType(typeOf(demux)));

   // use egress_port value to pick outgoing port
   // truncate egress_port to fit number of ports on board
   rule egress_demux;
      let v = egress.next.first;
      egress.next.deq;
      if (v.meta.standard_metadata.ingress_port matches tagged Valid .prt) begin
         let tpl = tuple2(truncate(prt), v);
         writeData.enq(tpl);
      end
      else begin
         dbprint(3, $format("invalid ingress_port"));
      end
   endrule

   interface prev = genWith(metaPipeIn);
   interface next = demux;
   method Action set_verbosity (int verbosity);
      cf_verbosity <= verbosity;
      ingress.set_verbosity(verbosity);
      egress.set_verbosity(verbosity);
   endmethod
`include "ProgDeclGenerated.bsv"
endmodule


add DDSTest machinery

add DDSTest machinery

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

// bsv libraries
import Vector::*;
import GetPut::*;
import Connectable :: *;
import FIFO::*;

// portz libraries
import Portal::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;

import MemPortal::*;
import MemTypes::*;
import MemServer::*;

// defined by user
import DDSTestInterfaces::*;
import DDSTest::*;
import ChannelSelectTestInterfaces::*;
import ChannelSelectTest::*;

// generated by tool
import ChannelSelectTestRequestWrapper::*;
import ChannelSelectTestIndicationProxy::*;
import DDSTestRequestWrapper::*;
import DDSTestIndicationProxy::*;

typedef enum { ChannelSelectTestIndication, ChannelSelectTestRequest, DDSTestIndication, DDSTestRequest} IfcNames deriving (Eq,Bits);

module mkPortalTop(StdPortalTop#(PhysAddrWidth));

   ChannelSelectTestIndicationProxy channelSelectTestIndicationProxy <- mkChannelSelectTestIndicationProxy(ChannelSelectTestIndication);

   ChannelSelectTestRequest channelSelectTestRequest <- mkChannelSelectTestRequest(channelSelectTestIndicationProxy.ifc);

   ChannelSelectTestRequestWrapper channelSelectTestRequestWrapper <- mkChannelSelectTestRequestWrapper(ChannelSelectTestRequest, channelSelectTestRequest);

   DDSTestIndicationProxy ddsTestIndicationProxy <- mkDDSTestIndicationProxy(DDSTestIndication);
   DDSTestRequest ddsTestRequest <- mkDDSTestRequest(ddsTestIndicationProxy.ifc);
   DDSTestRequestWrapper ddsTestRequestWrapper <- mkDDSTestRequestWrapper(DDSTestRequest, ddsTestRequest);

   Vector#(4,StdPortal) portals;
   portals[0] = channelSelectTestRequestWrapper.portalIfc;
   portals[1] = channelSelectTestIndicationProxy.portalIfc;
   portals[2] = ddsTestRequestWrapper.portalIfc;
   portals[3] = ddsTestIndicationProxy.portalIfc;

   // instantiate system directory
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = nil;
   interface leds = default_leds;

endmodule : mkPortalTop

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

// bsv libraries
import Vector::*;
import GetPut::*;
import Connectable :: *;
import FIFO::*;

// portz libraries
import Portal::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;

import MemPortal::*;
import MemTypes::*;
import MemServer::*;

// defined by user
import ChannelSelectTestInterfaces::*;
import ChannelSelectTest::*;

// generated by tool
import ChannelSelectTestRequestWrapper::*;
import ChannelSelectTestIndicationProxy::*;

typedef enum { ChannelSelectTestIndication, ChannelSelectTestRequest} IfcNames deriving (Eq,Bits);

module mkPortalTop(StdPortalTop#(PhysAddrWidth));

   ChannelSelectTestIndicationProxy channelSelectTestIndicationProxy <- mkChannelSelectTestIndicationProxy(ChannelSelectTestIndication);
   ChannelSelectTestRequest channelSelectTestRequest <- mkChannelSelectTestRequest(channelSelectTestIndicationProxy.ifc);
   ChannelSelectTestRequestWrapper channelSelectTestRequestWrapper <- mkChannelSelectTestRequestWrapper(ChannelSelectTestRequest, channelSelectTestRequest);

   Vector#(2,StdPortal) portals;
   portals[0] = channelSelectTestRequestWrapper.portalIfc;
   portals[1] = channelSelectTestIndicationProxy.portalIfc;

   // instantiate system directory
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = nil;
   interface leds = default_leds;

endmodule : mkPortalTop


update Sigmoid.bsv so it compiles again

update Sigmoid.bsv so it compiles again

Change-Id: I602305ddbbae12301fffd10f566797dae24aa39e

import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import Connectable::*;
import ClientServer::*;
import Memory::*;
import BRAM::*;
import DefaultValue::*;
import FloatingPoint::*;
import Real::*;
import PortalMemory::*;
import MemTypes::*;
import DmaVector::*;
import Pipe::*;
import FloatOps::*;
import RbmTypes::*;

interface SigmoidTable#(numeric type tsz);
   interface Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) ports;
   interface ReadOnly#(Float) rscale;
   interface ReadOnly#(Float) llimit;
   interface ReadOnly#(Float) ulimit;
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
   method Bit#(32) tableSize();
endinterface

module mkSigmoidTable(SigmoidTable#(tsz));
   let tsz = valueOf(tsz);
   BRAM_Configure bramCfg = defaultValue;
   let memorySize = 2**tsz;
   bramCfg.memorySize = memorySize;
   BRAM2Port#(Bit#(tsz), Vector#(3, Float)) sigmoidTable <- mkBRAM2Server(bramCfg);

   Reg#(Float) rscaleReg <- mkReg(fromReal(0.0));
   Reg#(Float) llimitReg <- mkReg(fromReal(0.0));
   Reg#(Float) ulimitReg <- mkReg(fromReal(0.0));

   Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) bramPorts;
   bramPorts[0] = sigmoidTable.portA;
   bramPorts[1] = sigmoidTable.portB;

   interface ReadOnly rscale = regToReadOnly(rscaleReg);
   interface ReadOnly llimit = regToReadOnly(llimitReg);
   interface ReadOnly ulimit = regToReadOnly(ulimitReg);
   interface Vector ports = bramPorts;
   method Action setSigmoidLimits(Float _rscale, Float _llimit, Float _ulimit);
      $display("setSigmoidLimits memorySize=%d\n", memorySize);
      rscaleReg <= _rscale;
      llimitReg <= _llimit;
      ulimitReg <= _ulimit;
      $display($format("rscale=", fshow(_rscale), "pack(rscale)=", fshow(pack(_rscale)), " llimit=", fshow(_llimit), " ulimit=", fshow(_ulimit)));
   endmethod
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
      sigmoidTable.portB.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: addr, datain: v});
   endmethod
   method Bit#(32) tableSize();
      return (1 << tsz);
   endmethod
endmodule

module mkSigmoidServer#(SigmoidTable#(tsz) sigmoidTable)(Server#(Float,Float))
   provisos (Add#(tsz,2,usz),
	     Add#(a__, usz, 32)
	     );
   let tsz = valueOf(tsz);
   Int#(usz) numEntries = 1<<fromInteger(tsz);
   // linear approximation around in range [-8,8]

   Bool verbose = False;
   FIFOF#(Float) angleFifo2 <- mkFIFOF();
   FIFOF#(Float) angleFifo <- mkFIFOF();
   let multiplier <- mkFloatMultiplier(defaultValue);
   let adder <- mkFloatAdder(defaultValue);
   let mac <- mkFloatMac(defaultValue);

   rule lookupEntry;
      Float angle = 0;
      if (verbose) begin
	 angle = angleFifo2.first;
	 angleFifo2.deq();
      end
      let response <- multiplier.response.get();
      Float scaled_angle = tpl_1(response);
      Exception e = tpl_2(response);
      if (pack(e) != 0) $display("lookup.exception e=%h scaled_angle=%h", e, pack(scaled_angle));

      Int#(usz) i = truncate(toInt32(scaled_angle));
      Bit#(tsz) index = truncate(pack(i + numEntries/2));
      if (i > (numEntries/2-1))
	 index = truncate(pack(numEntries-1));
      if (i < -numEntries/2)
	 index = 0;
      if (verbose)
	 $display("sigmoid lookupEntry angle=%h i=%d index=%d numEntries=%d", pack(angle), i, index, numEntries);
      sigmoidTable.ports[0].request.put(BRAMRequest{ write: False, responseOnWrite: False, address: index, datain: ?});
   endrule

   FIFOF#(Vector#(3, Float)) vFifo <- mkFIFOF();
   rule computeDelta;
      let vs <- sigmoidTable.ports[0].response.get();
      let angle = angleFifo.first();
      angleFifo.deq();
      if (verbose) $display("computeDelta angle=%h vs[0]=%h", pack(angle), pack(vs[0]));
      adder.request.put(tuple2(angle, vs[0]));
      vFifo.enq(vs);
   endrule

   rule interpolate;
      let vs = vFifo.first();
      vFifo.deq();
      let result <- adder.response.get();
      let delta = tpl_1(result);
      Exception e = tpl_2(result);
      if (pack(e) != 0) $display("interpolate.exception e=%h delta=%h", e, pack(delta));
      if (verbose) $display("sigmoid interpolate delta=%h vs[1]=%h vs[2]", pack(delta), pack(vs[1]), pack(vs[2]));
      mac.request.put(tuple3(tagged Valid vs[1], vs[2], delta));
   endrule

   interface Put request;
      method Action put(Float angle);
	 let c = compareFP(angle, sigmoidTable.llimit);
	 let d = compareFP(angle, sigmoidTable.ulimit);
	 if (c == LT)
	    angle = sigmoidTable.llimit;
	 if (d == GT)
	    angle = sigmoidTable.ulimit;
	 if (verbose)
	    angleFifo2.enq(angle);
	 angleFifo.enq(angle);
	 multiplier.request.put(tuple2(angle, sigmoidTable.rscale));
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Float) get();
	 let result <- mac.response.get();
	 let v = tpl_1(result);
	 Exception e = tpl_2(result);
	 if (pack(e) != 0) $display("mac.exception e=%h v=%h", e, pack(v));
	return v;
     endmethod
   endinterface
endmodule

module  mkSigmoid#(SigmoidTable#(tsz) sigmoidTable, PipeOut#(Float) in)(PipeOut#(Float))
   provisos (Add#(a__, TAdd#(tsz, 2), 32));

   let server <- mkSigmoidServer(sigmoidTable);

   FIFOF#(Float) rfifo <- mkFIFOF;
   rule sigmoidOut;
      let sv <- server.response.get();
      rfifo.enq(sv);
   endrule
   mkConnection(in, server.request);
   return toPipeOut(rfifo);
endmodule

interface DmaSigmoidIfc#(numeric type dsz);
   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numElts);
   method ActionValue#(Bool) finish();
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
   method ActionValue#(Bool) sigmoidTableUpdated();
   method Bit#(32) tableSize();

   interface Vector#(2, ObjectReadClient#(dsz)) readClients;
   interface ObjectWriteClient#(dsz) dmaClient;
endinterface

(* synthesize *)
module  mkDmaSigmoid(DmaSigmoidIfc#(dsz))
   provisos (Bits#(Float, fsz)
	     , Add#(N,0,n)
	     , Mul#(fsz,N,dmasz)
	     , Bits#(Vector#(2,Float), dsz)
	     , Mul#(dbytes, 8, dsz)
	     , Div#(dsz, 8, dbytes)
	     );

   Bool verbose = False;

   DmaVectorSource#(dmasz, Vector#(n,Float)) dmasource <- mkDmaVectorSource();
   DmaVectorSource#(dmasz, Vector#(n,Float)) dmatablesource <- mkDmaVectorSource();
   VectorSource#(dmasz, Vector#(n,Float)) source = dmasource.vector;
   VectorSource#(dmasz, Vector#(n,Float)) tableSource = dmatablesource.vector;

   Vector#(n, SigmoidTable#(6)) sigmoidTables <- replicateM(mkSigmoidTable);
   Vector#(n, Server#(Float,Float)) sigmoidServers;
   for (Integer i = 0; i < valueOf(n); i = i + 1) begin
      let s <- mkSigmoidServer(sigmoidTables[i]);
      sigmoidServers[i] = s;
   end

   Reg#(Bool) updatingSigmoidTable <- mkReg(False);
   Reg#(Bit#(6)) entryNumber <- mkReg(0);

   PipeOut#(Vector#(4, Float)) sigmoidSourceFunnel <- mkUnfunnel(tableSource.pipe);
   rule updateSigmoidTableRule if (updatingSigmoidTable);
      let vs = sigmoidSourceFunnel.first;
      if (verbose) $display("updateSigmaTableRule vs[0]=%h entryNumber=%d", vs[0], entryNumber);
      sigmoidSourceFunnel.deq();
      Vector#(3,Float) vs3 = take(vs);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].updateSigmoidTable(entryNumber, vs3);
      end
      entryNumber <= entryNumber + 1;
   endrule

   Reg#(Bit#(32)) countInput <- mkReg(0);
   rule consumeInput if (!updatingSigmoidTable);
      let vs = source.pipe.first;
      source.pipe.deq();
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         sigmoidServers[i].request.put(vs[i]);
      end
      if (verbose) $display("consumeInput countInput=%d vs[0]=%h", countInput+1, vs[0]);
      countInput <= countInput + 1;
   endrule

   Reg#(Bit#(32)) count <- mkReg(0);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule enqResult;
      Vector#(n, Float) vs;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         let v <- sigmoidServers[i].response.get();
	 vs[i] = v;
      end
      if (verbose) $display("sigmoid count=%d value=%h", count+1, vs);
      count <= count + 1;
      dfifo.enq(vs);
   endrule

   DmaVectorSink#(TMul#(N,32),Vector#(N,Float)) sinkC <- mkDmaVectorSink(toPipeOut(dfifo));

   rule sourceFinishRule;
      let b <- source.finish();
      if (verbose) $display("sigmoid.source.finish()");
   endrule

   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numvalues);
      source.start(pointerA, 0, pack(numvalues));
      sinkC.vector.start(pointerB, 0, pack(numvalues));
      if (verbose) $display("sigmoid.start numvalues=%d", numvalues);
   endmethod
   method ActionValue#(Bool) finish();
      let b <- sinkC.vector.finish();
      return b;
   endmethod
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].setSigmoidLimits(rscale, llimit, ulimit);
      end
   endmethod
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numvalues);
      entryNumber <= 0;
      updatingSigmoidTable <= True;
      tableSource.start(readPointer, extend(readOffset), 4*extend(numvalues));
   endmethod
   method ActionValue#(Bool) sigmoidTableUpdated();
      if (verbose) $display("tableSource.finish()");
      let b <- tableSource.finish();
      updatingSigmoidTable <= False;
      return b;
   endmethod
   method Bit#(32) tableSize();
      return sigmoidTables[0].tableSize();
   endmethod

   interface ObjectReadClient readClients = cons(dmasource.dmaClient, cons(dmatablesource.dmaClient, nil));
   interface ObjectWriteClient dmaClient = sinkC.dmaClient;

endmodule

import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import FIFOF::*;
import Connectable::*;
import ClientServer::*;
import Memory::*;
import BRAM::*;
import DefaultValue::*;
import FloatingPoint::*;
import Real::*;
import Dma::*;
import DmaVector::*;
import Pipe::*;
import FloatOps::*;
import RbmTypes::*;

interface SigmoidTable#(numeric type tsz);
   interface Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) ports;
   interface ReadOnly#(Float) rscale;
   interface ReadOnly#(Float) llimit;
   interface ReadOnly#(Float) ulimit;
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
   method Bit#(32) tableSize();
endinterface

module mkSigmoidTable(SigmoidTable#(tsz));
   let tsz = valueOf(tsz);
   BRAM_Configure bramCfg = defaultValue;
   let memorySize = 2**tsz;
   bramCfg.memorySize = memorySize;
   BRAM2Port#(Bit#(tsz), Vector#(3, Float)) sigmoidTable <- mkBRAM2Server(bramCfg);

   Reg#(Float) rscaleReg <- mkReg(fromReal(0.0));
   Reg#(Float) llimitReg <- mkReg(fromReal(0.0));
   Reg#(Float) ulimitReg <- mkReg(fromReal(0.0));

   Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) bramPorts;
   bramPorts[0] = sigmoidTable.portA;
   bramPorts[1] = sigmoidTable.portB;

   interface ReadOnly rscale = regToReadOnly(rscaleReg);
   interface ReadOnly llimit = regToReadOnly(llimitReg);
   interface ReadOnly ulimit = regToReadOnly(ulimitReg);
   interface Vector ports = bramPorts;
   method Action setSigmoidLimits(Float _rscale, Float _llimit, Float _ulimit);
      $display("setSigmoidLimits memorySize=%d\n", memorySize);
      rscaleReg <= _rscale;
      llimitReg <= _llimit;
      ulimitReg <= _ulimit;
      $display($format("rscale=", fshow(_rscale), "pack(rscale)=", fshow(pack(_rscale)), " llimit=", fshow(_llimit), " ulimit=", fshow(_ulimit)));
   endmethod
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
      sigmoidTable.portB.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: addr, datain: v});
   endmethod
   method Bit#(32) tableSize();
      return (1 << tsz);
   endmethod
endmodule

module mkSigmoidServer#(SigmoidTable#(tsz) sigmoidTable)(Server#(Float,Float))
   provisos (Add#(tsz,2,usz),
	     Add#(a__, usz, 32)
	     );
   let tsz = valueOf(tsz);
   Int#(usz) numEntries = 1<<fromInteger(tsz);
   // linear approximation around in range [-8,8]

   Bool verbose = False;
   FIFOF#(Float) angleFifo2 <- mkFIFOF();
   FIFOF#(Float) angleFifo <- mkFIFOF();
   let multiplier <- mkFloatMultiplier();
   let adder <- mkFloatAdder();
   let mac <- mkFloatMac();

   rule lookupEntry;
      Float angle = 0;
      if (verbose) begin
	 angle = angleFifo2.first;
	 angleFifo2.deq();
      end
      let response <- multiplier.response.get();
      Float scaled_angle = tpl_1(response);
      Exception e = tpl_2(response);
      if (pack(e) != 0) $display("lookup.exception e=%h scaled_angle=%h", e, pack(scaled_angle));

      Int#(usz) i = truncate(toInt32(scaled_angle));
      Bit#(tsz) index = truncate(pack(i + numEntries/2));
      if (i > (numEntries/2-1))
	 index = truncate(pack(numEntries-1));
      if (i < -numEntries/2)
	 index = 0;
      if (verbose)
	 $display("sigmoid lookupEntry angle=%h i=%d index=%d numEntries=%d", pack(angle), i, index, numEntries);
      sigmoidTable.ports[0].request.put(BRAMRequest{ write: False, responseOnWrite: False, address: index, datain: ?});
   endrule

   FIFOF#(Vector#(3, Float)) vFifo <- mkFIFOF();
   rule computeDelta;
      let vs <- sigmoidTable.ports[0].response.get();
      let angle = angleFifo.first();
      angleFifo.deq();
      if (verbose) $display("computeDelta angle=%h vs[0]=%h", pack(angle), pack(vs[0]));
      adder.request.put(tuple3(angle, vs[0], defaultValue));
      vFifo.enq(vs);
   endrule

   rule interpolate;
      let vs = vFifo.first();
      vFifo.deq();
      let result <- adder.response.get();
      let delta = tpl_1(result);
      Exception e = tpl_2(result);
      if (pack(e) != 0) $display("interpolate.exception e=%h delta=%h", e, pack(delta));
      if (verbose) $display("sigmoid interpolate delta=%h vs[1]=%h vs[2]", pack(delta), pack(vs[1]), pack(vs[2]));
      mac.request.put(tuple4(tagged Valid vs[1], vs[2], delta, defaultValue));
   endrule

   interface Put request;
      method Action put(Float angle);
	 let c = compareFP(angle, sigmoidTable.llimit);
	 let d = compareFP(angle, sigmoidTable.ulimit);
	 if (c == LT)
	    angle = sigmoidTable.llimit;
	 if (d == GT)
	    angle = sigmoidTable.ulimit;
	 if (verbose)
	    angleFifo2.enq(angle);
	 angleFifo.enq(angle);
	 multiplier.request.put(tuple3(angle, sigmoidTable.rscale, defaultValue));
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Float) get();
	 let result <- mac.response.get();
	 let v = tpl_1(result);
	 Exception e = tpl_2(result);
	 if (pack(e) != 0) $display("mac.exception e=%h v=%h", e, pack(v));
	return v;
     endmethod
   endinterface
endmodule

module  mkSigmoid#(SigmoidTable#(tsz) sigmoidTable, PipeOut#(Float) in)(PipeOut#(Float))
   provisos (Add#(a__, TAdd#(tsz, 2), 32));

   let server <- mkSigmoidServer(sigmoidTable);

   FIFOF#(Float) rfifo <- mkFIFOF;
   rule sigmoidOut;
      let sv <- server.response.get();
      rfifo.enq(sv);
   endrule
   mkConnection(in, server.request);
   return toPipeOut(rfifo);
endmodule

interface DmaSigmoidIfc#(numeric type dsz);
   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numElts);
   method ActionValue#(Bool) finish();
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
   method ActionValue#(Bool) sigmoidTableUpdated();
   method Bit#(32) tableSize();

   interface Vector#(2, ObjectReadClient#(dsz)) readClients;
   interface ObjectWriteClient#(dsz) dmaClient;
endinterface

(* synthesize *)
module  mkDmaSigmoid(DmaSigmoidIfc#(dsz))
   provisos (Bits#(Float, fsz)
	     , Add#(N,0,n)
	     , Mul#(fsz,N,dmasz)
	     , Bits#(Vector#(2,Float), dsz)
	     , PipeInOut#(Vector#(2,Float), FIFOF#(Vector#(2,Float)))
	     , Mul#(dbytes, 8, dsz)
	     , Div#(dsz, 8, dbytes)
	     );

   Bool verbose = False;

   DmaVectorSource#(dmasz, Vector#(n,Float)) dmasource <- mkDmaVectorSource();
   DmaVectorSource#(dmasz, Vector#(n,Float)) dmatablesource <- mkDmaVectorSource();
   VectorSource#(dmasz, Vector#(n,Float)) source = dmasource.vector;
   VectorSource#(dmasz, Vector#(n,Float)) tableSource = dmatablesource.vector;

   Vector#(n, SigmoidTable#(6)) sigmoidTables <- replicateM(mkSigmoidTable);
   Vector#(n, Server#(Float,Float)) sigmoidServers;
   for (Integer i = 0; i < valueOf(n); i = i + 1) begin
      let s <- mkSigmoidServer(sigmoidTables[i]);
      sigmoidServers[i] = s;
   end

   Reg#(Bool) updatingSigmoidTable <- mkReg(False);
   Reg#(Bit#(6)) entryNumber <- mkReg(0);

   PipeOut#(Vector#(4, Float)) sigmoidSourceFunnel <- mkUnfunnel(tableSource.pipe);
   rule updateSigmoidTableRule if (updatingSigmoidTable);
      let vs = sigmoidSourceFunnel.first;
      if (verbose) $display("updateSigmaTableRule vs[0]=%h entryNumber=%d", vs[0], entryNumber);
      sigmoidSourceFunnel.deq();
      Vector#(3,Float) vs3 = take(vs);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].updateSigmoidTable(entryNumber, vs3);
      end
      entryNumber <= entryNumber + 1;
   endrule

   Reg#(Bit#(32)) countInput <- mkReg(0);
   rule consumeInput if (!updatingSigmoidTable);
      let vs = source.pipe.first;
      source.pipe.deq();
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         sigmoidServers[i].request.put(vs[i]);
      end
      if (verbose) $display("consumeInput countInput=%d vs[0]=%h", countInput+1, vs[0]);
      countInput <= countInput + 1;
   endrule

   Reg#(Bit#(32)) count <- mkReg(0);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule enqResult;
      Vector#(n, Float) vs;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         let v <- sigmoidServers[i].response.get();
	 vs[i] = v;
      end
      if (verbose) $display("sigmoid count=%d value=%h", count+1, vs);
      count <= count + 1;
      dfifo.enq(vs);
   endrule

   DmaVectorSink#(TMul#(N,32),Vector#(N,Float)) sinkC <- mkDmaVectorSink(toPipeOut(dfifo));

   rule sourceFinishRule;
      let b <- source.finish();
      if (verbose) $display("sigmoid.source.finish()");
   endrule

   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numvalues);
      source.start(pointerA, 0, pack(numvalues));
      sinkC.vector.start(pointerB, 0, pack(numvalues));
      if (verbose) $display("sigmoid.start numvalues=%d", numvalues);
   endmethod
   method ActionValue#(Bool) finish();
      let b <- sinkC.vector.finish();
      return b;
   endmethod
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].setSigmoidLimits(rscale, llimit, ulimit);
      end
   endmethod
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numvalues);
      entryNumber <= 0;
      updatingSigmoidTable <= True;
      tableSource.start(readPointer, extend(readOffset), 4*extend(numvalues));
   endmethod
   method ActionValue#(Bool) sigmoidTableUpdated();
      if (verbose) $display("tableSource.finish()");
      let b <- tableSource.finish();
      updatingSigmoidTable <= False;
      return b;
   endmethod
   method Bit#(32) tableSize();
      return sigmoidTables[0].tableSize();
   endmethod

   interface ObjectReadClient readClients = cons(dmasource.dmaClient, cons(dmatablesource.dmaClient, nil));
   interface ObjectWriteClient dmaClient = sinkC.dmaClient;

endmodule