fix negative slack on malloc module

fix negative slack on malloc module

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

// MemMgmt module handles memory allocation and memory translation

import BuildVector::*;
import Cntrs::*;
import GetPut::*;
import ClientServer::*;
import ConfigCounter::*;
import StmtFSM::*;
import FIFO::*;
import FIFOF::*;
import Pipe::*;
import Vector::*;
import BRAMFIFO::*;
import BRAM::*;
import ConnectalBram::*;
import ConnectalMemory::*;
import MMU::*;
import Ethernet::*;
import SharedBuffMMU::*;
import DbgTypes::*;

typedef enum {
   MemMgmtErrorNone,
   MemMgmtErrorInvalidPacketId,
   MemMgmtErrorOutOfSpace
} MemMgmtErrorType deriving (Bits);

typedef struct {
   MemMgmtErrorType errorType;
   Bit#(32) id;
} MemMgmtError deriving (Bits);

typedef struct {
   Bit#(EtherLen) req;
   Bit#(TLog#(TMax#(1, numClients))) clients;
} MemMgmtAllocReq#(numeric type numClients) deriving (Bits);

typedef struct {
   Maybe#(PktId) id;
   Bit#(TLog#(TMax#(1, numClients))) clients;
} MemMgmtAllocResp#(numeric type numClients) deriving (Bits);

typedef struct {
   PktId id;
   Bit#(TLog#(TMax#(1, numClients))) clients;
} MemMgmtFreeReq#(numeric type numClients) deriving (Bits);

interface MemMgmtIndication;
   method Action memory_allocated(Bit#(32) id);
   method Action packet_committed(Bit#(32) tag);
   method Action packet_freed(Bit#(32) tag);
   method Action error(Bit#(32) errorType, Bit#(32) id);
endinterface

typedef 8  PageAddrLen; // 2^8 = 256 byte page
typedef 16 MemoryAddrLen; // 2^16 = 65536 byte packet buffer
typedef TExp#(PageAddrLen) PageSize; // 256
typedef TSub#(MemoryAddrLen, PageAddrLen) PageIdx; // 8-bit index
typedef TExp#(PageIdx) FreeQueueDepth; // 256 pages

Integer pageIdx = valueOf(PageIdx);
Integer freeQueueDepth = valueOf(FreeQueueDepth);

/* Terminate MMUIndication.idResponse, because sending it to sw is slow*/
interface MMUIndicationProxy;
   interface MMUIndication mmuInd;
   interface Get#(Bit#(32)) idResponse;
endinterface
module mkMMUIndicationProxy
`ifdef DEBUG
                           #(MMUIndication mmuInd)
`endif
                           (MMUIndicationProxy);
   FIFO#(Bit#(32)) idresponse_fifo <- mkFIFO;
   interface MMUIndication mmuInd;
      method Action idResponse(Bit#(32) sglId);
         idresponse_fifo.enq(sglId);
      endmethod
`ifdef DEBUG
      method configResp = mmuInd.configResp;
      method error = mmuInd.error;
`endif
   endinterface
   interface Get idResponse = toGet(idresponse_fifo);
endmodule

typedef struct {
   Bit#(PageIdx) nPages;
   MemMgmtAllocReq#(numAllocClients) request;
   Bit#(EtherLen) mask;
   Bit#(32) id;
} Stage2Params#(numeric type numAllocClients) deriving (Bits);

interface MemMgmt#(numeric type addrWidth, numeric type numAllocClients, numeric type numReadClients);
   method Action init_mem();
   interface MMU#(addrWidth) mmu;
   interface Put#(MemMgmtAllocReq#(numAllocClients)) mallocReq;
   interface Get#(MemMgmtAllocResp#(numAllocClients)) mallocDone;
   interface Put#(MemMgmtFreeReq#(numReadClients)) freeReq;
   interface Get#(Bool) freeDone;
   method MemMgmtDbgRec dbg;
endinterface
module mkMemMgmt
`ifdef DEBUG
                #(MemMgmtIndication indication, MMUIndication mmuInd)
`endif
                (MemMgmt#(addrWidth, numAllocClients, numReadClients))
   provisos(Add#(a__, addrWidth, 44));
   let verbose = False;

   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule cycleRule if (verbose);
      cycle <= cycle + 1;
   endrule

   Reg#(Bit#(64)) allocCnt <- mkReg(0);
   Reg#(Bit#(64)) allocCompleted <- mkReg(0);
   Reg#(Bit#(64)) freeCnt <- mkReg(0);
   Reg#(Bit#(64)) freeCompleted <- mkReg(0);
   Reg#(Bit#(64)) errorCode <- mkReg(0);
   Reg#(Bit#(64)) lastIdFreed <- mkReg(0);
   Reg#(Bit#(64)) lastIdAllocated <- mkReg(0);
   Reg#(Bit#(64)) firstSegment <- mkReg(0);
   Reg#(Bool) invalidSegment <- mkReg(False);

   Reg#(Bool) inited <- mkReg(False);
   FIFOF#(MemMgmtAllocReq#(numAllocClients)) mallcRequestFifo <- mkSizedFIFOF(16);
   FIFO#(MemMgmtAllocReq#(numAllocClients)) currRequestFIfo <- mkFIFO;
   FIFO#(MemMgmtAllocResp#(numAllocClients)) mallocDoneFifo <- mkFIFO;
   FIFOF#(PktId) freeRequestFifo <- mkFIFOF;

   FIFOF#(Bit#(PageIdx)) freePageList <- mkSizedFIFOF(freeQueueDepth);

   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   // Store mapping from packetId to first page in linked list
   // PortA
   BRAM2Port#(PktId, Maybe#(Bit#(PageIdx))) idmap <- mkBRAM2Server(bramConfig);
   // Pack linked list of pages into BRAM for free operation
   // BRAM is indiced with pageIdx, and each entry in BRAM stores
   // a Maybe#(pageIdx) for next entry in the same list.
   // Entry is Invalid for last entry in a list
   BRAM2Port#(Bit#(PageIdx), Maybe#(Bit#(PageIdx))) pagemap <- mkBRAM2Server(bramConfig);

   Reg#(Bit#(PageIdx)) reqBurstLen <- mkReg(0);
   Reg#(Bit#(PageIdx)) reqSglIndex<- mkReg(0);
   ConfigCounter#(PageIdx) freePageCount <- mkConfigCounter(0);
   Reg#(Bool) free_started <- mkReg(False);
   Reg#(Maybe#(Bit#(PageIdx))) lastSegment <- mkReg(tagged Invalid);
   Reg#(PktId) idToFree <- mkReg(0);
   Reg#(Bit#(PageIdx)) currSegment <- mkReg(0);

   Reg#(PktId) packetId <- mkReg(0);
   Reg#(Bit#(64)) barr0 <- mkReg(0);

   FIFO#(Bool) freeDoneFifo <- mkFIFO;
   FIFO#(MemMgmtError) memMgmtErrorFifo <- mkFIFO;
   FIFO#(Bit#(PageIdx)) pagePointerFifo <- mkFIFO;

   FIFOF#(Stage2Params#(numAllocClients)) stage2Params <- mkFIFOF;

   MMUIndicationProxy proxy <- mkMMUIndicationProxy(
`ifdef DEBUG
                                                    mmuInd
`endif
                                                   );
   MMU#(addrWidth) iommu <- mkSharedBuffMMU(0, proxy.mmuInd);

   function BRAMServer#(a,b) portsel(BRAM2Port#(a,b) x, Integer i);
      if(i==0) return x.portA;
      else return x.portB;
   endfunction

   rule initialization if (!inited);
      freePageList.enq(pack(freePageCount.read));
      if (freePageCount.read == fromInteger(freeQueueDepth-1)) begin
         inited <= True;
         $display("Init: freePageCount %h", freePageCount.read);
      end
      else begin
         // NOTE: maximum freeQueueDepth-1
         freePageCount.increment(1);
      end
   endrule

   // assign available pages to packet id.
   rule handle_alloc_req;
      let v <- toGet(mallcRequestFifo).get;
      let id <- proxy.idResponse.get;
      $display("MemMgmt:: %d Allocating pages for packet id %d packet size %d", cycle, id, v.req);
      // Corner case when v is close to 4kb.
      let mask = (1 << valueOf(PageAddrLen)) - 1;
      Bit#(PageIdx) nPages = truncate(((v.req + mask) & (~mask)) >> valueOf(PageAddrLen));
      $display("MemMgmt:: %d handle_malloc allocate nPage=%d", cycle, nPages);
      let hasSpace <- freePageCount.maybeDecrement(unpack(nPages));
      if (hasSpace) begin
         stage2Params.enq(Stage2Params{
            nPages : nPages,
            request : v,
            mask : mask,
            id : id });
      end
   endrule

   rule handle_alloc_req2;
      let params <- toGet(stage2Params).get;
      reqBurstLen <= params.nPages;
      reqSglIndex <= 0;
      lastSegment <= tagged Invalid;
      barr0 <= extend(((params.request.req + params.mask) & (~params.mask)) >> valueOf(PageAddrLen));
      packetId <= truncate(params.id); // MaxNumPkts defined in SharedBuffMMU;
      currRequestFIfo.enq(params.request);
   endrule

   rule generate_sglist if (reqBurstLen > 0);
      let segment <- toGet(freePageList).get;
      // assume fixed page size of 256 bytes
      // extend packetId to 32 bit, only lower TLog#(MaxNumPkts) bits are used
      iommu.request.sglist(extend(packetId), extend(reqSglIndex), extend(segment), 256);
      // add current page(segment) to the front of a linked list
      portsel(pagemap, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:segment, datain: lastSegment});
      reqBurstLen <= reqBurstLen - 1;
      reqSglIndex <= reqSglIndex + 1;
      lastSegment <= tagged Valid segment;
      if (reqBurstLen == 1) begin
         iommu.request.region(extend(packetId), 0, 0, 0, 0, 0, 0, barr0, 0);
         // map id to linked-list of pages
         portsel(idmap, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:packetId, datain:tagged Valid segment});
         mallocDoneFifo.enq(MemMgmtAllocResp{id: tagged Valid packetId, clients: currRequestFIfo.first.clients});
         currRequestFIfo.deq;
         allocCompleted <= allocCompleted + 1;
         lastIdAllocated <= extend(packetId);
`ifdef DEBUG
         indication.memory_allocated(extend(packetId));
`endif
      end
      $display("MemMgmt:: %d id=%d, segmentIdx=%x %h", cycle, packetId, segment, lastSegment);
   endrule

   rule handle_free_req if (!free_started);
      let sglId <- toGet(freeRequestFifo).get;
      free_started <= True;
      portsel(idmap, 1).request.put(BRAMRequest{write:False, responseOnWrite:False, address:sglId, datain:?});
      idToFree <= sglId;
      if (verbose) $display("MemMgmt:: %d start_free_sglist %h", cycle, sglId);
      lastIdFreed <= extend(sglId);
   endrule

   rule report_error;
      let v <- toGet(memMgmtErrorFifo).get;
`ifdef DEBUG
      indication.error(extend(pack(v.errorType)), v.id);
`endif
      if (verbose) $display("MemMgmt:: %d free_error: memMgmt error", cycle);
   endrule

   rule del_id_metadata if (free_started);
      Maybe#(Bit#(PageIdx)) segment <- portsel(idmap, 1).response.get;
      case (segment) matches
         tagged Valid .page: begin
            portsel(idmap, 1).request.put(BRAMRequest{write:True, responseOnWrite:False, address: idToFree, datain: tagged Invalid});
            portsel(pagemap, 1).request.put(BRAMRequest{write:False, responseOnWrite:False, address: page, datain:?});
            $display("MemMgmt:: %d free_idmap ", cycle, fshow(page));
            currSegment <= page;
         end
         tagged Invalid: begin
            memMgmtErrorFifo.enq(MemMgmtError{errorType: MemMgmtErrorInvalidPacketId, id: extend(idToFree)});
            invalidSegment <= True;
         end
      endcase
      firstSegment <= extend(pack(segment));
   endrule

   rule del_page_metadata if (free_started);
      Maybe#(Bit#(PageIdx)) segment <- portsel(pagemap, 1).response.get;
      case (segment) matches
         tagged Valid .page: begin
            currSegment <= page;
            pagePointerFifo.enq(page);
         end
         tagged Invalid: begin
            free_started <= False;
            freeCompleted <= freeCompleted + 1;
`ifdef DEBUG
            indication.packet_freed(extend(idToFree));
`endif
         end
      endcase
      // return current page to free page list
      portsel(pagemap, 1).request.put(BRAMRequest{write:True, responseOnWrite:False, address: currSegment, datain: tagged Invalid});
      freePageList.enq(currSegment);
      freePageCount.increment(1);
      if (verbose) $display("MemMgmt:: %d segment ", cycle, fshow(segment));
   endrule

   rule read_next_page_metadata if (free_started);
      let page <- toGet(pagePointerFifo).get;
      portsel(pagemap, 1).request.put(BRAMRequest{write:False, responseOnWrite:False, address:page, datain:?});
      if (verbose) $display("MemMgmt:: %d read next page ", cycle, fshow(page));
   endrule

   method Action init_mem();
      freePageList.clear;
      freePageCount.decrement(freePageCount.read);
      inited <= False;
   endmethod
   interface Put mallocReq;
      method Action put(MemMgmtAllocReq#(numAllocClients) req);
         $display("MemMgmt:: %d req page=%d", cycle, freePageCount.read);
         mallcRequestFifo.enq(req);
         iommu.request.idRequest(0); //FIXME
         allocCnt <= allocCnt + 1;
      endmethod
   endinterface
   interface Get mallocDone = toGet(mallocDoneFifo);
   interface Put freeReq;
      method Action put(MemMgmtFreeReq#(numReadClients) req);
         $display("MemMgmt:: %d free request %h", cycle, req.id);
         iommu.request.idReturn(extend(req.id));
         freeRequestFifo.enq(req.id);
         freeCnt <= freeCnt + 1;
      endmethod
   endinterface
   interface Get freeDone = toGet(freeDoneFifo);
   interface MMU mmu = iommu;
   method MemMgmtDbgRec dbg;
      return MemMgmtDbgRec { allocCnt: allocCnt
                            ,freeCnt: freeCnt
                            ,allocCompleted: allocCompleted
                            ,freeCompleted: freeCompleted
                            ,errorCode: errorCode
                            ,lastIdFreed: lastIdFreed
                            ,lastIdAllocated: lastIdAllocated
                            ,freeStarted: extend(pack(free_started))
                            ,firstSegment: extend(firstSegment)
                            ,lastSegment: extend(pack(lastSegment))
                            ,currSegment: extend(currSegment)
                            ,invalidSegment: extend(pack(invalidSegment))};
   endmethod
endmodule

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

// MemMgmt module handles memory allocation and memory translation

import BuildVector::*;
import Cntrs::*;
import GetPut::*;
import ClientServer::*;
import ConfigCounter::*;
import StmtFSM::*;
import FIFO::*;
import FIFOF::*;
import Pipe::*;
import Vector::*;
import BRAMFIFO::*;
import BRAM::*;
import ConnectalBram::*;
import ConnectalMemory::*;
import MMU::*;
import Ethernet::*;
import SharedBuffMMU::*;
import DbgTypes::*;

typedef enum {
   MemMgmtErrorNone,
   MemMgmtErrorInvalidPacketId,
   MemMgmtErrorOutOfSpace
} MemMgmtErrorType deriving (Bits);

typedef struct {
   MemMgmtErrorType errorType;
   Bit#(32) id;
} MemMgmtError deriving (Bits);

typedef struct {
   Bit#(EtherLen) req;
   Bit#(TLog#(TMax#(1, numClients))) clients;
} MemMgmtAllocReq#(numeric type numClients) deriving (Bits);

typedef struct {
   Maybe#(PktId) id;
   Bit#(TLog#(TMax#(1, numClients))) clients;
} MemMgmtAllocResp#(numeric type numClients) deriving (Bits);

typedef struct {
   PktId id;
   Bit#(TLog#(TMax#(1, numClients))) clients;
} MemMgmtFreeReq#(numeric type numClients) deriving (Bits);

interface MemMgmtIndication;
   method Action memory_allocated(Bit#(32) id);
   method Action packet_committed(Bit#(32) tag);
   method Action packet_freed(Bit#(32) tag);
   method Action error(Bit#(32) errorType, Bit#(32) id);
endinterface

typedef 8  PageAddrLen; // 2^8 = 256 byte page
typedef 16 MemoryAddrLen; // 2^16 = 65536 byte packet buffer
typedef TExp#(PageAddrLen) PageSize; // 256
typedef TSub#(MemoryAddrLen, PageAddrLen) PageIdx; // 8-bit index
typedef TExp#(PageIdx) FreeQueueDepth; // 256 pages

Integer pageIdx = valueOf(PageIdx);
Integer freeQueueDepth = valueOf(FreeQueueDepth);

/* Terminate MMUIndication.idResponse, because sending it to sw is slow*/
interface MMUIndicationProxy;
   interface MMUIndication mmuInd;
   interface Get#(Bit#(32)) idResponse;
endinterface
module mkMMUIndicationProxy
`ifdef DEBUG
                           #(MMUIndication mmuInd)
`endif
                           (MMUIndicationProxy);
   FIFO#(Bit#(32)) idresponse_fifo <- mkFIFO;
   interface MMUIndication mmuInd;
      method Action idResponse(Bit#(32) sglId);
         idresponse_fifo.enq(sglId);
      endmethod
`ifdef DEBUG
      method configResp = mmuInd.configResp;
      method error = mmuInd.error;
`endif
   endinterface
   interface Get idResponse = toGet(idresponse_fifo);
endmodule

interface MemMgmt#(numeric type addrWidth, numeric type numAllocClients, numeric type numReadClients);
   method Action init_mem();
   interface MMU#(addrWidth) mmu;
   interface Put#(MemMgmtAllocReq#(numAllocClients)) mallocReq;
   interface Get#(MemMgmtAllocResp#(numAllocClients)) mallocDone;
   interface Put#(MemMgmtFreeReq#(numReadClients)) freeReq;
   interface Get#(Bool) freeDone;
   method MemMgmtDbgRec dbg;
endinterface
module mkMemMgmt
`ifdef DEBUG
                #(MemMgmtIndication indication, MMUIndication mmuInd)
`endif
                (MemMgmt#(addrWidth, numAllocClients, numReadClients))
   provisos(Add#(a__, addrWidth, 44));
   let verbose = False;

   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule cycleRule if (verbose);
      cycle <= cycle + 1;
   endrule

   Reg#(Bit#(64)) allocCnt <- mkReg(0);
   Reg#(Bit#(64)) allocCompleted <- mkReg(0);
   Reg#(Bit#(64)) freeCnt <- mkReg(0);
   Reg#(Bit#(64)) freeCompleted <- mkReg(0);
   Reg#(Bit#(64)) errorCode <- mkReg(0);
   Reg#(Bit#(64)) lastIdFreed <- mkReg(0);
   Reg#(Bit#(64)) lastIdAllocated <- mkReg(0);
   Reg#(Bit#(64)) firstSegment <- mkReg(0);
   Reg#(Bool) invalidSegment <- mkReg(False);

   Reg#(Bool) inited <- mkReg(False);
   FIFO#(MemMgmtAllocReq#(numAllocClients)) mallcRequestFifo <- mkSizedFIFO(16);
   FIFO#(MemMgmtAllocReq#(numAllocClients)) currRequestFIfo <- mkFIFO;
   FIFO#(MemMgmtAllocResp#(numAllocClients)) mallocDoneFifo <- mkFIFO;
   FIFOF#(PktId) freeRequestFifo <- mkFIFOF;

   FIFOF#(Bit#(PageIdx)) freePageList <- mkSizedFIFOF(freeQueueDepth);

   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   // Store mapping from packetId to first page in linked list
   // PortA
   BRAM2Port#(PktId, Maybe#(Bit#(PageIdx))) idmap <- mkBRAM2Server(bramConfig);
   // Pack linked list of pages into BRAM for free operation
   // BRAM is indiced with pageIdx, and each entry in BRAM stores
   // a Maybe#(pageIdx) for next entry in the same list.
   // Entry is Invalid for last entry in a list
   BRAM2Port#(Bit#(PageIdx), Maybe#(Bit#(PageIdx))) pagemap <- mkBRAM2Server(bramConfig);

   Reg#(Bit#(PageIdx)) reqBurstLen <- mkReg(0);
   Reg#(Bit#(PageIdx)) reqSglIndex<- mkReg(0);
   ConfigCounter#(PageIdx) freePageCount <- mkConfigCounter(0);
   Reg#(Bool) free_started <- mkReg(False);
   Reg#(Maybe#(Bit#(PageIdx))) lastSegment <- mkReg(tagged Invalid);
   Reg#(PktId) idToFree <- mkReg(0);
   Reg#(Bit#(PageIdx)) currSegment <- mkReg(0);

   Reg#(PktId) packetId <- mkReg(0);
   Reg#(Bit#(64)) barr0 <- mkReg(0);

   FIFO#(Bool) freeDoneFifo <- mkFIFO;
   FIFO#(MemMgmtError) memMgmtErrorFifo <- mkFIFO;
   FIFO#(Bit#(PageIdx)) pagePointerFifo <- mkFIFO;

   MMUIndicationProxy proxy <- mkMMUIndicationProxy(
`ifdef DEBUG
                                                    mmuInd
`endif
                                                   );
   MMU#(addrWidth) iommu <- mkSharedBuffMMU(0, proxy.mmuInd);

   function BRAMServer#(a,b) portsel(BRAM2Port#(a,b) x, Integer i);
      if(i==0) return x.portA;
      else return x.portB;
   endfunction

   rule initialization if (!inited);
      freePageList.enq(pack(freePageCount.read));
      if (freePageCount.read == fromInteger(freeQueueDepth-1)) begin
         inited <= True;
         $display("Init: freePageCount %h", freePageCount.read);
      end
      else begin
         // NOTE: maximum freeQueueDepth-1
         freePageCount.increment(1);
      end
   endrule

   // assign available pages to packet id.
   rule handle_alloc_req;
      let v <- toGet(mallcRequestFifo).get;
      let id <- proxy.idResponse.get;
      $display("MemMgmt:: %d Allocating pages for packet id %d packet size %d", cycle, id, v.req);
      // Corner case when v is close to 4kb.
      let mask = (1 << valueOf(PageAddrLen)) - 1;
      Bit#(PageIdx) nPages = truncate(((v.req + mask) & (~mask)) >> valueOf(PageAddrLen));
      $display("MemMgmt:: %d handle_malloc allocate nPage=%d", cycle, nPages);
      let hasSpace <- freePageCount.maybeDecrement(unpack(nPages));
      if (hasSpace) begin
         reqBurstLen <= nPages;
         reqSglIndex <= 0;
         lastSegment <= tagged Invalid;
         barr0 <= extend(((v.req + mask) & (~mask)) >> valueOf(PageAddrLen));
         packetId <= truncate(id); // MaxNumPkts defined in SharedBuffMMU;
         currRequestFIfo.enq(v);
      end
      else begin
         $display("Error:: insufficient space %d instead of %d", freePageCount.read, nPages);
         mallocDoneFifo.enq(MemMgmtAllocResp{id: tagged Invalid, clients: v.clients});
         errorCode <= extend(pack(MemMgmtErrorOutOfSpace));
      end
   endrule

   rule generate_sglist if (reqBurstLen > 0);
      let segment <- toGet(freePageList).get;
      // assume fixed page size of 256 bytes
      // extend packetId to 32 bit, only lower TLog#(MaxNumPkts) bits are used
      iommu.request.sglist(extend(packetId), extend(reqSglIndex), extend(segment), 256);
      // add current page(segment) to the front of a linked list
      portsel(pagemap, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:segment, datain: lastSegment});
      reqBurstLen <= reqBurstLen - 1;
      reqSglIndex <= reqSglIndex + 1;
      lastSegment <= tagged Valid segment;
      if (reqBurstLen == 1) begin
         iommu.request.region(extend(packetId), 0, 0, 0, 0, 0, 0, barr0, 0);
         // map id to linked-list of pages
         portsel(idmap, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:packetId, datain:tagged Valid segment});
         mallocDoneFifo.enq(MemMgmtAllocResp{id: tagged Valid packetId, clients: currRequestFIfo.first.clients});
         currRequestFIfo.deq;
         allocCompleted <= allocCompleted + 1;
         lastIdAllocated <= extend(packetId);
`ifdef DEBUG
         indication.memory_allocated(extend(packetId));
`endif
      end
      $display("MemMgmt:: %d id=%d, segmentIdx=%x %h", cycle, packetId, segment, lastSegment);
   endrule

   rule handle_free_req if (!free_started);
      let sglId <- toGet(freeRequestFifo).get;
      free_started <= True;
      portsel(idmap, 1).request.put(BRAMRequest{write:False, responseOnWrite:False, address:sglId, datain:?});
      idToFree <= sglId;
      if (verbose) $display("MemMgmt:: %d start_free_sglist %h", cycle, sglId);
      lastIdFreed <= extend(sglId);
   endrule

   rule report_error;
      let v <- toGet(memMgmtErrorFifo).get;
`ifdef DEBUG
      indication.error(extend(pack(v.errorType)), v.id);
`endif
      if (verbose) $display("MemMgmt:: %d free_error: memMgmt error", cycle);
   endrule

   rule del_id_metadata if (free_started);
      Maybe#(Bit#(PageIdx)) segment <- portsel(idmap, 1).response.get;
      case (segment) matches
         tagged Valid .page: begin
            portsel(idmap, 1).request.put(BRAMRequest{write:True, responseOnWrite:False, address: idToFree, datain: tagged Invalid});
            portsel(pagemap, 1).request.put(BRAMRequest{write:False, responseOnWrite:False, address: page, datain:?});
            $display("MemMgmt:: %d free_idmap ", cycle, fshow(page));
            currSegment <= page;
         end
         tagged Invalid: begin
            memMgmtErrorFifo.enq(MemMgmtError{errorType: MemMgmtErrorInvalidPacketId, id: extend(idToFree)});
            invalidSegment <= True;
         end
      endcase
      firstSegment <= extend(pack(segment));
   endrule

   rule del_page_metadata if (free_started);
      Maybe#(Bit#(PageIdx)) segment <- portsel(pagemap, 1).response.get;
      case (segment) matches
         tagged Valid .page: begin
            currSegment <= page;
            pagePointerFifo.enq(page);
         end
         tagged Invalid: begin
            free_started <= False;
            freeCompleted <= freeCompleted + 1;
`ifdef DEBUG
            indication.packet_freed(extend(idToFree));
`endif
         end
      endcase
      // return current page to free page list
      portsel(pagemap, 1).request.put(BRAMRequest{write:True, responseOnWrite:False, address: currSegment, datain: tagged Invalid});
      freePageList.enq(currSegment);
      freePageCount.increment(1);
      if (verbose) $display("MemMgmt:: %d segment ", cycle, fshow(segment));
   endrule

   rule read_next_page_metadata if (free_started);
      let page <- toGet(pagePointerFifo).get;
      portsel(pagemap, 1).request.put(BRAMRequest{write:False, responseOnWrite:False, address:page, datain:?});
      if (verbose) $display("MemMgmt:: %d read next page ", cycle, fshow(page));
   endrule

   method Action init_mem();
      freePageList.clear;
      freePageCount.decrement(freePageCount.read);
      inited <= False;
   endmethod
   interface Put mallocReq;
      method Action put(MemMgmtAllocReq#(numAllocClients) req);
         $display("MemMgmt:: %d req page=%d", cycle, freePageCount.read);
         mallcRequestFifo.enq(req);
         iommu.request.idRequest(0); //FIXME
         allocCnt <= allocCnt + 1;
      endmethod
   endinterface
   interface Get mallocDone = toGet(mallocDoneFifo);
   interface Put freeReq;
      method Action put(MemMgmtFreeReq#(numReadClients) req);
         $display("MemMgmt:: %d free request %h", cycle, req.id);
         iommu.request.idReturn(extend(req.id));
         freeRequestFifo.enq(req.id);
         freeCnt <= freeCnt + 1;
      endmethod
   endinterface
   interface Get freeDone = toGet(freeDoneFifo);
   interface MMU mmu = iommu;
   method MemMgmtDbgRec dbg;
      return MemMgmtDbgRec { allocCnt: allocCnt
                            ,freeCnt: freeCnt
                            ,allocCompleted: allocCompleted
                            ,freeCompleted: freeCompleted
                            ,errorCode: errorCode
                            ,lastIdFreed: lastIdFreed
                            ,lastIdAllocated: lastIdAllocated
                            ,freeStarted: extend(pack(free_started))
                            ,firstSegment: extend(firstSegment)
                            ,lastSegment: extend(pack(lastSegment))
                            ,currSegment: extend(currSegment)
                            ,invalidSegment: extend(pack(invalidSegment))};
   endmethod
endmodule


Revert "simplify Bscan"

Revert "simplify Bscan"

This reverts commit 534b5ec27b67df9d6a460cef2ed44e8f644bb3d6.

// 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 FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

interface Bscan#(numeric type width);
   interface Put#(Bit#(width)) capture;
   interface Get#(Bit#(width)) update;
endinterface

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

module mkBscan#(Integer bus)(Bscan#(width));
   let width = valueOf(width);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
       // SEL := (IR == 'USERx')
       // CAPTURE, RESET, RUNTEST, SHIFT, UPDATE: <name> := (TAP_state == <name>-DR)
       // TCK, TDI, TDO := corresponding JTAG pins
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);

   Reg#(Bit#(width)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   SyncFIFOIfc#(Bit#(width)) infifo <- mkSyncFIFO(2, defaultClock, defaultReset, tck);
   SyncFIFOIfc#(Bit#(width)) outfifo <- mkSyncFIFO(2, tck, rst, defaultClock);
   Wire#(Bit#(1)) tdow <- mkDWire(0, clocked_by tck, reset_by rst);
   rule tdo;
      bscan.tdo(tdow);
   endrule

   rule captureRule if (bscan.capture() == 1 && bscan.sel() == 1);
      if (infifo.notEmpty()) begin
	 infifo.deq();
      end
      //else
      //shiftReg <= 0;
   endrule
   rule shift if (bscan.shift() == 1 && bscan.sel() == 1);
      tdow <= shiftReg[0];
      let v = (shiftReg >> 1);
      v[width-1] = bscan.tdi();
      shiftReg <= v;
   endrule
   rule updateRule if (bscan.update() == 1 && bscan.sel() == 1);
      //if (outfifo.notFull()) begin
      //outfifo.enq(shiftReg);
      //end
   endrule

   interface Put capture = toPut(infifo);
   interface Get update = toGet(outfifo);
endmodule

interface BscanBram#(type atype, type dtype);
   interface Clock jtagClock;
   interface Reset jtagReset;
   interface BRAMClient#(atype, dtype) bramClient;
   method Bit#(4) debug;
endinterface

module mkBscanBram#(Integer bus, atype addr)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);
   SyncBitIfc#(Bit#(asz)) addr_jtag <- mkSyncBits(0, defaultClock, defaultReset, tck, rst);
   Wire#(Maybe#(BRAMRequest#(atype, dtype))) requestWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);
   Wire#(Maybe#(dtype)) responseWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(asz)) addrReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bool) capture_delay <- mkReg(False, clocked_by tck, reset_by rst);
   Reg#(Bool) selected_delay <- mkReg(False, clocked_by tck, reset_by rst);
   Wire#(Bit#(1)) tdow <- mkDWire(0, clocked_by tck, reset_by rst);
   rule tdo;
      bscan.tdo(tdow);
   endrule

   rule selected_rule;
       selected_delay <= bscan.sel() == 1;
       capture_delay <= bscan.sel() == 1 && bscan.capture() == 1;
   endrule

   rule addr_clock_crossing;
       addr_jtag.send(pack(addr));
   endrule

   rule captureRule if (bscan.sel() == 1 && bscan.capture() == 1);
       requestWire <= tagged Valid BRAMRequest {write:False, responseOnWrite:False, address:unpack(addrReg), datain:?};
   endrule

   rule shiftrule if (bscan.sel() == 1 && bscan.shift() == 1);
       Bit#(dsz) shift = shiftReg;
       if (capture_delay) begin
	  Maybe#(dtype) m = responseWire;
	  let d = fromMaybe(unpack(0), m);
	  shift = pack(d);
       end
       tdow <= shift[0];
       let v = (shift >> 1);
       v[dsz-1] = bscan.tdi();
       shiftReg <= v;
   endrule

   rule updateRule if (bscan.sel() == 1 && bscan.update() == 1 && bscan.capture() == 0);
       requestWire <= tagged Valid (BRAMRequest {write:True, responseOnWrite:False, address:unpack(addrReg), datain:unpack(shiftReg)});
       let addr = addrReg + 1;
       if (!selected_delay)
	  addr = 0;  // first time USER1 selected, reset address
       addrReg <= addr;
   endrule

   method Bit#(4) debug;
       return {bscan.sel(), bscan.capture(), bscan.shift(), bscan.update()};
   endmethod
   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (requestWire matches tagged Valid .req);
	    return req;
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
	    responseWire <= tagged Valid d;
	 endmethod
      endinterface
   endinterface
   interface Clock jtagClock = tck;
   interface Reset jtagReset = rst;
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 FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

interface BscanBram#(type atype, type dtype);
   interface Clock jtagClock;
   interface Reset jtagReset;
   interface BRAMClient#(atype, dtype) bramClient;
endinterface

module mkBscanBram#(Integer bus, atype addr)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz), Add#(1, a__, dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   //Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);
   //SyncBitIfc#(Bit#(asz)) addr_jtag <- mkSyncBits(0, defaultClock, defaultReset, tck, rst);
   Wire#(Maybe#(BRAMRequest#(atype, dtype))) requestWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);
   Wire#(Maybe#(dtype)) responseWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(asz)) addrReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bool) capture_delay <- mkReg(False, clocked_by tck, reset_by rst);
   Reg#(Bool) selected_delay <- mkReg(False, clocked_by tck, reset_by rst);
   rule tdo;
       bscan.tdo(shiftReg[0]);
   endrule

   rule selected_rule;
       selected_delay <= bscan.sel() == 1;
       capture_delay <= bscan.sel() == 1 && bscan.capture() == 1;
   endrule

   //rule addr_clock_crossing;
       //addr_jtag.send(pack(addr));
   //endrule

   rule captureRule if (bscan.sel() == 1 && bscan.capture() == 1);
       requestWire <= tagged Valid BRAMRequest {write:False, responseOnWrite:False, address:unpack(addrReg), datain:?};
   endrule

   rule shiftrule if (bscan.sel() == 1 && bscan.shift() == 1);
       Bit#(dsz) shift = shiftReg;
       if (capture_delay) begin
	  Maybe#(dtype) m = responseWire;
	  let d = fromMaybe(unpack(0), m);
	  shift = pack(d);
       end
       shiftReg <= {bscan.tdi(), shift[dsz-1:1]};
   endrule

   rule updateRule if (bscan.sel() == 1 && bscan.update() == 1 && bscan.capture() == 0);
       requestWire <= tagged Valid (BRAMRequest {write:True, responseOnWrite:False, address:unpack(addrReg), datain:unpack(shiftReg)});
       let addr = addrReg + 1;
       if (!selected_delay)
	  addr = 0;  // first time USER1 selected, reset address
       addrReg <= addr;
   endrule

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (requestWire matches tagged Valid .req);
	    return req;
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
	    responseWire <= tagged Valid d;
	 endmethod
      endinterface
   endinterface
   interface Clock jtagClock = tck;
   interface Reset jtagReset = rst;
endmodule


Incremented Directory version to 2 because portal layout changed.

// Copyright (c) 2013-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 FIFO::*;
import FIFOF::*;
import RegFile::*;
import SpecialFIFOs::*;
import GetPut::*;
import BRAM::*;
import Assert::*;

//portz libraries
import Portal::*;
import MemTypes::*;
import Ctrl2BRAM::*;

interface Directory#(numeric type _n,
		     numeric type _a,
		     numeric type _d);
   interface MemPortal#(_a,_d) portalIfc;
endinterface

typedef Directory#(16,16,32) StdDirectory;

typedef 6 StartDirectoryOffset;

module mkStdDirectoryPortalIfc#(BRAMServer#(Bit#(16), Bit#(32)) br)(StdPortal);
   MemSlave#(16,32) ctrl <- mkCtrl2BRAM(br);
   method Bit#(32) ifcId();
      return 0;
   endmethod
   method Bit#(32) ifcType();
      return 0;
   endmethod
   interface MemSlave slave = ctrl;
   interface ReadOnly interrupt;
      method Bool _read;
	 return False;
      endmethod
   endinterface
endmodule

module mkStdDirectory#(Vector#(n,StdPortal) portals) (StdDirectory);

   Reg#(Bit#(64)) cycle_count <- mkReg(0);
   Reg#(Bit#(32))    snapshot <- mkReg(0);
   FIFOF#(Bit#(16))  addrFifo <- mkSizedFIFOF(1);
   FIFO#(Bit#(32))   dataFifo <- mkSizedFIFO(1);
   let startDirectoryOffset=valueOf(StartDirectoryOffset);

   let base = 128;

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   rule req1;
      let addr = addrFifo.first;
      addrFifo.deq;
      let idx = (addr-fromInteger(startDirectoryOffset)-base);
      if (idx[0] == 0)
	 dataFifo.enq(portals[idx>>1].ifcId);
      else
	 dataFifo.enq(portals[idx>>1].ifcType);
   endrule

   let br = (interface BRAMServer#(Bit#(16), Bit#(32));
		interface Put request;
		   method Action put(BRAMRequest#(Bit#(16),Bit#(32)) req) if (!addrFifo.notEmpty);
		      if (!req.write) begin
      			 if (req.address == 0+base)
			    dataFifo.enq(2); // directory version
			 else if (req.address == 1+base)
			    dataFifo.enq(`TimeStamp);
			 else if (req.address == 2+base)
			    dataFifo.enq(fromInteger(valueOf(n)));
			 else if (req.address == 3+base)
			    dataFifo.enq(16); // portal Addr bits
			 else if (req.address == 4+base) begin
			    snapshot <= truncate(cycle_count);
			    dataFifo.enq(cycle_count[63:32]);
			 end
			 else if (req.address == 5+base)
			    dataFifo.enq(snapshot);
			 else if (req.address == 6+base) // portal layout version
			    dataFifo.enq(2);
			 else begin
			    dynamicAssert((req.address > base), "mkStdDirectory: invalid address");
			    addrFifo.enq(truncate(req.address));
			 end
		      end
		   endmethod
		endinterface
		interface Get response;
		   method ActionValue#(Bit#(32)) get;
		      dataFifo.deq;
		      return dataFifo.first;
      		   endmethod
		endinterface
      	     endinterface);
   let ifc <- mkStdDirectoryPortalIfc(br);
   interface StdPortal portalIfc = ifc;
endmodule

// Copyright (c) 2013-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 FIFO::*;
import FIFOF::*;
import RegFile::*;
import SpecialFIFOs::*;
import GetPut::*;
import BRAM::*;
import Assert::*;

//portz libraries
import Portal::*;
import MemTypes::*;
import Ctrl2BRAM::*;

interface Directory#(numeric type _n,
		     numeric type _a,
		     numeric type _d);
   interface MemPortal#(_a,_d) portalIfc;
endinterface

typedef Directory#(16,16,32) StdDirectory;

typedef 6 StartDirectoryOffset;

module mkStdDirectoryPortalIfc#(BRAMServer#(Bit#(16), Bit#(32)) br)(StdPortal);
   MemSlave#(16,32) ctrl <- mkCtrl2BRAM(br);
   method Bit#(32) ifcId();
      return 0;
   endmethod
   method Bit#(32) ifcType();
      return 0;
   endmethod
   interface MemSlave slave = ctrl;
   interface ReadOnly interrupt;
      method Bool _read;
	 return False;
      endmethod
   endinterface
endmodule

module mkStdDirectory#(Vector#(n,StdPortal) portals) (StdDirectory);

   Reg#(Bit#(64)) cycle_count <- mkReg(0);
   Reg#(Bit#(32))    snapshot <- mkReg(0);
   FIFOF#(Bit#(16))  addrFifo <- mkSizedFIFOF(1);
   FIFO#(Bit#(32))   dataFifo <- mkSizedFIFO(1);
   let startDirectoryOffset=valueOf(StartDirectoryOffset);

   let base = 128;

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   rule req1;
      let addr = addrFifo.first;
      addrFifo.deq;
      let idx = (addr-fromInteger(startDirectoryOffset)-base);
      if (idx[0] == 0)
	 dataFifo.enq(portals[idx>>1].ifcId);
      else
	 dataFifo.enq(portals[idx>>1].ifcType);
   endrule

   let br = (interface BRAMServer#(Bit#(16), Bit#(32));
		interface Put request;
		   method Action put(BRAMRequest#(Bit#(16),Bit#(32)) req) if (!addrFifo.notEmpty);
		      if (!req.write) begin
      			 if (req.address == 0+base)
			    dataFifo.enq(1); // directory version
			 else if (req.address == 1+base)
			    dataFifo.enq(`TimeStamp);
			 else if (req.address == 2+base)
			    dataFifo.enq(fromInteger(valueOf(n)));
			 else if (req.address == 3+base)
			    dataFifo.enq(16); // portal Addr bits
			 else if (req.address == 4+base) begin
			    snapshot <= truncate(cycle_count);
			    dataFifo.enq(cycle_count[63:32]);
			 end
			 else if (req.address == 5+base)
			    dataFifo.enq(snapshot);
			 else begin
			    dynamicAssert((req.address > base), "mkStdDirectory: invalid address");
			    addrFifo.enq(truncate(req.address));
			 end
		      end
		   endmethod
		endinterface
		interface Get response;
		   method ActionValue#(Bit#(32)) get;
		      dataFifo.deq;
		      return dataFifo.first;
      		   endmethod
		endinterface
      	     endinterface);
   let ifc <- mkStdDirectoryPortalIfc(br);
   interface StdPortal portalIfc = ifc;
endmodule


imageon example has no DMA master

imageon example has no DMA master

Change-Id: I042e9ab12eeb8802eab41abc11f6b87f985c7d5d

// 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 Clocks :: *;
import Vector            :: *;
import Connectable       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import AxiDma            :: *;
import XilinxCells       :: *;
import XbsvXilinxCells   :: *;
import PS7LIB::*;
import PPS7LIB::*;
import XADC::*;
import FIFOF::*;
import HDMI::*;
import Imageon::*;
import ConnectableWithTrace::*;
import CtrlMux::*;
//import TriState::*;

interface I2C_Pins;
   interface Inout#(Bit#(1)) scl;
   interface Inout#(Bit#(1)) sda;
endinterface

//`define TRACE_AXI
//`define AXI_READ_TIMING

(* always_ready, always_enabled *)
interface ZynqTop#(type pins);
   (* prefix="" *)
   interface ZynqPins zynq;
   (* prefix="GPIO" *)
   interface LEDS             leds;
   (* prefix="XADC" *)
   interface XADC             xadc;
   (* prefix="I2C" *)
   interface I2C_Pins         i2c;
   (* prefix="" *)
   interface pins             pins;
   interface Vector#(4, Clock) unused_clock;
   interface Vector#(4, Reset) unused_reset;
endinterface

typedef (function Module#(PortalTop#(32, 64, ipins, 0)) mkpt(Clock clock200, Clock io_vita_clk)) MkPortalTop#(type ipins);

module [Module] mkZynqTopFromPortal#(Clock fmc_video_clk1, MkPortalTop#(ipins) constructor)(ZynqTop#(ipins));
   PS7 ps7 <- mkPS7();
   Clock mainclock = ps7.fclkclk[0];
   Reset mainreset = ps7.fclkreset[0];

   let tscl <- mkIOBUF(~ps7.i2c[1].scltn, ps7.i2c[1].sclo, clocked_by mainclock, reset_by mainreset);
   let tsda <- mkIOBUF(~ps7.i2c[1].sdatn, ps7.i2c[1].sdao, clocked_by mainclock, reset_by mainreset);
   rule sdai;
      ps7.i2c[1].sdai(tsda.o);
      ps7.i2c[1].scli(tscl.o);
   endrule

   Clock fmc_video_clk1_buf <- mkClockIBUFG(clocked_by fmc_video_clk1);
   let top <- constructor(ps7.fclkclk[3], fmc_video_clk1_buf, clocked_by mainclock, reset_by mainreset);

   //mkConnection(ps7.m_axi_gp[0].client, top.ctrl);
   //mkConnectionWithTrace(top.m_axi, ps7.s_axi_hp[0].axi.server);
   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(top.slave);
   mkConnection(ps7.m_axi_gp[0].client, ctrl, clocked_by mainclock, reset_by mainreset);
   //Axi3Master#(32,64,6) m_axi <- mkAxiDmaMaster(top.masters[0], clocked_by mainclock, reset_by mainreset);
   //mkConnectionWithTrace(m_axi, ps7.s_axi_hp[0].axi.server, clocked_by mainclock, reset_by mainreset);

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule send_int_rule;
      ps7.interrupt(pack(intr_mux));
   endrule

   interface zynq = ps7.pins;
   interface leds = top.leds;
   interface XADC xadc;
       method Bit#(4) gpio;
           return 0;
       endmethod
   endinterface

    interface I2C_Pins i2c;
       interface Inout scl = tscl.io;
       interface Inout sda = tsda.io;
    endinterface

   interface pins = top.pins;

   // these are exported to make bsc happy, and then the ports are disconnected after synthesis
   interface unused_clock = ps7.fclkclk;
   interface unused_reset = ps7.fclkreset;
endmodule

module mkImageonZynqTop#(Clock fmc_video_clk1)(ZynqTop#(ImageCapturePins));
   let top <- mkZynqTopFromPortal(fmc_video_clk1, mkPortalTop);
   return top;
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 Clocks :: *;
import Vector            :: *;
import Connectable       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import AxiDma            :: *;
import XilinxCells       :: *;
import XbsvXilinxCells   :: *;
import PS7LIB::*;
import PPS7LIB::*;
import XADC::*;
import FIFOF::*;
import HDMI::*;
import Imageon::*;
import ConnectableWithTrace::*;
import CtrlMux::*;
//import TriState::*;

interface I2C_Pins;
   interface Inout#(Bit#(1)) scl;
   interface Inout#(Bit#(1)) sda;
endinterface

//`define TRACE_AXI
//`define AXI_READ_TIMING

(* always_ready, always_enabled *)
interface ZynqTop#(type pins);
   (* prefix="" *)
   interface ZynqPins zynq;
   (* prefix="GPIO" *)
   interface LEDS             leds;
   (* prefix="XADC" *)
   interface XADC             xadc;
   (* prefix="I2C" *)
   interface I2C_Pins         i2c;
   (* prefix="" *)
   interface pins             pins;
   interface Vector#(4, Clock) unused_clock;
   interface Vector#(4, Reset) unused_reset;
endinterface

typedef (function Module#(PortalTop#(32, 64, ipins)) mkpt(Clock clock200, Clock io_vita_clk)) MkPortalTop#(type ipins);

module [Module] mkZynqTopFromPortal#(Clock fmc_video_clk1, MkPortalTop#(ipins) constructor)(ZynqTop#(ipins));
   PS7 ps7 <- mkPS7();
   Clock mainclock = ps7.fclkclk[0];
   Reset mainreset = ps7.fclkreset[0];

   let tscl <- mkIOBUF(~ps7.i2c[1].scltn, ps7.i2c[1].sclo, clocked_by mainclock, reset_by mainreset);
   let tsda <- mkIOBUF(~ps7.i2c[1].sdatn, ps7.i2c[1].sdao, clocked_by mainclock, reset_by mainreset);
   rule sdai;
      ps7.i2c[1].sdai(tsda.o);
      ps7.i2c[1].scli(tscl.o);
   endrule

   Clock fmc_video_clk1_buf <- mkClockIBUFG(clocked_by fmc_video_clk1);
   let top <- constructor(ps7.fclkclk[3], fmc_video_clk1_buf, clocked_by mainclock, reset_by mainreset);

   //mkConnection(ps7.m_axi_gp[0].client, top.ctrl);
   //mkConnectionWithTrace(top.m_axi, ps7.s_axi_hp[0].axi.server);
   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(top.slave);
   mkConnection(ps7.m_axi_gp[0].client, ctrl, clocked_by mainclock, reset_by mainreset);
   Axi3Master#(32,64,6) m_axi <- mkAxiDmaMaster(top.master, clocked_by mainclock, reset_by mainreset);
   mkConnectionWithTrace(m_axi, ps7.s_axi_hp[0].axi.server, clocked_by mainclock, reset_by mainreset);

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule send_int_rule;
      ps7.interrupt(pack(intr_mux));
   endrule

   interface zynq = ps7.pins;
   interface leds = top.leds;
   interface XADC xadc;
       method Bit#(4) gpio;
           return 0;
       endmethod
   endinterface

    interface I2C_Pins i2c;
       interface Inout scl = tscl.io;
       interface Inout sda = tsda.io;
    endinterface

   interface pins = top.pins;

   // these are exported to make bsc happy, and then the ports are disconnected after synthesis
   interface unused_clock = ps7.fclkclk;
   interface unused_reset = ps7.fclkreset;
endmodule

module mkImageonZynqTop#(Clock fmc_video_clk1)(ZynqTop#(ImageCapturePins));
   let top <- mkZynqTopFromPortal(fmc_video_clk1, mkPortalTop);
   return top;
endmodule


fix maxi and saxi types

fix maxi and saxi types

// 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 Clocks::*;
import DefaultValue::*;
import PParallellaLIB::*;
import AxiMasterSlave::*;
import ConnectalClocks::*;
import AxiBits::*;
import AxiGather::*;

interface ParallellaPins;
   interface Par_txo txo;
   interface Par_txi txi;
   interface Par_rxo rxo;
   interface Par_rxi rxi;
endinterface

interface ParallellaLib;
   interface ParallellaPins pins;
   interface AxiSlaveCommon#(32,32,12,Empty) maxi;  // this will connect to a master
   interface AxiMasterCommon#(32,64,6) saxi;  // this will connect to a slave
   interface Par_misc misc;
endinterface

// 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 Clocks::*;
import DefaultValue::*;
import PParallellaLIB::*;
import AxiMasterSlave::*;
import ConnectalClocks::*;
import AxiBits::*;
import AxiGather::*;

interface ParallellaPins;
   interface Par_txo txo;
   interface Par_txi txi;
   interface Par_rxo rxo;
   interface Par_rxi rxi;
endinterface

interface ParallellaLib;
   interface ParallellaPins pins;
   interface AxiSlaveCommon#(32,32,12) maxi;  // this will connect to a master
   interface AxiMasterCommon#(32,64,6) saxi;  // this will connect to a slave
   interface Par_misc misc;
endinterface


fix debug info error in CtrlMux.bsv

fix debug info error in CtrlMux.bsv

// Copyright (c) 2012 Nokia, Inc.
// 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 Vector::*;
import GetPut::*;
import FIFOF::*;
import SpecialFIFOs::*;
import FIFO::*;

`include "ProjectConfig.bsv"
import ToolConfig::*;
import HostInterface::*;
import Connectable::*;
import AddressGenerator::*;

import Portal::*;
import MemTypes::*;
import Arith::*;
import Pipe::*;

interface PortalCtrl#(numeric type addrWidth, numeric type dataWidth);
   method ActionValue#(Bit#(dataWidth)) read(Bit#(addrWidth) addr);
   method Action write(Bit#(addrWidth) addr, Bit#(dataWidth) v);
endinterface

interface PortalCtrlMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PortalCtrl#(addrWidth, dataWidth)  memSlave;
   interface ReadOnly#(Bool)                    interrupt;
   interface WriteOnly#(Bit#(dataWidth))        num_portals;
endinterface

module mkInterruptMux#(Vector#(numPortals,ReadOnly#(Bool)) inputs) (ReadOnly#(Bool))
   provisos(Add#(nz, TLog#(numPortals), 4),
            Add#(1, a__, numPortals));
   function Bool my_read(ReadOnly#(Bool) x);
      return x._read;
   endfunction
   method Bool _read;
      return fold(boolor,map(my_read,inputs));
   endmethod
endmodule

module mkPortalInterrupt#(Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indicationPipes)
   (PortalInterrupt#(dataWidth));
   Bool      interruptStatus = False;
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, indicationPipes);

   Bit#(dataWidth)  readyChannel = -1;
   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end
   method Bool status();
      return interruptStatus;
   endmethod
   method Bit#(dataWidth) channel();
      return readyChannel;
   endmethod
endmodule

module mkPortalCtrlMemSlave#(Bit#(dataWidth) ifcId, PortalInterrupt#(dataWidth) intr)
   (PortalCtrlMemSlave#(addrWidth, dataWidth))
   provisos(Add#(d__, dataWidth, TMul#(dataWidth, 2)));
   Reg#(Bit#(dataWidth)) num_portals_reg <- mkReg(0);
   Reg#(Bool) interruptEnableReg <- mkReg(False);
   Reg#(Bit#(TMul#(dataWidth,2))) cycle_count <- mkReg(0);
   Reg#(Bit#(dataWidth))    snapshot <- mkReg(0);
   let verbose = False;

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   interface PortalCtrl memSlave;
   method Action write(Bit#(addrWidth) addr, Bit#(dataWidth) v);
      if (addr == 4)
         interruptEnableReg <= (v[0] == 1'd1);
   endmethod

   method ActionValue#(Bit#(dataWidth)) read(Bit#(addrWidth) addr);
      let v = 'h05a05a0;
      if (addr == 0)
         v = intr.status() ? 1 : 0;
      if (addr == 4)
         v = interruptEnableReg ? 1 : 0;
      if (addr == 8)
         v = fromInteger(valueOf(NumberOfTiles));
      if (addr == 'h00C) begin
         if (intr.status())
            v = intr.channel()+1;
         else
            v = 0;
      end
      if (addr == 'h010)
         v = ifcId;
      if (addr == 'h014)
         v = num_portals_reg;
      if (addr == 'h018) begin
         snapshot <= truncate(cycle_count);
         v = truncate(cycle_count>>valueOf(dataWidth));
      end
      if (addr == 'h01C)
         v = snapshot;
      return v;
   endmethod
   endinterface
   interface ReadOnly interrupt;
      method Bool _read();
         return intr.status() && interruptEnableReg;
      endmethod
   endinterface
   interface WriteOnly num_portals;
      method Action _write(Bit#(dataWidth) v);
         num_portals_reg <= v;
      endmethod
   endinterface
endmodule

module mkMemMethodMuxIn#(PortalCtrl#(aw,dataWidth) ctrl, Vector#(numRequests, PipeIn#(Bit#(dataWidth))) requests
        )(PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            , Add#(a__, TLog#(numRequests), selWidth)
            , Add#(1, b__, dataWidth)
      );
   AddressGenerator#(aw,dataWidth) fifoReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(aw,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                fifoWriteDoneFifo <- mkFIFO();
   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TSub#(addrWidth,1));
   function Bit#(selWidth) psel(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v;
   endfunction
   function Bool pselCtrl(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v == ~0;
   endfunction
   function Bit#(aw) asel(Bit#(addrWidth) a);
      return a[(port_sel_low-1):0];
   endfunction

   FIFO#(Bit#(MemTagSize)) doneFifo          <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_ars <- mkFIFO1();
   FIFO#(Bit#(TLog#(numRequests))) rs <- mkFIFO1();
   FIFO#(Bool)                   rsCtrl <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_aws <- mkFIFO1();
   FIFO#(Bit#(TLog#(numRequests))) ws <- mkFIFO1();
   FIFO#(Bool)                   wsCtrl <- mkFIFO1();

   rule write_done;
      let rv <- toGet(fifoWriteDoneFifo).get();
      ws.deq();
      wsCtrl.deq();
      doneFifo.enq(rv);
   endrule

   rule req_aw;
      let req <- toGet(req_aws).get;
      fifoWriteAddrGenerator.request.put(req);
   endrule

   rule req_ar;
      let req <- toGet(req_ars).get;
      fifoReadAddrGenerator.request.put(req);
   endrule

   FIFO#(MemData#(dataWidth)) writeDataFifo <- mkFIFO();
   rule writeDataRule;
      let wdata <- toGet(writeDataFifo).get();
      //$display("mkMemMethodMux.writeData aw=%d ws=%d data=%h", valueOf(aw), ws.first, wdata.data);
      let b <- fifoWriteAddrGenerator.addrBeat.get();
      //$display("mkPipeInMemSlave.writeData.put addr=%h data=%h", b.addr, wdata.data);
      if (b.last)
         fifoWriteDoneFifo.enq(b.tag);
      if (wsCtrl.first)
         ctrl.write(b.addr, wdata.data);
      else begin
         requests[ws.first].enq(wdata.data);
         // this used to be where we triggered putFailed
      end
   endrule

   FIFO#(MemData#(dataWidth)) rvFifo <- mkFIFO;
   rule rvrule;
         let v = 0;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      if (rsCtrl.first) begin
         let vr <- ctrl.read(b.addr);
         v = vr;
      end
      else begin
         if (b.addr == 4)
            v = extend(pack(requests[rs.first].notFull()));
      end
      rvFifo.enq(MemData { data: v, tag: b.tag, last: b.last });
      //$display("mkMemMethodMux.readData aw=%d rs=%d data=%h", valueOf(aw), rs.first, rv.data);
      if (b.last) begin
         rs.deq();
         rsCtrl.deq();
      end
   endrule

   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_aws.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
                                       , firstbe: req.firstbe, lastbe: req.lastbe
`endif
                                       });
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.writeReq len=%d \n\n ****", req.burstLen);
            //$display("mkMemMethodMux.writeReq addr=%h selWidth=%d aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(selWidth), valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            ws.enq(truncate(psel(req.addr)));
            wsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Put writeData;
         method Action put(MemData#(dataWidth) wdata);
            writeDataFifo.enq(wdata);
         endmethod
      endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
            let rv <- toGet(doneFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_ars.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
                                       , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            //$display("mkMemMethodMux.readReq addr=%h aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.readReq len=%d \n\n ****", req.burstLen);
            rs.enq(truncate(psel(req.addr)));
            rsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Get readData;
         method ActionValue#(MemData#(dataWidth)) get();
            let rv <- toGet(rvFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
endmodule

module mkMemMethodMuxOut#(PortalCtrl#(aw,dataWidth) ctrl, Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indications)(PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            , Add#(a__, TLog#(numIndications), selWidth)
            , Add#(1, b__, dataWidth)
      );
   AddressGenerator#(aw,dataWidth) fifoReadAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(aw,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                fifoWriteDoneFifo <- mkFIFO();
   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TSub#(addrWidth,1));
   function Bit#(selWidth) psel(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v;
   endfunction
   function Bool pselCtrl(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v == ~0;
   endfunction
   function Bit#(aw) asel(Bit#(addrWidth) a);
      return a[(port_sel_low-1):0];
   endfunction

   FIFO#(Bit#(MemTagSize)) doneFifo          <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_ars <- mkFIFO1();
   FIFO#(Bit#(TLog#(numIndications))) rs <- mkFIFO1();
   FIFO#(Bool)                   rsCtrl <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_aws <- mkFIFO1();
   FIFO#(Bit#(TLog#(numIndications))) ws <- mkFIFO1();
   FIFO#(Bool)                   wsCtrl <- mkFIFO1();

   rule write_done;
      let rv <- toGet(fifoWriteDoneFifo).get();
      ws.deq();
      wsCtrl.deq();
      doneFifo.enq(rv);
   endrule

   rule req_aw;
      let req <- toGet(req_aws).get;
      fifoWriteAddrGenerator.request.put(req);
   endrule

   rule req_ar;
      let req <- toGet(req_ars).get;
      fifoReadAddrGenerator.request.put(req);
   endrule

   FIFO#(MemData#(dataWidth)) rvFifo <- mkFIFO;
   rule rvrule;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      let rv = MemData { data: 0, tag: b.tag, last: b.last };
      if (rsCtrl.first) begin
         let vr <- ctrl.read(b.addr);
         rv.data = vr;
      end
      else begin
         if (b.addr == 0)
            rv.data <- toGet(indications[rs.first]).get();
         else if (b.addr == 4)
            rv.data = extend(pack(indications[rs.first].notEmpty()));
      end
      rvFifo.enq(rv);
      //$display("mkMemMethodMux.readData aw=%d rs=%d data=%h", valueOf(aw), rs.first, rv.data);
      rs.deq();
      rsCtrl.deq();
   endrule

   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_aws.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
               , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.writeReq len=%d \n\n ****", req.burstLen);
            //$display("mkMemMethodMux.writeReq addr=%h selWidth=%d aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(selWidth), valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            ws.enq(truncate(psel(req.addr)));
            wsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Put writeData;
         method Action put(MemData#(dataWidth) wdata);
            //$display("mkMemMethodMux.writeData aw=%d ws=%d data=%h", valueOf(aw), ws.first, wdata.data);
            let b <- fifoWriteAddrGenerator.addrBeat.get();
            if (wsCtrl.first)
               ctrl.write(b.addr, wdata.data);
            //$display("mkPipeOutMemSlave.writeData.put addr=%h data=%h", b.addr, wdata.data);
            if (b.last)
               fifoWriteDoneFifo.enq(b.tag);
         endmethod
      endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
            let rv <- toGet(doneFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_ars.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
               , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            //$display("mkMemMethodMux.readReq addr=%h aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.readReq len=%d \n\n ****", req.burstLen);
            rs.enq(truncate(psel(req.addr)));
            rsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Get readData;
         method ActionValue#(MemData#(dataWidth)) get();
            let rv <- toGet(rvFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
endmodule

module mkPhysMemSlaveMux#(Vector#(numSlaves,PhysMemSlave#(aw,dataWidth)) slaves) (PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            ,Add#(a__, TLog#(numSlaves), selWidth)
            ,Min#(4,TLog#(numSlaves),bpc)
            ,Pipe::FunnelPipesPipelined#(1, numSlaves, MemTypes::MemData#(dataWidth),bpc)
            );
   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TSub#(addrWidth,1));
   function Bit#(selWidth) psel(Bit#(addrWidth) a);
      return a[port_sel_high:port_sel_low];
   endfunction
   function Bit#(aw) asel(Bit#(addrWidth) a);
      return a[(port_sel_low-1):0];
   endfunction
   function Get#(MemData#(dataWidth)) getMemPortalReadData(PhysMemSlave#(aw,dataWidth) x) = x.read_server.readData;
   function Put#(MemData#(dataWidth)) getMemPortalWriteData(PhysMemSlave#(aw,dataWidth) x) = x.write_server.writeData;

   FIFO#(Bit#(MemTagSize))        doneFifo <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_ars <- mkSizedFIFO(1);
   FIFO#(Bit#(TLog#(numSlaves))) rs <- mkFIFO1();
   Vector#(numSlaves, PipeOut#(MemData#(dataWidth))) readDataPipes <- mapM(mkPipeOut, map(getMemPortalReadData,slaves));
   FunnelPipe#(1, numSlaves, MemData#(dataWidth), bpc) read_data_funnel <- mkFunnelPipesPipelined(readDataPipes);

   FIFO#(PhysMemRequest#(aw,dataWidth)) req_aws <- mkFIFO1();
   FIFO#(Bit#(TLog#(numSlaves))) ws <- mkFIFO1();
   FIFOF#(Tuple2#(Bit#(TLog#(numSlaves)), MemData#(dataWidth))) write_data <- mkFIFOF;
   UnFunnelPipe#(1, numSlaves, MemData#(dataWidth), bpc) write_data_unfunnel <- mkUnFunnelPipesPipelined(cons(toPipeOut(write_data),nil));
   Vector#(numSlaves, PipeIn#(MemData#(dataWidth))) writeDataPipes <- mapM(mkPipeIn, map(getMemPortalWriteData,slaves));
   zipWithM_(mkConnection, write_data_unfunnel, writeDataPipes);
   let verbose = False;

   rule req_aw;
      let req <- toGet(req_aws).get;
      slaves[ws.first].write_server.writeReq.put(req);
   endrule

   rule req_ar;
      let req <- toGet(req_ars).get;
      slaves[rs.first].read_server.readReq.put(req);
   endrule

   rule write_done_rule;
      let rv <- slaves[ws.first].write_server.writeDone.get();
      ws.deq();
      doneFifo.enq(rv);
   endrule

   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_aws.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
               , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            if (req.burstLen > 4) $display("**** \n\n mkPhysMemSlaveMux.writeReq len=%d \n\n ****", req.burstLen);
            ws.enq(truncate(psel(req.addr)));
            if(verbose) $display("mkPhysMemSlaveMux.writeReq addr=%h aw=%d psel=%h", req.addr, valueOf(aw), psel(req.addr));
         endmethod
      endinterface
      interface Put writeData;
         method Action put(MemData#(dataWidth) wdata);
            write_data.enq(tuple2(ws.first,wdata));
            if(verbose) $display("mkPhysMemSlaveMux.writeData dst=%h wdata=%h", ws.first,wdata);
         endmethod
      endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
            let rv <- toGet(doneFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_ars.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
                                       , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            rs.enq(truncate(psel(req.addr)));
            if (req.burstLen > 4) $display("**** \n\n mkPhysMemSlaveMux.readReq len=%d \n\n ****", req.burstLen);
            if(verbose) $display("mkPhysMemSlaveMux.readReq addr=%h aw=%d psel=%h", req.addr, valueOf(aw), psel(req.addr));
         endmethod
      endinterface
      interface Get readData;
         method ActionValue#(MemData#(dataWidth)) get();
            let rv <- toGet(read_data_funnel[0]).get;
            rs.deq();
            if(verbose) $display("mkPhysMemSlaveMux.readData rs=%d data=%h", rs.first, rv.data);
            return rv;
         endmethod
      endinterface
   endinterface
endmodule

module mkSlaveMux#(Vector#(numPortals,MemPortal#(aw,dataWidth)) portals) (PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            ,Add#(a__, TLog#(numPortals), selWidth)
            ,FunnelPipesPipelined#(1, numPortals, MemData#(dataWidth),TMin#(4, TLog#(numPortals)))
            );
   function PhysMemSlave#(_a,_d) getSlave(MemPortal#(_a,_d) p);
      return p.slave;
   endfunction
   Vector#(numPortals, PhysMemSlave#(aw,dataWidth)) slaves = map(getSlave, portals);
   for(Integer i = 0; i < valueOf(numPortals); i=i+1)
      rule writeTop;
         portals[i].num_portals <= fromInteger(valueOf(numPortals));
      endrule
   let rv <- mkPhysMemSlaveMux(slaves);
   return rv;
endmodule

// Copyright (c) 2012 Nokia, Inc.
// 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 Vector::*;
import GetPut::*;
import FIFOF::*;
import SpecialFIFOs::*;
import FIFO::*;

`include "ProjectConfig.bsv"
import ToolConfig::*;
import HostInterface::*;
import Connectable::*;
import AddressGenerator::*;

import Portal::*;
import MemTypes::*;
import Arith::*;
import Pipe::*;

interface PortalCtrl#(numeric type addrWidth, numeric type dataWidth);
   method ActionValue#(Bit#(dataWidth)) read(Bit#(addrWidth) addr);
   method Action write(Bit#(addrWidth) addr, Bit#(dataWidth) v);
endinterface

interface PortalCtrlMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PortalCtrl#(addrWidth, dataWidth)  memSlave;
   interface ReadOnly#(Bool)                    interrupt;
   interface WriteOnly#(Bit#(dataWidth))        num_portals;
endinterface

module mkInterruptMux#(Vector#(numPortals,ReadOnly#(Bool)) inputs) (ReadOnly#(Bool))
   provisos(Add#(nz, TLog#(numPortals), 4),
            Add#(1, a__, numPortals));
   function Bool my_read(ReadOnly#(Bool) x);
      return x._read;
   endfunction
   method Bool _read;
      return fold(boolor,map(my_read,inputs));
   endmethod
endmodule

module mkPortalInterrupt#(Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indicationPipes)
   (PortalInterrupt#(dataWidth));
   Bool      interruptStatus = False;
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, indicationPipes);

   Bit#(dataWidth)  readyChannel = -1;
   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end
   method Bool status();
      return interruptStatus;
   endmethod
   method Bit#(dataWidth) channel();
      return readyChannel;
   endmethod
endmodule

module mkPortalCtrlMemSlave#(Bit#(dataWidth) ifcId, PortalInterrupt#(dataWidth) intr)
   (PortalCtrlMemSlave#(addrWidth, dataWidth))
   provisos(Add#(d__, dataWidth, TMul#(dataWidth, 2)));
   Reg#(Bit#(dataWidth)) num_portals_reg <- mkReg(0);
   Reg#(Bool) interruptEnableReg <- mkReg(False);
   Reg#(Bit#(TMul#(dataWidth,2))) cycle_count <- mkReg(0);
   Reg#(Bit#(dataWidth))    snapshot <- mkReg(0);
   let verbose = False;

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   interface PortalCtrl memSlave;
   method Action write(Bit#(addrWidth) addr, Bit#(dataWidth) v);
      if (addr == 4)
         interruptEnableReg <= (v[0] == 1'd1);
   endmethod

   method ActionValue#(Bit#(dataWidth)) read(Bit#(addrWidth) addr);
      let v = 'h05a05a0;
      if (addr == 0)
         v = intr.status() ? 1 : 0;
      if (addr == 4)
         v = interruptEnableReg ? 1 : 0;
      if (addr == 8)
         v = fromInteger(valueOf(NumberOfTiles));
      if (addr == 'h00C) begin
         if (intr.status())
            v = intr.channel()+1;
         else
            v = 0;
      end
      if (addr == 'h010)
         v = ifcId;
      if (addr == 'h014)
         v = num_portals_reg;
      if (addr == 'h018) begin
         snapshot <= truncate(cycle_count);
         v = truncate(cycle_count>>valueOf(dataWidth));
      end
      if (addr == 'h01C)
         v = snapshot;
      return v;
   endmethod
   endinterface
   interface ReadOnly interrupt;
      method Bool _read();
         return intr.status() && interruptEnableReg;
      endmethod
   endinterface
   interface WriteOnly num_portals;
      method Action _write(Bit#(dataWidth) v);
         num_portals_reg <= v;
      endmethod
   endinterface
endmodule

module mkMemMethodMuxIn#(PortalCtrl#(aw,dataWidth) ctrl, Vector#(numRequests, PipeIn#(Bit#(dataWidth))) requests
        )(PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            , Add#(a__, TLog#(numRequests), selWidth)
            , Add#(1, b__, dataWidth)
      );
   AddressGenerator#(aw,dataWidth) fifoReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(aw,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                fifoWriteDoneFifo <- mkFIFO();
   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TSub#(addrWidth,1));
   function Bit#(selWidth) psel(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v;
   endfunction
   function Bool pselCtrl(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v == ~0;
   endfunction
   function Bit#(aw) asel(Bit#(addrWidth) a);
      return a[(port_sel_low-1):0];
   endfunction

   FIFO#(Bit#(MemTagSize)) doneFifo          <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_ars <- mkFIFO1();
   FIFO#(Bit#(TLog#(numRequests))) rs <- mkFIFO1();
   FIFO#(Bool)                   rsCtrl <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_aws <- mkFIFO1();
   FIFO#(Bit#(TLog#(numRequests))) ws <- mkFIFO1();
   FIFO#(Bool)                   wsCtrl <- mkFIFO1();

   rule write_done;
      let rv <- toGet(fifoWriteDoneFifo).get();
      ws.deq();
      wsCtrl.deq();
      doneFifo.enq(rv);
   endrule

   rule req_aw;
      let req <- toGet(req_aws).get;
      fifoWriteAddrGenerator.request.put(req);
   endrule

   rule req_ar;
      let req <- toGet(req_ars).get;
      fifoReadAddrGenerator.request.put(req);
   endrule

   FIFO#(MemData#(dataWidth)) writeDataFifo <- mkFIFO();
   rule writeDataRule;
      let wdata <- toGet(writeDataFifo).get();
      //$display("mkMemMethodMux.writeData aw=%d ws=%d data=%h", valueOf(aw), ws.first, wdata.data);
      let b <- fifoWriteAddrGenerator.addrBeat.get();
      //$display("mkPipeInMemSlave.writeData.put addr=%h data=%h", b.addr, wdata.data);
      if (b.last)
         fifoWriteDoneFifo.enq(b.tag);
      if (wsCtrl.first)
         ctrl.write(b.addr, wdata.data);
      else begin
         requests[ws.first].enq(wdata.data);
         // this used to be where we triggered putFailed
      end
   endrule

   FIFO#(MemData#(dataWidth)) rvFifo <- mkFIFO;
   rule rvrule;
         let v = 0;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      if (rsCtrl.first) begin
         let vr <- ctrl.read(b.addr);
         v = vr;
      end
      else begin
         if (b.addr == 4)
            v = extend(pack(requests[rs.first].notFull()));
      end
      rvFifo.enq(MemData { data: v, tag: b.tag, last: b.last });
      //$display("mkMemMethodMux.readData aw=%d rs=%d data=%h", valueOf(aw), rs.first, rv.data);
      if (b.last) begin
         rs.deq();
         rsCtrl.deq();
      end
   endrule

   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_aws.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
                                       , firstbe: req.firstbe, lastbe: req.lastbe
`endif
                                       });
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.writeReq len=%d \n\n ****", req.burstLen);
            //$display("mkMemMethodMux.writeReq addr=%h selWidth=%d aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(selWidth), valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            ws.enq(truncate(psel(req.addr)));
            wsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Put writeData;
         method Action put(MemData#(dataWidth) wdata);
            writeDataFifo.enq(wdata);
         endmethod
      endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
            let rv <- toGet(doneFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_ars.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
                                       , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            //$display("mkMemMethodMux.readReq addr=%h aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.readReq len=%d \n\n ****", req.burstLen);
            rs.enq(truncate(psel(req.addr)));
            rsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Get readData;
         method ActionValue#(MemData#(dataWidth)) get();
            let rv <- toGet(rvFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
endmodule

module mkMemMethodMuxOut#(PortalCtrl#(aw,dataWidth) ctrl, Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indications)(PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            , Add#(a__, TLog#(numIndications), selWidth)
            , Add#(1, b__, dataWidth)
      );
   AddressGenerator#(aw,dataWidth) fifoReadAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(aw,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                fifoWriteDoneFifo <- mkFIFO();
   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TSub#(addrWidth,1));
   function Bit#(selWidth) psel(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v;
   endfunction
   function Bool pselCtrl(Bit#(addrWidth) a);
      Bit#(selWidth) v = a[port_sel_high:port_sel_low];
      return v == ~0;
   endfunction
   function Bit#(aw) asel(Bit#(addrWidth) a);
      return a[(port_sel_low-1):0];
   endfunction

   FIFO#(Bit#(MemTagSize)) doneFifo          <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_ars <- mkFIFO1();
   FIFO#(Bit#(TLog#(numIndications))) rs <- mkFIFO1();
   FIFO#(Bool)                   rsCtrl <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_aws <- mkFIFO1();
   FIFO#(Bit#(TLog#(numIndications))) ws <- mkFIFO1();
   FIFO#(Bool)                   wsCtrl <- mkFIFO1();

   rule write_done;
      let rv <- toGet(fifoWriteDoneFifo).get();
      ws.deq();
      wsCtrl.deq();
      doneFifo.enq(rv);
   endrule

   rule req_aw;
      let req <- toGet(req_aws).get;
      fifoWriteAddrGenerator.request.put(req);
   endrule

   rule req_ar;
      let req <- toGet(req_ars).get;
      fifoReadAddrGenerator.request.put(req);
   endrule

   FIFO#(MemData#(dataWidth)) rvFifo <- mkFIFO;
   rule rvrule;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      let rv = MemData { data: 0, tag: b.tag, last: b.last };
      if (rsCtrl.first) begin
         let vr <- ctrl.read(b.addr);
         rv.data = vr;
      end
      else begin
         if (b.addr == 0)
            rv.data <- toGet(indications[rs.first]).get();
         else if (b.addr == 4)
            rv.data = extend(pack(indications[rs.first].notEmpty()));
      end
      rvFifo.enq(rv);
      //$display("mkMemMethodMux.readData aw=%d rs=%d data=%h", valueOf(aw), rs.first, rv.data);
      rs.deq();
      rsCtrl.deq();
   endrule

   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_aws.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
               , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.writeReq len=%d \n\n ****", req.burstLen);
            //$display("mkMemMethodMux.writeReq addr=%h selWidth=%d aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(selWidth), valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            ws.enq(truncate(psel(req.addr)));
            wsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Put writeData;
         method Action put(MemData#(dataWidth) wdata);
            //$display("mkMemMethodMux.writeData aw=%d ws=%d data=%h", valueOf(aw), ws.first, wdata.data);
            let b <- fifoWriteAddrGenerator.addrBeat.get();
            if (wsCtrl.first)
               ctrl.write(b.addr, wdata.data);
            //$display("mkPipeOutMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
            if (b.last)
               fifoWriteDoneFifo.enq(b.tag);
         endmethod
      endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
            let rv <- toGet(doneFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_ars.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
               , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            //$display("mkMemMethodMux.readReq addr=%h aw=%d psel=%h pselCtrl=%x", req.addr, valueOf(aw), psel(req.addr), pselCtrl(req.addr));
            if (req.burstLen > 4) $display("**** \n\n mkMemMethodMux.readReq len=%d \n\n ****", req.burstLen);
            rs.enq(truncate(psel(req.addr)));
            rsCtrl.enq(pselCtrl(req.addr));
         endmethod
      endinterface
      interface Get readData;
         method ActionValue#(MemData#(dataWidth)) get();
            let rv <- toGet(rvFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
endmodule

module mkPhysMemSlaveMux#(Vector#(numSlaves,PhysMemSlave#(aw,dataWidth)) slaves) (PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            ,Add#(a__, TLog#(numSlaves), selWidth)
            ,Min#(4,TLog#(numSlaves),bpc)
            ,Pipe::FunnelPipesPipelined#(1, numSlaves, MemTypes::MemData#(dataWidth),bpc)
            );
   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TSub#(addrWidth,1));
   function Bit#(selWidth) psel(Bit#(addrWidth) a);
      return a[port_sel_high:port_sel_low];
   endfunction
   function Bit#(aw) asel(Bit#(addrWidth) a);
      return a[(port_sel_low-1):0];
   endfunction
   function Get#(MemData#(dataWidth)) getMemPortalReadData(PhysMemSlave#(aw,dataWidth) x) = x.read_server.readData;
   function Put#(MemData#(dataWidth)) getMemPortalWriteData(PhysMemSlave#(aw,dataWidth) x) = x.write_server.writeData;

   FIFO#(Bit#(MemTagSize))        doneFifo <- mkFIFO1();
   FIFO#(PhysMemRequest#(aw,dataWidth)) req_ars <- mkSizedFIFO(1);
   FIFO#(Bit#(TLog#(numSlaves))) rs <- mkFIFO1();
   Vector#(numSlaves, PipeOut#(MemData#(dataWidth))) readDataPipes <- mapM(mkPipeOut, map(getMemPortalReadData,slaves));
   FunnelPipe#(1, numSlaves, MemData#(dataWidth), bpc) read_data_funnel <- mkFunnelPipesPipelined(readDataPipes);

   FIFO#(PhysMemRequest#(aw,dataWidth)) req_aws <- mkFIFO1();
   FIFO#(Bit#(TLog#(numSlaves))) ws <- mkFIFO1();
   FIFOF#(Tuple2#(Bit#(TLog#(numSlaves)), MemData#(dataWidth))) write_data <- mkFIFOF;
   UnFunnelPipe#(1, numSlaves, MemData#(dataWidth), bpc) write_data_unfunnel <- mkUnFunnelPipesPipelined(cons(toPipeOut(write_data),nil));
   Vector#(numSlaves, PipeIn#(MemData#(dataWidth))) writeDataPipes <- mapM(mkPipeIn, map(getMemPortalWriteData,slaves));
   zipWithM_(mkConnection, write_data_unfunnel, writeDataPipes);
   let verbose = False;

   rule req_aw;
      let req <- toGet(req_aws).get;
      slaves[ws.first].write_server.writeReq.put(req);
   endrule

   rule req_ar;
      let req <- toGet(req_ars).get;
      slaves[rs.first].read_server.readReq.put(req);
   endrule

   rule write_done_rule;
      let rv <- slaves[ws.first].write_server.writeDone.get();
      ws.deq();
      doneFifo.enq(rv);
   endrule

   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_aws.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
               , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            if (req.burstLen > 4) $display("**** \n\n mkPhysMemSlaveMux.writeReq len=%d \n\n ****", req.burstLen);
            ws.enq(truncate(psel(req.addr)));
            if(verbose) $display("mkPhysMemSlaveMux.writeReq addr=%h aw=%d psel=%h", req.addr, valueOf(aw), psel(req.addr));
         endmethod
      endinterface
      interface Put writeData;
         method Action put(MemData#(dataWidth) wdata);
            write_data.enq(tuple2(ws.first,wdata));
            if(verbose) $display("mkPhysMemSlaveMux.writeData dst=%h wdata=%h", ws.first,wdata);
         endmethod
      endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
            let rv <- toGet(doneFifo).get();
            return rv;
         endmethod
      endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
            req_ars.enq(PhysMemRequest{addr:asel(req.addr), burstLen:req.burstLen, tag:req.tag
`ifdef BYTE_ENABLES
                                       , firstbe: req.firstbe, lastbe: req.lastbe
`endif
               });
            rs.enq(truncate(psel(req.addr)));
            if (req.burstLen > 4) $display("**** \n\n mkPhysMemSlaveMux.readReq len=%d \n\n ****", req.burstLen);
            if(verbose) $display("mkPhysMemSlaveMux.readReq addr=%h aw=%d psel=%h", req.addr, valueOf(aw), psel(req.addr));
         endmethod
      endinterface
      interface Get readData;
         method ActionValue#(MemData#(dataWidth)) get();
            let rv <- toGet(read_data_funnel[0]).get;
            rs.deq();
            if(verbose) $display("mkPhysMemSlaveMux.readData rs=%d data=%h", rs.first, rv.data);
            return rv;
         endmethod
      endinterface
   endinterface
endmodule

module mkSlaveMux#(Vector#(numPortals,MemPortal#(aw,dataWidth)) portals) (PhysMemSlave#(addrWidth,dataWidth))
   provisos(Add#(selWidth,aw,addrWidth)
            ,Add#(a__, TLog#(numPortals), selWidth)
            ,FunnelPipesPipelined#(1, numPortals, MemData#(dataWidth),TMin#(4, TLog#(numPortals)))
            );
   function PhysMemSlave#(_a,_d) getSlave(MemPortal#(_a,_d) p);
      return p.slave;
   endfunction
   Vector#(numPortals, PhysMemSlave#(aw,dataWidth)) slaves = map(getSlave, portals);
   for(Integer i = 0; i < valueOf(numPortals); i=i+1)
      rule writeTop;
         portals[i].num_portals <= fromInteger(valueOf(numPortals));
      endrule
   let rv <- mkPhysMemSlaveMux(slaves);
   return rv;
endmodule