debugging MMU for xsim

debugging MMU for xsim

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

// BSV Libraries
import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import MemTypes::*;
import StmtFSM::*;
import ClientServer::*;
import ConnectalMemory::*;
import ConnectalCompletionBuffer::*;
import Pareff::*;

typedef 32 MaxNumSGLists;
typedef Bit#(TLog#(MaxNumSGLists)) SGListId;
typedef 12 SGListPageShift0;
typedef 16 SGListPageShift4;
typedef 20 SGListPageShift8;
typedef Bit#(TLog#(MaxNumSGLists)) RegionsIdx;

typedef 8 IndexWidth;

typedef struct {
   SGListId             id;
   Bit#(MemOffsetSize) off;
} ReqTup deriving (Eq,Bits,FShow);

interface MMU#(numeric type addrWidth);
   interface MMURequest request;
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef struct {
   Bit#(2) pageSize;
   Bit#(SGListPageShift8) value;
} Offset deriving (Eq,Bits,FShow);

typedef Bit#(TSub#(MemOffsetSize,SGListPageShift0)) Page0;
typedef Bit#(TSub#(MemOffsetSize,SGListPageShift4)) Page4;
typedef Bit#(TSub#(MemOffsetSize,SGListPageShift8)) Page8;

typedef struct {
   Bit#(TSub#(MemOffsetSize,SGListPageShift0)) barrier;
   Bit#(IndexWidth) idxOffset;
   } SingleRegion deriving (Eq,Bits,FShow);

typedef struct {
   SingleRegion reg8;
   SingleRegion reg4;
   SingleRegion reg0;
   } Region deriving (Eq,Bits,FShow);

typedef struct {DmaErrorType errorType;
		Bit#(32) pref;
		Bit#(MemOffsetSize) off;
   } DmaError deriving (Bits);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkMMU#(Integer iid, Bool hostMapped, MMUIndication mmuIndication)(MMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(a__,addrWidth,MemOffsetSize));

   let verbose = True;
   TagGen#(MaxNumSGLists) sglId_gen <- mkTagGen;
   rule complete_sglId_gen;
      let __x <- sglId_gen.complete;
   endrule

   // for simulators
   Pareff#(32) pareff <- mkPareff();

   // stage 0 (latency == 1)
   Vector#(2, FIFO#(ReqTup)) incomingReqs <- replicateM(mkFIFO);

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Maybe#(Region)) regall <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(ReqTup))          reqs0 <- replicateM(mkSizedFIFOF(3));

   // stage 2 (latency == 1)
   Vector#(2,FIFOF#(Tuple3#(Bool,Bool,Bool))) conds <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Tuple3#(Bit#(IndexWidth),Bit#(IndexWidth),Bit#(IndexWidth)))) idxOffsets0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(ReqTup))           reqs1 <- replicateM(mkSizedFIFOF(3));

   // stage 3 (latency == 1)
   Vector#(2,FIFOF#(Offset))           offs0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))    idxOffsets1 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))         ptrs1 <- replicateM(mkFIFOF);

   // stage 4 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page0) pages <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(Offset))           offs1 <- replicateM(mkSizedFIFOF(3));

   // stage 4 (latnecy == 1)
   Vector#(2,FIFOF#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFOF);

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      mmuIndication.error(extend(pack(error.errorType)), error.pref, extend(error.off), fromInteger(iid));
   endrule

   let page_shift0 = fromInteger(valueOf(SGListPageShift0));
   let page_shift4 = fromInteger(valueOf(SGListPageShift4));
   let page_shift8 = fromInteger(valueOf(SGListPageShift8));

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

   for (Integer i = 0; i < 2; i=i+1)
      rule stage1;  // first read in the address cutoff values between regions
	 ReqTup req <- toGet(incomingReqs[i]).get();
	 portsel(regall, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(req.id), datain:?});
	 reqs0[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2; // Now compare address cutoffs with requested offset
	 ReqTup req <- toGet(reqs0[i]).get;
	 Maybe#(Region) m_regionall <- portsel(regall,i).response.get;

	 case (m_regionall) matches
	    tagged Valid .regionall: begin
               Page0 off0 = truncate(req.off >> valueOf(SGListPageShift0));
               Page4 off4 = truncate(req.off >> valueOf(SGListPageShift4));
               Page8 off8 = truncate(req.off >> valueOf(SGListPageShift8));
	       let cond8 = off8 < truncate(regionall.reg8.barrier);
	       let cond4 = off4 < truncate(regionall.reg4.barrier);
	       let cond0 = off0 < regionall.reg0.barrier;

	       if (verbose) $display("mkMMU::stage2: id=%d off=%h (%h %h %h) (%h %h %h)", req.id, req.off,
				     regionall.reg8.barrier, regionall.reg4.barrier, regionall.reg0.barrier,
				     off8, off4, off0);

	       conds[i].enq(tuple3(cond8,cond4,cond0));
	       idxOffsets0[i].enq(tuple3(regionall.reg8.idxOffset,regionall.reg4.idxOffset, regionall.reg0.idxOffset));
	       reqs1[i].enq(req);
	    end
	    tagged Invalid:
	       dmaErrorFifo.enq(DmaError { errorType: DmaErrorSGLIdInvalid, pref: extend(req.id), off:req.off });
	 endcase
      endrule
      rule stage3; // Based on results of comparision, select a region, putting it into 'o.pageSize'.  idxOffset holds offset in sglist table of relevant entry
	 ReqTup req <- toGet(reqs1[i]).get;
	 Offset o = Offset{pageSize: 0, value: truncate(req.off)};
	 Bit#(IndexWidth) pbase = 0;
	 Bit#(IndexWidth) idxOffset = 0;

	 match{.cond8,.cond4,.cond0} <- toGet(conds[i]).get;
	 match{.idxOffset8,.idxOffset4,.idxOffset0} <- toGet(idxOffsets0[i]).get;

	 if (cond8) begin
	    if (verbose) $display("mkMMU::request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 3;
	    pbase = truncate(req.off>>page_shift8);
	    idxOffset = idxOffset8;
	 end
	 else if (cond4) begin
	    if (verbose) $display("mkMMU::request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 2;
	    pbase = truncate(req.off>>page_shift4);
	    idxOffset = idxOffset4;
	 end
	 else if (cond0) begin
	    if (verbose) $display("mkMMU::request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 1;
	    pbase = truncate(req.off>>page_shift0);
	    idxOffset = idxOffset0;
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets1[i].enq(idxOffset);
	 ptrs1[i].enq(req.id);
      endrule
      rule stage4; // Read relevant sglist entry
	 let off <- toGet(offs0[i]).get();
	 let pbase <- toGet(pbases[i]).get();
	 let idxOffset <- toGet(idxOffsets1[i]).get();
	 let ptr <- toGet(ptrs1[i]).get();
	 Bit#(IndexWidth) p = pbase + idxOffset;
	 if (off.pageSize == 0) begin
	    if (verbose) $display("mkMMU::addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorOffsetOutOfRange, pref: extend(ptr), off:extend(off.value) });
	 end
	 else begin
	    if (verbose) $display("mkMMU::pages[%d].read %h", i, {ptr,p});
	    portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
						      address:{ptr,p}, datain:?});
	    offs1[i].enq(off);
	 end
      endrule
      rule stage5; // Concatenate page base address from sglist entry with LSB offset bits from request and return
	 Page0 page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 if (verbose) $display("mkMMU::p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(MemOffsetSize) rv = ?;
	 Page4 b4 = truncate(page);
	 Page8 b8 = truncate(page);
	 case (offset.pageSize)
	    1: rv = {page,truncate(offset.value)};
	    2: rv = {b4,truncate(offset.value)};
	    3: rv = {b8,truncate(offset.value)};
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   FIFO#(SGListId) configRespFifo <- mkFIFO;
   rule sendConfigResp;
      let ptr <- toGet(configRespFifo).get();
      mmuIndication.configResp(extend(ptr));
   endrule

   FIFOF#(Bit#(32)) idReturnFifo <- mkSizedBRAMFIFOF(valueOf(MaxNumSGLists));
   rule idReturnRule;
      let sglId <- toGet(idReturnFifo).get;
      sglId_gen.returnTag(truncate(sglId));
      portsel(regall, 1).request.put(BRAMRequest{write:True, responseOnWrite:False, address: truncate(sglId), datain: tagged Invalid });
      $display("idReturn %h", sglId);
   endrule

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		incomingReqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
`ifdef BSIM
		rv = rv | (fromInteger(iid)<<valueOf(addrWidth)-3);
`endif
`ifdef XSIM
		rv = rv | (fromInteger(iid)<<valueOf(addrWidth)-3);
`endif
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface MMURequest request;
   method Action idRequest(SpecialTypeForSendingFd fd);
      let nextId <- sglId_gen.getTag;
      let resp = (fromInteger(iid) << 16) | extend(nextId);
      if (verbose) $display("mkMMU::idRequest %d", fd);
      $display("mkMMU::idRequest %d", fd);
      let va <- pareff.initfd(resp, fd);
      mmuIndication.idResponse(resp);
   endmethod
   method Action idReturn(Bit#(32) sglId);
      idReturnFifo.enq(sglId);
   endmethod
   method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(32) index8, Bit#(64) barr4, Bit#(32) index4, Bit#(64) barr0, Bit#(32) index0);
      portsel(regall, 1).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(pointer), datain: tagged Valid Region{
             reg8: SingleRegion{barrier: truncate(barr8), idxOffset: truncate(index8)},
             reg4: SingleRegion{barrier: truncate(barr4), idxOffset: truncate(index4)},
             reg0: SingleRegion{barrier: truncate(barr0), idxOffset: truncate(index0)}} });
      if (verbose) $display("mkMMU::region pointer=%d barr8=%h barr4=%h barr0=%h", pointer, barr8, barr4, barr0);
      configRespFifo.enq(truncate(pointer));
   endmethod

   method Action sglist(Bit#(32) pointer, Bit#(32) pointerIndex, Bit#(64) addr,  Bit#(32) len);
         if (fromInteger(iid) != pointer[31:16]) begin
	    $display("mkMMU::sglist ERROR");
	    $finish();
	 end
	 if(hostMapped)
	    let va <- pareff.init({0,pointer[31:16]}, {0,pointer[15:0]}, len);
         Bit#(IndexWidth) ind = truncate(pointerIndex);
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(pointer),ind}, datain:truncate(addr)});
         if (verbose) $display("mkMMU::sglist pointer=%d pointerIndex=%d addr=%d len=%d", pointer, pointerIndex, addr, len);
   endmethod
   method Action setInterface(Bit#(32) interfaceId, Bit#(32) sglId);
       /* this method is only implemented in s/w responders */
   endmethod
   endinterface
   interface addr = addrServers;

endmodule

interface MMUAddrServer#(numeric type addrWidth, numeric type numServers);
   interface Vector#(numServers,Server#(ReqTup,Bit#(addrWidth))) servers;
endinterface

module mkMMUAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (MMUAddrServer#(addrWidth,numServers));

   FIFOF#(Bit#(TAdd#(1,TLog#(numServers)))) tokFifo <- mkSizedFIFOF(9);
   Vector#(numServers, Server#(ReqTup,Bit#(addrWidth))) addrServers;
   Reg#(Bit#(TLog#(numServers))) arb <- mkReg(0);

   // this is a very crude arbiter.  something more sophisticated may be required (mdk)
   rule inc_arb;
      arb <= arb+1;
   endrule

   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req) if (arb == fromInteger(i));
		tokFifo.enq(fromInteger(i));
		server.request.put(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get() if (tokFifo.first == fromInteger(i));
		tokFifo.deq;
		let rv <- server.response.get;
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface servers = addrServers;

endmodule

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

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

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

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

// BSV Libraries
import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import MemTypes::*;
import StmtFSM::*;
import ClientServer::*;
import ConnectalMemory::*;
import ConnectalCompletionBuffer::*;
import Pareff::*;

typedef 32 MaxNumSGLists;
typedef Bit#(TLog#(MaxNumSGLists)) SGListId;
typedef 12 SGListPageShift0;
typedef 16 SGListPageShift4;
typedef 20 SGListPageShift8;
typedef Bit#(TLog#(MaxNumSGLists)) RegionsIdx;

typedef 8 IndexWidth;

typedef struct {
   SGListId             id;
   Bit#(MemOffsetSize) off;
} ReqTup deriving (Eq,Bits,FShow);

interface MMU#(numeric type addrWidth);
   interface MMURequest request;
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef struct {
   Bit#(2) pageSize;
   Bit#(SGListPageShift8) value;
} Offset deriving (Eq,Bits,FShow);

typedef Bit#(TSub#(MemOffsetSize,SGListPageShift0)) Page0;
typedef Bit#(TSub#(MemOffsetSize,SGListPageShift4)) Page4;
typedef Bit#(TSub#(MemOffsetSize,SGListPageShift8)) Page8;

typedef struct {
   Bit#(TSub#(MemOffsetSize,SGListPageShift0)) barrier;
   Bit#(IndexWidth) idxOffset;
   } SingleRegion deriving (Eq,Bits,FShow);

typedef struct {
   SingleRegion reg8;
   SingleRegion reg4;
   SingleRegion reg0;
   } Region deriving (Eq,Bits,FShow);

typedef struct {DmaErrorType errorType;
		Bit#(32) pref;
		Bit#(MemOffsetSize) off;
   } DmaError deriving (Bits);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkMMU#(Integer iid, Bool hostMapped, MMUIndication mmuIndication)(MMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(a__,addrWidth,MemOffsetSize));

   let verbose = False;
   TagGen#(MaxNumSGLists) sglId_gen <- mkTagGen;
   rule complete_sglId_gen;
      let __x <- sglId_gen.complete;
   endrule

   // for simulators
   Pareff#(32) pareff <- mkPareff();

   // stage 0 (latency == 1)
   Vector#(2, FIFO#(ReqTup)) incomingReqs <- replicateM(mkFIFO);

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Maybe#(Region)) regall <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(ReqTup))          reqs0 <- replicateM(mkSizedFIFOF(3));

   // stage 2 (latency == 1)
   Vector#(2,FIFOF#(Tuple3#(Bool,Bool,Bool))) conds <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Tuple3#(Bit#(IndexWidth),Bit#(IndexWidth),Bit#(IndexWidth)))) idxOffsets0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(ReqTup))           reqs1 <- replicateM(mkSizedFIFOF(3));

   // stage 3 (latency == 1)
   Vector#(2,FIFOF#(Offset))           offs0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))    idxOffsets1 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))         ptrs1 <- replicateM(mkFIFOF);

   // stage 4 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page0) pages <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(Offset))           offs1 <- replicateM(mkSizedFIFOF(3));

   // stage 4 (latnecy == 1)
   Vector#(2,FIFOF#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFOF);

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      mmuIndication.error(extend(pack(error.errorType)), error.pref, extend(error.off), fromInteger(iid));
   endrule

   let page_shift0 = fromInteger(valueOf(SGListPageShift0));
   let page_shift4 = fromInteger(valueOf(SGListPageShift4));
   let page_shift8 = fromInteger(valueOf(SGListPageShift8));

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

   for (Integer i = 0; i < 2; i=i+1)
      rule stage1;  // first read in the address cutoff values between regions
	 ReqTup req <- toGet(incomingReqs[i]).get();
	 portsel(regall, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(req.id), datain:?});
	 reqs0[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2; // Now compare address cutoffs with requested offset
	 ReqTup req <- toGet(reqs0[i]).get;
	 Maybe#(Region) m_regionall <- portsel(regall,i).response.get;

	 case (m_regionall) matches
	    tagged Valid .regionall: begin
               Page0 off0 = truncate(req.off >> valueOf(SGListPageShift0));
               Page4 off4 = truncate(req.off >> valueOf(SGListPageShift4));
               Page8 off8 = truncate(req.off >> valueOf(SGListPageShift8));
	       let cond8 = off8 < truncate(regionall.reg8.barrier);
	       let cond4 = off4 < truncate(regionall.reg4.barrier);
	       let cond0 = off0 < regionall.reg0.barrier;

	       if (verbose) $display("mkMMU::stage2: id=%d off=%h (%h %h %h) (%h %h %h)", req.id, req.off,
				     regionall.reg8.barrier, regionall.reg4.barrier, regionall.reg0.barrier,
				     off8, off4, off0);

	       conds[i].enq(tuple3(cond8,cond4,cond0));
	       idxOffsets0[i].enq(tuple3(regionall.reg8.idxOffset,regionall.reg4.idxOffset, regionall.reg0.idxOffset));
	       reqs1[i].enq(req);
	    end
	    tagged Invalid:
	       dmaErrorFifo.enq(DmaError { errorType: DmaErrorSGLIdInvalid, pref: extend(req.id), off:req.off });
	 endcase
      endrule
      rule stage3; // Based on results of comparision, select a region, putting it into 'o.pageSize'.  idxOffset holds offset in sglist table of relevant entry
	 ReqTup req <- toGet(reqs1[i]).get;
	 Offset o = Offset{pageSize: 0, value: truncate(req.off)};
	 Bit#(IndexWidth) pbase = 0;
	 Bit#(IndexWidth) idxOffset = 0;

	 match{.cond8,.cond4,.cond0} <- toGet(conds[i]).get;
	 match{.idxOffset8,.idxOffset4,.idxOffset0} <- toGet(idxOffsets0[i]).get;

	 if (cond8) begin
	    if (verbose) $display("mkMMU::request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 3;
	    pbase = truncate(req.off>>page_shift8);
	    idxOffset = idxOffset8;
	 end
	 else if (cond4) begin
	    if (verbose) $display("mkMMU::request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 2;
	    pbase = truncate(req.off>>page_shift4);
	    idxOffset = idxOffset4;
	 end
	 else if (cond0) begin
	    if (verbose) $display("mkMMU::request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 1;
	    pbase = truncate(req.off>>page_shift0);
	    idxOffset = idxOffset0;
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets1[i].enq(idxOffset);
	 ptrs1[i].enq(req.id);
      endrule
      rule stage4; // Read relevant sglist entry
	 let off <- toGet(offs0[i]).get();
	 let pbase <- toGet(pbases[i]).get();
	 let idxOffset <- toGet(idxOffsets1[i]).get();
	 let ptr <- toGet(ptrs1[i]).get();
	 Bit#(IndexWidth) p = pbase + idxOffset;
	 if (off.pageSize == 0) begin
	    if (verbose) $display("mkMMU::addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorOffsetOutOfRange, pref: extend(ptr), off:extend(off.value) });
	 end
	 else begin
	    if (verbose) $display("mkMMU::pages[%d].read %h", i, {ptr,p});
	    portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
						      address:{ptr,p}, datain:?});
	    offs1[i].enq(off);
	 end
      endrule
      rule stage5; // Concatenate page base address from sglist entry with LSB offset bits from request and return
	 Page0 page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 if (verbose) $display("mkMMU::p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(MemOffsetSize) rv = ?;
	 Page4 b4 = truncate(page);
	 Page8 b8 = truncate(page);
	 case (offset.pageSize)
	    1: rv = {page,truncate(offset.value)};
	    2: rv = {b4,truncate(offset.value)};
	    3: rv = {b8,truncate(offset.value)};
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   FIFO#(SGListId) configRespFifo <- mkFIFO;
   rule sendConfigResp;
      let ptr <- toGet(configRespFifo).get();
      mmuIndication.configResp(extend(ptr));
   endrule

   FIFOF#(Bit#(32)) idReturnFifo <- mkSizedBRAMFIFOF(valueOf(MaxNumSGLists));
   rule idReturnRule;
      let sglId <- toGet(idReturnFifo).get;
      sglId_gen.returnTag(truncate(sglId));
      portsel(regall, 1).request.put(BRAMRequest{write:True, responseOnWrite:False, address: truncate(sglId), datain: tagged Invalid });
      $display("idReturn %h", sglId);
   endrule

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		incomingReqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
`ifdef BSIM
		rv = rv | (fromInteger(iid)<<valueOf(addrWidth)-3);
`endif
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface MMURequest request;
   method Action idRequest(SpecialTypeForSendingFd fd);
      let nextId <- sglId_gen.getTag;
      let resp = (fromInteger(iid) << 16) | extend(nextId);
      if (verbose) $display("mkMMU::idRequest %d", fd);
      let va <- pareff.initfd(resp, fd);
      mmuIndication.idResponse(resp);
   endmethod
   method Action idReturn(Bit#(32) sglId);
      idReturnFifo.enq(sglId);
   endmethod
   method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(32) index8, Bit#(64) barr4, Bit#(32) index4, Bit#(64) barr0, Bit#(32) index0);
      portsel(regall, 1).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(pointer), datain: tagged Valid Region{
             reg8: SingleRegion{barrier: truncate(barr8), idxOffset: truncate(index8)},
             reg4: SingleRegion{barrier: truncate(barr4), idxOffset: truncate(index4)},
             reg0: SingleRegion{barrier: truncate(barr0), idxOffset: truncate(index0)}} });
      if (verbose) $display("mkMMU::region pointer=%d barr8=%h barr4=%h barr0=%h", pointer, barr8, barr4, barr0);
      configRespFifo.enq(truncate(pointer));
   endmethod

   method Action sglist(Bit#(32) pointer, Bit#(32) pointerIndex, Bit#(64) addr,  Bit#(32) len);
         if (fromInteger(iid) != pointer[31:16]) begin
	    $display("mkMMU::sglist ERROR");
	    $finish();
	 end
	 if(hostMapped)
	    let va <- pareff.init({0,pointer[31:16]}, {0,pointer[15:0]}, len);
         Bit#(IndexWidth) ind = truncate(pointerIndex);
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(pointer),ind}, datain:truncate(addr)});
         if (verbose) $display("mkMMU::sglist pointer=%d pointerIndex=%d addr=%d len=%d", pointer, pointerIndex, addr, len);
   endmethod
   method Action setInterface(Bit#(32) interfaceId, Bit#(32) sglId);
       /* this method is only implemented in s/w responders */
   endmethod
   endinterface
   interface addr = addrServers;

endmodule

interface MMUAddrServer#(numeric type addrWidth, numeric type numServers);
   interface Vector#(numServers,Server#(ReqTup,Bit#(addrWidth))) servers;
endinterface

module mkMMUAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (MMUAddrServer#(addrWidth,numServers));

   FIFOF#(Bit#(TAdd#(1,TLog#(numServers)))) tokFifo <- mkSizedFIFOF(9);
   Vector#(numServers, Server#(ReqTup,Bit#(addrWidth))) addrServers;
   Reg#(Bit#(TLog#(numServers))) arb <- mkReg(0);

   // this is a very crude arbiter.  something more sophisticated may be required (mdk)
   rule inc_arb;
      arb <= arb+1;
   endrule

   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req) if (arb == fromInteger(i));
		tokFifo.enq(fromInteger(i));
		server.request.put(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get() if (tokFifo.first == fromInteger(i));
		tokFifo.deq;
		let rv <- server.response.get;
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface servers = addrServers;

endmodule


fix memwrite so it can be run repeatedly

// 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 BuildVector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import ClientServer::*;
import GetPut::*;
import HostInterface::*;
import MemTypes::*;
import MemwriteEngine::*;
import Pipe::*;
import AddressGenerator::*;

typedef TDiv#(DataBusWidth,32) WordsPerBeat;

interface MemwriteRequest;
   method Action startWrite(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) numReqs, Bit#(32) burstLen);
endinterface

interface MemwriteIndication;
   method Action writeDone(Bit#(32) v);
   method Action writeProgress(Bit#(32) v);
endinterface

interface Memwrite;
   interface MemwriteRequest request;
   interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaClients;
endinterface

module  mkMemwrite#(MemwriteIndication indication) (Memwrite);
   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))        numReqs <- mkReg(0);
   Reg#(Bit#(32))        numDone <- mkReg(0);
   Reg#(Bit#(MemOffsetSize)) reqOffset <- mkReg(0);
   Reg#(Bit#(3))                   tag <- mkReg(0);
   Reg#(Bit#(32))             numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   Reg#(Bit#(32))              srcGens <- mkReg(0);

   AddressGenerator#(32, DataBusWidth) addrGenerator <- mkAddressGenerator();
   FIFO#(MemRequest) reqFifo <- mkFIFO();
   FIFO#(PhysMemRequest#(32)) preqFifo <- mkFIFO();
   FIFO#(MemData#(DataBusWidth))   dataFifo <- mkSizedBRAMFIFO(1024);
   FIFO#(Bit#(MemTagSize)) doneFifo <- mkFIFO();

   let verboseProgress = False;

   rule start if (numReqs != 0);
      reqFifo.enq(MemRequest { sglId: pointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });
      preqFifo.enq(PhysMemRequest { addr: 0, burstLen: burstLenBytes, tag: extend(tag) });
      numReqs <= numReqs - 1;
      reqOffset <= reqOffset + extend(burstLenBytes);
      tag <= tag + 1;
      //$display("start numReqs", numReqs);
   endrule

   rule preq;
      let preq <- toGet(preqFifo).get();
      addrGenerator.request.put(preq);
   endrule

   rule finish;
      let donetag <- toGet(doneFifo).get();
      //$display("finished num todo=%d", numDone);
      if (numDone == 1) begin
         indication.writeDone(0);
      end
      numDone <= numDone - 1;
      if (verboseProgress)
	 indication.writeProgress(extend(donetag));
   endrule

   rule src if (numWords != 0);
      let b <- addrGenerator.addrBeat.get();

      function Bit#(32) plusi(Integer i); return srcGens + fromInteger(i); endfunction
      Vector#(WordsPerBeat, Bit#(32)) v = genWith(plusi);
      dataFifo.enq(MemData { data: pack(v), tag: b.tag, last: b.last});
      srcGens <= srcGens+fromInteger(valueOf(WordsPerBeat));
      numWords <= numWords - fromInteger(valueOf(WordsPerBeat));
   endrule

   MemWriteClient#(DataBusWidth) dmaClient = (interface MemWriteClient;
      interface Get writeReq = toGet(reqFifo);
      interface Get writeData = toGet(dataFifo);
      interface Put writeDone = toPut(doneFifo);
   endinterface );

   interface MemwriteRequest request;
       method Action startWrite(Bit#(32) wp, Bit#(32) nw, Bit#(32) nreq, Bit#(32) bl);
	  $dumpvars();
          $display("startWrite pointer=%d numWords=%d (%d) numReqs=%d burstLen=%d", pointer, nw, nreq*bl, nreq, bl);
          pointer <= wp;
          numWords  <= nw;
          burstLenBytes <= truncate(bl);
	  numReqs <= nreq;
	  numDone <= nreq;

	  reqOffset <= 0;
	  srcGens <= 0;
       endmethod
   endinterface
   interface dmaClients = vec(dmaClient);

endmodule

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

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

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

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

import Vector::*;
import BuildVector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import ClientServer::*;
import GetPut::*;
import HostInterface::*;
import MemTypes::*;
import MemwriteEngine::*;
import Pipe::*;
import AddressGenerator::*;

typedef TDiv#(DataBusWidth,32) WordsPerBeat;

interface MemwriteRequest;
   method Action startWrite(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) numReqs, Bit#(32) burstLen);
endinterface

interface MemwriteIndication;
   method Action writeDone(Bit#(32) v);
   method Action writeProgress(Bit#(32) v);
endinterface

interface Memwrite;
   interface MemwriteRequest request;
   interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaClients;
endinterface

module  mkMemwrite#(MemwriteIndication indication) (Memwrite);
   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))        numReqs <- mkReg(0);
   Reg#(Bit#(32))        numDone <- mkReg(0);
   Reg#(Bit#(MemOffsetSize)) reqOffset <- mkReg(0);
   Reg#(Bit#(3))                   tag <- mkReg(0);
   Reg#(Bit#(32))             numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   Reg#(Bit#(32))              srcGens <- mkReg(0);

   AddressGenerator#(32, DataBusWidth) addrGenerator <- mkAddressGenerator();
   FIFO#(MemRequest) reqFifo <- mkFIFO();
   FIFO#(PhysMemRequest#(32)) preqFifo <- mkFIFO();
   FIFO#(MemData#(DataBusWidth))   dataFifo <- mkSizedBRAMFIFO(1024);
   FIFO#(Bit#(MemTagSize)) doneFifo <- mkFIFO();

   let verboseProgress = False;

   rule start if (numReqs != 0);
      reqFifo.enq(MemRequest { sglId: pointer, offset: reqOffset, burstLen: burstLenBytes, tag: extend(tag) });
      preqFifo.enq(PhysMemRequest { addr: 0, burstLen: burstLenBytes, tag: extend(tag) });
      numReqs <= numReqs - 1;
      reqOffset <= reqOffset + extend(burstLenBytes);
      tag <= tag + 1;
      //$display("start numReqs", numReqs);
   endrule

   rule preq;
      let preq <- toGet(preqFifo).get();
      addrGenerator.request.put(preq);
   endrule

   rule finish;
      let donetag <- toGet(doneFifo).get();
      //$display("finished num todo=%d", numDone);
      if (numDone == 1) begin
         indication.writeDone(0);
      end
      numDone <= numDone - 1;
      if (verboseProgress)
	 indication.writeProgress(extend(donetag));
   endrule

   rule src if (numWords != 0);
      let b <- addrGenerator.addrBeat.get();

      function Bit#(32) plusi(Integer i); return srcGens + fromInteger(i); endfunction
      Vector#(WordsPerBeat, Bit#(32)) v = genWith(plusi);
      dataFifo.enq(MemData { data: pack(v), tag: b.tag, last: b.last});
      srcGens <= srcGens+fromInteger(valueOf(WordsPerBeat));
      numWords <= numWords - fromInteger(valueOf(WordsPerBeat));
   endrule

   MemWriteClient#(DataBusWidth) dmaClient = (interface MemWriteClient;
      interface Get writeReq = toGet(reqFifo);
      interface Get writeData = toGet(dataFifo);
      interface Put writeDone = toPut(doneFifo);
   endinterface );

   interface MemwriteRequest request;
       method Action startWrite(Bit#(32) wp, Bit#(32) nw, Bit#(32) nreq, Bit#(32) bl);
	  $dumpvars();
          $display("startWrite pointer=%d numWords=%d (%d) numReqs=%d burstLen=%d", pointer, nw, nreq*bl, nreq, bl);
          pointer <= wp;
          numWords  <= nw;
          burstLenBytes <= truncate(bl);
	  numReqs <= nreq;
	  numDone <= nreq;
       endmethod
   endinterface
   interface dmaClients = vec(dmaClient);

endmodule


missed one case

missed one case

// Copyright (c) 2014 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.

package DtpRx;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;
typedef 5 RXTX_DELAY;

interface DtpRx;
   interface PipeIn#(Bit#(66))  dtpRxIn;
   interface PipeOut#(Bit#(66)) dtpRxOut;
   interface PipeOut#(DtpEvent) dtpEventOut;
   interface PipeOut#(Bit#(32)) dtpErrCnt;
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   method Action bsync_lock(Bool v);
endinterface

(* synthesize *)
module mkDtpRxTop(DtpRx);
   DtpRx _a <- mkDtpRx(0, 0);
   return _a;
endmodule

module mkDtpRx#(Integer id, Integer c_local_init)(DtpRx);

   let verbose = True;

   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);
   Wire#(Bool) bsync_lock_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpRxInFifo    <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo   <- mkFIFOF;
   FIFOF#(DtpEvent) dtpEventOutFifo <- mkFIFOF;
   FIFOF#(Bit#(32)) dtpErrCntFifo  <- mkFIFOF;

   Reg#(Bit#(32))  err_cnt <- mkReg(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   rule rx_bypass(!rx_ready_wire);
      let v <- toGet(dtpRxInFifo).get;
      dtpRxOutFifo.enq(v);
   endrule

   // Parse received DTP frame
   // Remove DTP timestamp before passing frame to MAC.
   rule parse_dtp_message(rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      let rxtx_delay  = fromInteger(valueOf(RXTX_DELAY));
      let v <- toGet(dtpRxInFifo).get();
      //if(verbose) $display("%d: %d dtpRxIn=%h", cycle, id, v);
      Bit#(1)  parity = ^v[65:13];
      Bit#(53) c_remote = v[65:13];
      Bit#(66) vo = v;

      let c_remote_compensated = c_remote + rxtx_delay;

      if (v[9:2] == 8'h1e) begin
         vo[65:10] = 56'h0;
         if (v[11:10] == init_type && bsync_lock_wire) begin
            if (parity == v[12]) begin
               if(dtpEventOutFifo.notFull && bsync_lock_wire) begin
                  dtpEventOutFifo.enq(DtpEvent{e:zeroExtend(v[11:10]), t:c_remote});
               end
               if(verbose) $display("%d: %d init_rcvd %d, forward to tx %d", cycle, id, c_remote, c_remote_compensated);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == ack_type && bsync_lock_wire) begin
            if (parity == v[12]) begin
               if(dtpEventOutFifo.notFull) begin
                  dtpEventOutFifo.enq(DtpEvent{e:zeroExtend(v[11:10]), t:c_remote});
               end
               if(verbose) $display("%d: %d ack_rcvd %d, forward to tx %d", cycle, id, c_remote, c_remote_compensated);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == beacon_type && bsync_lock_wire) begin
            if (parity == v[12]) begin
               if(dtpEventOutFifo.notFull) begin
                  dtpEventOutFifo.enq(DtpEvent{e:zeroExtend(v[11:10]), t:c_remote_compensated});
               end
               if(verbose) $display("%d: %d beacon_rcvd %d, forward to tx %d", cycle, id, c_remote, c_remote_compensated);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[12:10] == log_type && bsync_lock_wire) begin
            // send v[65:13] to logger, when bsync_lock is True
            if (dtpEventOutFifo.notFull) begin
               $display("%d: %d received log message %h", cycle, id, v[65:13]);
               dtpEventOutFifo.enq(DtpEvent{e:v[12:10], t:v[65:13]});
            end
         end
//         else begin
//            err_cnt <= err_cnt + 1;
//            dtpErrCntFifo.enq(err_cnt);
//         end
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
      dtpRxOutFifo.enq(vo);
   endrule

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   method Action bsync_lock(Bool v);
      bsync_lock_wire <= v;
   endmethod

   interface dtpRxIn = toPipeIn(dtpRxInFifo);
   interface dtpRxOut = toPipeOut(dtpRxOutFifo);
   interface dtpEventOut = toPipeOut(dtpEventOutFifo);
   interface dtpErrCnt = toPipeOut(dtpErrCntFifo);
endmodule
endpackage: DtpRx

// Copyright (c) 2014 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.

package DtpRx;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;
typedef 5 RXTX_DELAY;

interface DtpRx;
   interface PipeIn#(Bit#(66))  dtpRxIn;
   interface PipeOut#(Bit#(66)) dtpRxOut;
   interface PipeOut#(DtpEvent) dtpEventOut;
   interface PipeOut#(Bit#(32)) dtpErrCnt;
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   method Action bsync_lock(Bool v);
endinterface

(* synthesize *)
module mkDtpRxTop(DtpRx);
   DtpRx _a <- mkDtpRx(0, 0);
   return _a;
endmodule

module mkDtpRx#(Integer id, Integer c_local_init)(DtpRx);

   let verbose = True;

   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);
   Wire#(Bool) bsync_lock_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpRxInFifo    <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo   <- mkFIFOF;
   FIFOF#(DtpEvent) dtpEventOutFifo <- mkFIFOF;
   FIFOF#(Bit#(32)) dtpErrCntFifo  <- mkFIFOF;

   Reg#(Bit#(32))  err_cnt <- mkReg(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   rule rx_bypass(!rx_ready_wire);
      let v <- toGet(dtpRxInFifo).get;
      dtpRxOutFifo.enq(v);
   endrule

   // Parse received DTP frame
   // Remove DTP timestamp before passing frame to MAC.
   rule parse_dtp_message(rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      let rxtx_delay  = fromInteger(valueOf(RXTX_DELAY));
      let v <- toGet(dtpRxInFifo).get();
      //if(verbose) $display("%d: %d dtpRxIn=%h", cycle, id, v);
      Bit#(1)  parity = ^v[65:13];
      Bit#(53) c_remote = v[65:13];
      Bit#(66) vo = v;

      let c_remote_compensated = c_remote + rxtx_delay;

      if (v[9:2] == 8'h1e) begin
         vo[65:10] = 56'h0;
         if (v[11:10] == init_type) begin
            if (parity == v[12]) begin
               if(dtpEventOutFifo.notFull && bsync_lock_wire) begin
                  dtpEventOutFifo.enq(DtpEvent{e:zeroExtend(v[11:10]), t:c_remote});
               end
               if(verbose) $display("%d: %d init_rcvd %d, forward to tx %d", cycle, id, c_remote, c_remote_compensated);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == ack_type && bsync_lock_wire) begin
            if (parity == v[12]) begin
               if(dtpEventOutFifo.notFull) begin
                  dtpEventOutFifo.enq(DtpEvent{e:zeroExtend(v[11:10]), t:c_remote});
               end
               if(verbose) $display("%d: %d ack_rcvd %d, forward to tx %d", cycle, id, c_remote, c_remote_compensated);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == beacon_type && bsync_lock_wire) begin
            if (parity == v[12]) begin
               if(dtpEventOutFifo.notFull) begin
                  dtpEventOutFifo.enq(DtpEvent{e:zeroExtend(v[11:10]), t:c_remote_compensated});
               end
               if(verbose) $display("%d: %d beacon_rcvd %d, forward to tx %d", cycle, id, c_remote, c_remote_compensated);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[12:10] == log_type && bsync_lock_wire) begin
            // send v[65:13] to logger, when bsync_lock is True
            if (dtpEventOutFifo.notFull) begin
               $display("%d: %d received log message %h", cycle, id, v[65:13]);
               dtpEventOutFifo.enq(DtpEvent{e:v[12:10], t:v[65:13]});
            end
         end
//         else begin
//            err_cnt <= err_cnt + 1;
//            dtpErrCntFifo.enq(err_cnt);
//         end
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
      dtpRxOutFifo.enq(vo);
   endrule

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   method Action bsync_lock(Bool v);
      bsync_lock_wire <= v;
   endmethod

   interface dtpRxIn = toPipeIn(dtpRxInFifo);
   interface dtpRxOut = toPipeOut(dtpRxOutFifo);
   interface dtpEventOut = toPipeOut(dtpEventOutFifo);
   interface dtpErrCnt = toPipeOut(dtpErrCntFifo);
endmodule
endpackage: DtpRx


Add xdma (PCIe root bridge) address ranges.

// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved

package SoC_Map;

// ================================================================
// This module defines the overall 'address map' of the SoC, showing
// the addresses serviced by each slave IP, and which addresses are
// memory vs. I/O.

// ***** WARNING! WARNING! WARNING! *****

// During system integration, this address map should be identical to
// the system interconnect settings (e.g., routing of requests between
// masters and slaves).  This map is also needed by software so that
// it knows how to address various IPs.

// This module contains no state; it just has constants, and so can be
// freely instantiated at multiple places in the SoC module hierarchy
// at no hardware cost.  It allows this map to be defined in one
// place and shared across the SoC.

// ================================================================
// This version of SoC_Map is for the DARPA SSITH GFE

// Our "Near_Mem_IO" corresponds to "CLINT" in Rocket

// ================================================================
// Exports

export  SoC_Map_IFC (..), mkSoC_Map;

export  N_External_Interrupt_Sources;
export  n_external_interrupt_sources;
export  irq_num_uart16550_0;

// ================================================================
// Bluespec library imports

// None

// ================================================================
// Project imports

import Fabric_Defs :: *;    // Only for type Fabric_Addr

// ================================================================

function Bool addr_function(Fabric_Addr base, Fabric_Addr size, Fabric_Addr addr);
   return (base <= addr) && (addr < (base + size));
endfunction

// ================================================================
// Interface and module for the address map

interface SoC_Map_IFC;
   (* always_ready *)   method  Fabric_Addr  m_plic_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_plic_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_plic_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_near_mem_io_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_near_mem_io_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_near_mem_io_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_flash_mem_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_flash_mem_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_flash_mem_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_ethernet_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_ethernet_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_ethernet_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_dma_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_dma_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_dma_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_uart16550_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_uart16550_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_uart16550_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_gpio_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_gpio_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_gpio_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_boot_rom_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_boot_rom_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_boot_rom_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_uncached_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_uncached_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_uncached_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_cached_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_cached_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_cached_addr_lim;

   (* always_ready *)
   method  Bool  m_is_mem_addr (Fabric_Addr addr);

   (* always_ready *)
   method  Bool  m_is_IO_addr (Fabric_Addr addr);

   (* always_ready *)
   method  Bool  m_is_near_mem_IO_addr (Fabric_Addr addr);

   (* always_ready *)   method  Bit #(64)  m_pc_reset_value;
   (* always_ready *)   method  Bit #(64)  m_mtvec_reset_value;
   (* always_ready *)   method  Bit #(64)  m_nmivec_reset_value;
endinterface

// ================================================================

(* synthesize *)
module mkSoC_Map (SoC_Map_IFC);

   // ----------------------------------------------------------------
   // PLIC

   Fabric_Addr plic_addr_base = 'h_0C00_0000;
   Fabric_Addr plic_addr_size = 'h_0040_0000;    // 4M
   Fabric_Addr plic_addr_lim  = plic_addr_base + plic_addr_size;

   function Bool fn_is_plic_addr (Fabric_Addr addr);
      return ((plic_addr_base <= addr) && (addr < plic_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // Near_Mem_IO (CLINT)

   Fabric_Addr near_mem_io_addr_base = 'h_1000_0000;
   Fabric_Addr near_mem_io_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr near_mem_io_addr_lim  = near_mem_io_addr_base + near_mem_io_addr_size;

   function Bool fn_is_near_mem_io_addr (Fabric_Addr addr);
      return ((near_mem_io_addr_base <= addr) && (addr < near_mem_io_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // Flash Mem

   Fabric_Addr flash_mem_addr_base = 'h_4000_0000;
   Fabric_Addr flash_mem_addr_size = 'h_0800_0000;    // 128M
   Fabric_Addr flash_mem_addr_lim  = flash_mem_addr_base + flash_mem_addr_size;

   function Bool fn_is_flash_mem_addr (Fabric_Addr addr);
      return ((flash_mem_addr_base <= addr) && (addr < flash_mem_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // Ethernet 0

   Fabric_Addr ethernet_0_addr_base = 'h_6210_0000;
   Fabric_Addr ethernet_0_addr_size = 'h_0004_0000;    // 256K
   Fabric_Addr ethernet_0_addr_lim  = ethernet_0_addr_base + ethernet_0_addr_size;

   function Bool fn_is_ethernet_0_addr (Fabric_Addr addr);
      return ((ethernet_0_addr_base <= addr) && (addr < ethernet_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // DMA 0

   Fabric_Addr dma_0_addr_base = 'h_6220_0000;
   Fabric_Addr dma_0_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr dma_0_addr_lim  = dma_0_addr_base + dma_0_addr_size;

   function Bool fn_is_dma_0_addr (Fabric_Addr addr);
      return ((dma_0_addr_base <= addr) && (addr < dma_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // UART 0

   Fabric_Addr uart16550_0_addr_base = 'h_6230_0000;
   Fabric_Addr uart16550_0_addr_size = 'h_0000_1000;    // 4K
   Fabric_Addr uart16550_0_addr_lim  = uart16550_0_addr_base + uart16550_0_addr_size;

   function Bool fn_is_uart16550_0_addr (Fabric_Addr addr);
      return ((uart16550_0_addr_base <= addr) && (addr < uart16550_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // GPIO 0

   Fabric_Addr gpio_0_addr_base = 'h_6FFF_0000;
   Fabric_Addr gpio_0_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr gpio_0_addr_lim  = gpio_0_addr_base + gpio_0_addr_size;

   function Bool fn_is_gpio_0_addr (Fabric_Addr addr);
      return ((gpio_0_addr_base <= addr) && (addr < gpio_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // Boot ROM

   Fabric_Addr boot_rom_addr_base = 'h_7000_0000;
   Fabric_Addr boot_rom_addr_size = 'h_0000_1000;    // 4K
   Fabric_Addr boot_rom_addr_lim  = boot_rom_addr_base + boot_rom_addr_size;

   function Bool fn_is_boot_rom_addr (Fabric_Addr addr);
      return ((boot_rom_addr_base <= addr) && (addr < boot_rom_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // DDR memory 0 uncached

   Fabric_Addr ddr4_0_uncached_addr_base = 'h_8000_0000;
   Fabric_Addr ddr4_0_uncached_addr_size = 'h_4000_0000;    // 1G
   Fabric_Addr ddr4_0_uncached_addr_lim  = ddr4_0_uncached_addr_base + ddr4_0_uncached_addr_size;

   function Bool fn_is_ddr4_0_uncached_addr (Fabric_Addr addr);
      return ((ddr4_0_uncached_addr_base <= addr) && (addr < ddr4_0_uncached_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // DDR memory 0 cached

   Fabric_Addr ddr4_0_cached_addr_base = 'h_C000_0000;
   Fabric_Addr ddr4_0_cached_addr_size = 'h_4000_0000;    // 1G
   Fabric_Addr ddr4_0_cached_addr_lim  = ddr4_0_cached_addr_base + ddr4_0_cached_addr_size;

   function Bool fn_is_ddr4_0_cached_addr (Fabric_Addr addr);
      return ((ddr4_0_cached_addr_base <= addr) && (addr < ddr4_0_cached_addr_lim));
   endfunction

   // ----------------------------------------------------------------

   function fn_is_flash_regs_addr = addr_function('h6240_0000, 'h1000);
   function fn_is_uart1_addr = addr_function('h6230_0000, 'h1000);
   function fn_is_i2c_addr = addr_function('h6231_0000, 'h1000);
   function fn_is_spi_addr = addr_function('h6232_0000, 'h1000);
   function fn_is_uart2_addr = addr_function('h6236_0000, 'h1000);
   function fn_is_gpio1_addr = addr_function('h6233_0000, 'h1000);
   function fn_is_gpio2_addr = addr_function('h6237_0000, 'h1000);

   function fn_is_xdma_control = addr_function('h2000_0000, 'h1000_0000);
   function fn_is_xdma_ecam = addr_function('h3000_0000, 'h1000_0000);

   // ----------------------------------------------------------------
   // Memory address predicate
   // Identifies memory addresses in the Fabric.
   // (Caches needs this information to cache these addresses.)

   function Bool fn_is_mem_addr (Fabric_Addr addr);
      return (   fn_is_ddr4_0_cached_addr (addr)
	      );
   endfunction

   // ----------------------------------------------------------------
   // I/O address predicate
   // Identifies I/O addresses in the Fabric.
   // (Caches needs this information to avoid cacheing these addresses.)

   function Bool fn_is_IO_addr (Fabric_Addr addr);
      return (   fn_is_plic_addr (addr)
	      || fn_is_near_mem_io_addr (addr)
	      || fn_is_flash_mem_addr (addr)
	      || fn_is_ethernet_0_addr (addr)
	      || fn_is_dma_0_addr (addr)
	      || fn_is_uart16550_0_addr  (addr)
	      || fn_is_gpio_0_addr (addr)
	      || fn_is_boot_rom_addr (addr)
	      || fn_is_ddr4_0_uncached_addr (addr)
	      || fn_is_flash_regs_addr (addr)
	      || fn_is_uart1_addr (addr)
	      || fn_is_i2c_addr (addr)
	      || fn_is_spi_addr (addr)
	      || fn_is_uart2_addr (addr)
	      || fn_is_gpio1_addr (addr)
	      || fn_is_gpio2_addr (addr)
	      || fn_is_xdma_control (addr)
	      || fn_is_xdma_ecam (addr)
	      );
   endfunction

   // ----------------------------------------------------------------
   // PC, MTVEC and NMIVEC reset values

   Bit #(64) pc_reset_value     = boot_rom_addr_base;
   Bit #(64) mtvec_reset_value  = 'h1000;    // TODO
   Bit #(64) nmivec_reset_value = ?;         // TODO

   // ================================================================
   // INTERFACE

   method  Fabric_Addr  m_plic_addr_base = plic_addr_base;
   method  Fabric_Addr  m_plic_addr_size = plic_addr_size;
   method  Fabric_Addr  m_plic_addr_lim  = plic_addr_lim;

   method  Fabric_Addr  m_near_mem_io_addr_base = near_mem_io_addr_base;
   method  Fabric_Addr  m_near_mem_io_addr_size = near_mem_io_addr_size;
   method  Fabric_Addr  m_near_mem_io_addr_lim  = near_mem_io_addr_lim;

   method  Fabric_Addr  m_flash_mem_addr_base = flash_mem_addr_base;
   method  Fabric_Addr  m_flash_mem_addr_size = flash_mem_addr_size;
   method  Fabric_Addr  m_flash_mem_addr_lim  = flash_mem_addr_lim;

   method  Fabric_Addr  m_ethernet_0_addr_base = ethernet_0_addr_base;
   method  Fabric_Addr  m_ethernet_0_addr_size = ethernet_0_addr_size;
   method  Fabric_Addr  m_ethernet_0_addr_lim  = ethernet_0_addr_lim;

   method  Fabric_Addr  m_dma_0_addr_base = dma_0_addr_base;
   method  Fabric_Addr  m_dma_0_addr_size = dma_0_addr_size;
   method  Fabric_Addr  m_dma_0_addr_lim  = dma_0_addr_lim;

   method  Fabric_Addr  m_uart16550_0_addr_base = uart16550_0_addr_base;
   method  Fabric_Addr  m_uart16550_0_addr_size = uart16550_0_addr_size;
   method  Fabric_Addr  m_uart16550_0_addr_lim  = uart16550_0_addr_lim;

   method  Fabric_Addr  m_gpio_0_addr_base = gpio_0_addr_base;
   method  Fabric_Addr  m_gpio_0_addr_size = gpio_0_addr_size;
   method  Fabric_Addr  m_gpio_0_addr_lim  = gpio_0_addr_lim;

   method  Fabric_Addr  m_boot_rom_addr_base = boot_rom_addr_base;
   method  Fabric_Addr  m_boot_rom_addr_size = boot_rom_addr_size;
   method  Fabric_Addr  m_boot_rom_addr_lim  = boot_rom_addr_lim;

   method  Fabric_Addr  m_ddr4_0_uncached_addr_base = ddr4_0_uncached_addr_base;
   method  Fabric_Addr  m_ddr4_0_uncached_addr_size = ddr4_0_uncached_addr_size;
   method  Fabric_Addr  m_ddr4_0_uncached_addr_lim  = ddr4_0_uncached_addr_lim;

   method  Fabric_Addr  m_ddr4_0_cached_addr_base = ddr4_0_cached_addr_base;
   method  Fabric_Addr  m_ddr4_0_cached_addr_size = ddr4_0_cached_addr_size;
   method  Fabric_Addr  m_ddr4_0_cached_addr_lim  = ddr4_0_cached_addr_lim;

   method  Bool  m_is_mem_addr (Fabric_Addr addr) = fn_is_mem_addr (addr);

   method  Bool  m_is_IO_addr (Fabric_Addr addr) = fn_is_IO_addr (addr);

   method  Bool  m_is_near_mem_IO_addr (Fabric_Addr addr) = fn_is_near_mem_io_addr (addr);

   method  Bit #(64)  m_pc_reset_value     = pc_reset_value;
   method  Bit #(64)  m_mtvec_reset_value  = mtvec_reset_value;
   method  Bit #(64)  m_nmivec_reset_value = nmivec_reset_value;
endmodule

// ================================================================
// Interrupt request numbers (== index in to vector of
// interrupt-request lines in Core)

typedef  16  N_External_Interrupt_Sources;
Integer  n_external_interrupt_sources = valueOf (N_External_Interrupt_Sources);

Integer irq_num_uart16550_0 = 0;

// ================================================================

endpackage

// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved

package SoC_Map;

// ================================================================
// This module defines the overall 'address map' of the SoC, showing
// the addresses serviced by each slave IP, and which addresses are
// memory vs. I/O.

// ***** WARNING! WARNING! WARNING! *****

// During system integration, this address map should be identical to
// the system interconnect settings (e.g., routing of requests between
// masters and slaves).  This map is also needed by software so that
// it knows how to address various IPs.

// This module contains no state; it just has constants, and so can be
// freely instantiated at multiple places in the SoC module hierarchy
// at no hardware cost.  It allows this map to be defined in one
// place and shared across the SoC.

// ================================================================
// This version of SoC_Map is for the DARPA SSITH GFE

// Our "Near_Mem_IO" corresponds to "CLINT" in Rocket

// ================================================================
// Exports

export  SoC_Map_IFC (..), mkSoC_Map;

export  N_External_Interrupt_Sources;
export  n_external_interrupt_sources;
export  irq_num_uart16550_0;

// ================================================================
// Bluespec library imports

// None

// ================================================================
// Project imports

import Fabric_Defs :: *;    // Only for type Fabric_Addr

// ================================================================

function Bool addr_function(Fabric_Addr base, Fabric_Addr size, Fabric_Addr addr);
   return (base <= addr) && (addr < (base + size));
endfunction

// ================================================================
// Interface and module for the address map

interface SoC_Map_IFC;
   (* always_ready *)   method  Fabric_Addr  m_plic_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_plic_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_plic_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_near_mem_io_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_near_mem_io_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_near_mem_io_addr_lim;

   /* REMOVED?
   (* always_ready *)   method  Fabric_Addr  m_pcie_ecam_slave_bridge_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_pcie_ecam_slave_bridge_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_pcie_ecam_slave_bridge_addr_lim;
   */

   (* always_ready *)   method  Fabric_Addr  m_flash_mem_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_flash_mem_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_flash_mem_addr_lim;

   /* REMOVED?
   (* always_ready *)   method  Fabric_Addr  m_pcie_block_registers_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_pcie_block_registers_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_pcie_block_registers_addr_lim;
   */

   (* always_ready *)   method  Fabric_Addr  m_ethernet_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_ethernet_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_ethernet_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_dma_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_dma_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_dma_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_uart16550_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_uart16550_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_uart16550_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_gpio_0_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_gpio_0_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_gpio_0_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_boot_rom_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_boot_rom_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_boot_rom_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_uncached_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_uncached_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_uncached_addr_lim;

   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_cached_addr_base;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_cached_addr_size;
   (* always_ready *)   method  Fabric_Addr  m_ddr4_0_cached_addr_lim;

   (* always_ready *)
   method  Bool  m_is_mem_addr (Fabric_Addr addr);

   (* always_ready *)
   method  Bool  m_is_IO_addr (Fabric_Addr addr);

   (* always_ready *)
   method  Bool  m_is_near_mem_IO_addr (Fabric_Addr addr);

   (* always_ready *)   method  Bit #(64)  m_pc_reset_value;
   (* always_ready *)   method  Bit #(64)  m_mtvec_reset_value;
   (* always_ready *)   method  Bit #(64)  m_nmivec_reset_value;
endinterface

// ================================================================

(* synthesize *)
module mkSoC_Map (SoC_Map_IFC);

   // ----------------------------------------------------------------
   // PLIC

   Fabric_Addr plic_addr_base = 'h_0C00_0000;
   Fabric_Addr plic_addr_size = 'h_0040_0000;    // 4M
   Fabric_Addr plic_addr_lim  = plic_addr_base + plic_addr_size;

   function Bool fn_is_plic_addr (Fabric_Addr addr);
      return ((plic_addr_base <= addr) && (addr < plic_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // Near_Mem_IO (CLINT)

   Fabric_Addr near_mem_io_addr_base = 'h_1000_0000;
   Fabric_Addr near_mem_io_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr near_mem_io_addr_lim  = near_mem_io_addr_base + near_mem_io_addr_size;

   function Bool fn_is_near_mem_io_addr (Fabric_Addr addr);
      return ((near_mem_io_addr_base <= addr) && (addr < near_mem_io_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // PCIE_ECAM_SLAVE_BRIDGE

   /* REMOVED?
   Fabric_Addr pcie_ecam_slave_bridge_addr_base = 'h_2000_0000;
   Fabric_Addr pcie_ecam_slave_bridge_addr_size = 'h_2000_0000;    // 512M
   Fabric_Addr pcie_ecam_slave_bridge_addr_lim  = (  pcie_ecam_slave_bridge_addr_base
						   + pcie_ecam_slave_bridge_addr_size);

   function Bool fn_is_pcie_ecam_slave_bridge_addr (Fabric_Addr addr);
      return ((pcie_ecam_slave_bridge_addr_base <= addr) && (addr < pcie_ecam_slave_bridge_addr_lim));
   endfunction
   */

   // ----------------------------------------------------------------
   // Flash Mem

   Fabric_Addr flash_mem_addr_base = 'h_4000_0000;
   Fabric_Addr flash_mem_addr_size = 'h_0800_0000;    // 128M
   Fabric_Addr flash_mem_addr_lim  = flash_mem_addr_base + flash_mem_addr_size;

   function Bool fn_is_flash_mem_addr (Fabric_Addr addr);
      return ((flash_mem_addr_base <= addr) && (addr < flash_mem_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // PCIe Block Registers

   /* REMOVED?
   Fabric_Addr pcie_block_registers_addr_base = 'h_6000_0000;
   Fabric_Addr pcie_block_registers_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr pcie_block_registers_addr_lim  = ( pcie_block_registers_addr_base
						 + pcie_block_registers_addr_size);

   function Bool fn_is_pcie_block_registers_addr (Fabric_Addr addr);
      return ((pcie_block_registers_addr_base <= addr) && (addr < pcie_block_registers_addr_lim));
   endfunction
   */

   // ----------------------------------------------------------------
   // Ethernet 0

   Fabric_Addr ethernet_0_addr_base = 'h_6210_0000;
   Fabric_Addr ethernet_0_addr_size = 'h_0004_0000;    // 256K
   Fabric_Addr ethernet_0_addr_lim  = ethernet_0_addr_base + ethernet_0_addr_size;

   function Bool fn_is_ethernet_0_addr (Fabric_Addr addr);
      return ((ethernet_0_addr_base <= addr) && (addr < ethernet_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // DMA 0

   Fabric_Addr dma_0_addr_base = 'h_6220_0000;
   Fabric_Addr dma_0_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr dma_0_addr_lim  = dma_0_addr_base + dma_0_addr_size;

   function Bool fn_is_dma_0_addr (Fabric_Addr addr);
      return ((dma_0_addr_base <= addr) && (addr < dma_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // UART 0

   Fabric_Addr uart16550_0_addr_base = 'h_6230_0000;
   Fabric_Addr uart16550_0_addr_size = 'h_0000_1000;    // 4K
   Fabric_Addr uart16550_0_addr_lim  = uart16550_0_addr_base + uart16550_0_addr_size;

   function Bool fn_is_uart16550_0_addr (Fabric_Addr addr);
      return ((uart16550_0_addr_base <= addr) && (addr < uart16550_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // GPIO 0

   Fabric_Addr gpio_0_addr_base = 'h_6FFF_0000;
   Fabric_Addr gpio_0_addr_size = 'h_0001_0000;    // 64K
   Fabric_Addr gpio_0_addr_lim  = gpio_0_addr_base + gpio_0_addr_size;

   function Bool fn_is_gpio_0_addr (Fabric_Addr addr);
      return ((gpio_0_addr_base <= addr) && (addr < gpio_0_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // Boot ROM

   Fabric_Addr boot_rom_addr_base = 'h_7000_0000;
   Fabric_Addr boot_rom_addr_size = 'h_0000_1000;    // 4K
   Fabric_Addr boot_rom_addr_lim  = boot_rom_addr_base + boot_rom_addr_size;

   function Bool fn_is_boot_rom_addr (Fabric_Addr addr);
      return ((boot_rom_addr_base <= addr) && (addr < boot_rom_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // DDR memory 0 uncached

   Fabric_Addr ddr4_0_uncached_addr_base = 'h_8000_0000;
   Fabric_Addr ddr4_0_uncached_addr_size = 'h_4000_0000;    // 1G
   Fabric_Addr ddr4_0_uncached_addr_lim  = ddr4_0_uncached_addr_base + ddr4_0_uncached_addr_size;

   function Bool fn_is_ddr4_0_uncached_addr (Fabric_Addr addr);
      return ((ddr4_0_uncached_addr_base <= addr) && (addr < ddr4_0_uncached_addr_lim));
   endfunction

   // ----------------------------------------------------------------
   // DDR memory 0 cached

   Fabric_Addr ddr4_0_cached_addr_base = 'h_C000_0000;
   Fabric_Addr ddr4_0_cached_addr_size = 'h_4000_0000;    // 1G
   Fabric_Addr ddr4_0_cached_addr_lim  = ddr4_0_cached_addr_base + ddr4_0_cached_addr_size;

   function Bool fn_is_ddr4_0_cached_addr (Fabric_Addr addr);
      return ((ddr4_0_cached_addr_base <= addr) && (addr < ddr4_0_cached_addr_lim));
   endfunction

   // ----------------------------------------------------------------

   function fn_is_flash_regs_addr = addr_function('h6240_0000, 'h1000);
   function fn_is_uart1_addr = addr_function('h6230_0000, 'h1000);
   function fn_is_i2c_addr = addr_function('h6231_0000, 'h1000);
   function fn_is_spi_addr = addr_function('h6232_0000, 'h1000);
   function fn_is_uart2_addr = addr_function('h6236_0000, 'h1000);
   function fn_is_gpio1_addr = addr_function('h6233_0000, 'h1000);
   function fn_is_gpio2_addr = addr_function('h6237_0000, 'h1000);

   // ----------------------------------------------------------------
   // Memory address predicate
   // Identifies memory addresses in the Fabric.
   // (Caches needs this information to cache these addresses.)

   function Bool fn_is_mem_addr (Fabric_Addr addr);
      return (   fn_is_ddr4_0_cached_addr (addr)
	      );
   endfunction

   // ----------------------------------------------------------------
   // I/O address predicate
   // Identifies I/O addresses in the Fabric.
   // (Caches needs this information to avoid cacheing these addresses.)

   function Bool fn_is_IO_addr (Fabric_Addr addr);
      return (   fn_is_plic_addr (addr)
	      || fn_is_near_mem_io_addr (addr)
	   // || fn_is_pcie_ecam_slave_bridge_addr (addr)
	      || fn_is_flash_mem_addr (addr)
	   // || fn_is_pcie_block_registers_addr (addr)
	      || fn_is_ethernet_0_addr (addr)
	      || fn_is_dma_0_addr (addr)
	      || fn_is_uart16550_0_addr  (addr)
	      || fn_is_gpio_0_addr (addr)
	      || fn_is_boot_rom_addr (addr)
	      || fn_is_ddr4_0_uncached_addr (addr)
	      || fn_is_flash_regs_addr (addr)
	      || fn_is_uart1_addr (addr)
	      || fn_is_i2c_addr (addr)
	      || fn_is_spi_addr (addr)
	      || fn_is_uart2_addr (addr)
	      || fn_is_gpio1_addr (addr)
	      || fn_is_gpio2_addr (addr)
	      );
   endfunction

   // ----------------------------------------------------------------
   // PC, MTVEC and NMIVEC reset values

   Bit #(64) pc_reset_value     = boot_rom_addr_base;
   Bit #(64) mtvec_reset_value  = 'h1000;    // TODO
   Bit #(64) nmivec_reset_value = ?;         // TODO

   // ================================================================
   // INTERFACE

   method  Fabric_Addr  m_plic_addr_base = plic_addr_base;
   method  Fabric_Addr  m_plic_addr_size = plic_addr_size;
   method  Fabric_Addr  m_plic_addr_lim  = plic_addr_lim;

   method  Fabric_Addr  m_near_mem_io_addr_base = near_mem_io_addr_base;
   method  Fabric_Addr  m_near_mem_io_addr_size = near_mem_io_addr_size;
   method  Fabric_Addr  m_near_mem_io_addr_lim  = near_mem_io_addr_lim;

   /* REMOVED?
   method  Fabric_Addr  m_pcie_ecam_slave_bridge_addr_base = pcie_ecam_slave_bridge_addr_base;
   method  Fabric_Addr  m_pcie_ecam_slave_bridge_addr_size = pcie_ecam_slave_bridge_addr_size;
   method  Fabric_Addr  m_pcie_ecam_slave_bridge_addr_lim  = pcie_ecam_slave_bridge_addr_lim;
   */

   method  Fabric_Addr  m_flash_mem_addr_base = flash_mem_addr_base;
   method  Fabric_Addr  m_flash_mem_addr_size = flash_mem_addr_size;
   method  Fabric_Addr  m_flash_mem_addr_lim  = flash_mem_addr_lim;

   /* REMOVED?
   method  Fabric_Addr  m_pcie_block_registers_addr_base = pcie_block_registers_addr_base;
   method  Fabric_Addr  m_pcie_block_registers_addr_size = pcie_block_registers_addr_size;
   method  Fabric_Addr  m_pcie_block_registers_addr_lim  = pcie_block_registers_addr_lim;
   */

   method  Fabric_Addr  m_ethernet_0_addr_base = ethernet_0_addr_base;
   method  Fabric_Addr  m_ethernet_0_addr_size = ethernet_0_addr_size;
   method  Fabric_Addr  m_ethernet_0_addr_lim  = ethernet_0_addr_lim;

   method  Fabric_Addr  m_dma_0_addr_base = dma_0_addr_base;
   method  Fabric_Addr  m_dma_0_addr_size = dma_0_addr_size;
   method  Fabric_Addr  m_dma_0_addr_lim  = dma_0_addr_lim;

   method  Fabric_Addr  m_uart16550_0_addr_base = uart16550_0_addr_base;
   method  Fabric_Addr  m_uart16550_0_addr_size = uart16550_0_addr_size;
   method  Fabric_Addr  m_uart16550_0_addr_lim  = uart16550_0_addr_lim;

   method  Fabric_Addr  m_gpio_0_addr_base = gpio_0_addr_base;
   method  Fabric_Addr  m_gpio_0_addr_size = gpio_0_addr_size;
   method  Fabric_Addr  m_gpio_0_addr_lim  = gpio_0_addr_lim;

   method  Fabric_Addr  m_boot_rom_addr_base = boot_rom_addr_base;
   method  Fabric_Addr  m_boot_rom_addr_size = boot_rom_addr_size;
   method  Fabric_Addr  m_boot_rom_addr_lim  = boot_rom_addr_lim;

   method  Fabric_Addr  m_ddr4_0_uncached_addr_base = ddr4_0_uncached_addr_base;
   method  Fabric_Addr  m_ddr4_0_uncached_addr_size = ddr4_0_uncached_addr_size;
   method  Fabric_Addr  m_ddr4_0_uncached_addr_lim  = ddr4_0_uncached_addr_lim;

   method  Fabric_Addr  m_ddr4_0_cached_addr_base = ddr4_0_cached_addr_base;
   method  Fabric_Addr  m_ddr4_0_cached_addr_size = ddr4_0_cached_addr_size;
   method  Fabric_Addr  m_ddr4_0_cached_addr_lim  = ddr4_0_cached_addr_lim;

   method  Bool  m_is_mem_addr (Fabric_Addr addr) = fn_is_mem_addr (addr);

   method  Bool  m_is_IO_addr (Fabric_Addr addr) = fn_is_IO_addr (addr);

   method  Bool  m_is_near_mem_IO_addr (Fabric_Addr addr) = fn_is_near_mem_io_addr (addr);

   method  Bit #(64)  m_pc_reset_value     = pc_reset_value;
   method  Bit #(64)  m_mtvec_reset_value  = mtvec_reset_value;
   method  Bit #(64)  m_nmivec_reset_value = nmivec_reset_value;
endmodule

// ================================================================
// Interrupt request numbers (== index in to vector of
// interrupt-request lines in Core)

typedef  16  N_External_Interrupt_Sources;
Integer  n_external_interrupt_sources = valueOf (N_External_Interrupt_Sources);

Integer irq_num_uart16550_0 = 0;

// ================================================================

endpackage


1. reverting DmaUtils as pipelined one didn't work. 2. further simplifying the buffered memcpy example

// 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 FIFOF::*;
import FIFO::*;
import Connectable::*;

import PortalMemory::*;
import Dma::*;
import MemreadEngine::*;
import MemwriteEngine::*;

interface MemcpyRequest;
   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
endinterface

interface MemcpyIndication;
   method Action started;
   method Action done;
endinterface

module mkMemcpyRequest#(MemcpyIndication indication,
			ObjectReadServer#(64) dma_read_server,
			ObjectWriteServer#(64) dma_write_server)(MemcpyRequest);

   let dataFifo <- mkFIFOF;

   MemreadEngine#(64) re <- mkMemreadEngine(1, dataFifo);
   MemwriteEngine#(64) we <- mkMemwriteEngine(1, dataFifo);

   Reg#(Bit#(32))          iterCnt <- mkReg(0);
   Reg#(Bit#(32))         numWords <- mkReg(0);
   Reg#(ObjectPointer)      rdPointer <- mkReg(0);
   Reg#(ObjectPointer)      wrPointer <- mkReg(0);
   Reg#(Bit#(32))         burstLen <- mkReg(0);

   mkConnection(re.dmaClient,dma_read_server);
   mkConnection(we.dmaClient,dma_write_server);

   rule start(iterCnt > 0);
      re.start(rdPointer, 0, numWords*4, burstLen*4);
      we.start(wrPointer, 0, numWords*4, burstLen*4);
      iterCnt <= iterCnt-1;
   endrule

   rule finish;
      let rv0 <- re.finish;
      let rv1 <- we.finish;
      if(iterCnt==0) begin
	 indication.done;
      end
   endrule

   method Action startCopy(Bit#(32) wp, Bit#(32) rp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
      $display("startCopy wrPointer=%d rdPointer=%d numWords=%h burstLen=%d iterCnt=%d", wp, rp, nw, bl, ic);
      indication.started;
      // initialized
      wrPointer <= wp;
      rdPointer <= rp;
      numWords  <= nw;
      iterCnt   <= ic;
      burstLen  <= bl;
   endmethod

endmodule

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

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

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

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

import FIFOF::*;
import FIFO::*;
import Connectable::*;

import PortalMemory::*;
import Dma::*;
import MemreadEngine::*;
import MemwriteEngine::*;

interface MemcpyRequest;
   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
endinterface

interface MemcpyIndication;
   method Action started;
   method Action done;
endinterface

module mkMemcpyRequest#(MemcpyIndication indication,
			ObjectReadServer#(64) dma_read_server,
			ObjectWriteServer#(64) dma_write_server)(MemcpyRequest);

   let readFifo <- mkFIFOF;
   let writeFifo <- mkFIFOF;

   MemreadEngine#(64) re <- mkMemreadEngine(1, readFifo);
   MemwriteEngine#(64) we <- mkMemwriteEngine(1, writeFifo);

   Reg#(Bit#(32))          iterCnt <- mkReg(0);
   Reg#(Bit#(32))         numWords <- mkReg(0);
   Reg#(ObjectPointer)      rdPointer <- mkReg(0);
   Reg#(ObjectPointer)      wrPointer <- mkReg(0);
   Reg#(Bit#(32))         burstLen <- mkReg(0);

   mkConnection(re.dmaClient,dma_read_server);
   mkConnection(we.dmaClient,dma_write_server);

   rule start(iterCnt > 0);
      re.start(rdPointer, 0, numWords*4, burstLen*4);
      we.start(wrPointer, 0, numWords*4, burstLen*4);
      iterCnt <= iterCnt-1;
   endrule

   rule finish;
      let rv0 <- re.finish;
      let rv1 <- we.finish;
      if(iterCnt==0) begin
	 indication.done;
      end
   endrule

   rule xfer;
      //$display("xfer: %h", readFifo.first);
      readFifo.deq;
      writeFifo.enq(readFifo.first);
   endrule

   method Action startCopy(Bit#(32) wp, Bit#(32) rp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
      $display("startCopy wrPointer=%d rdPointer=%d numWords=%h burstLen=%d iterCnt=%d", wp, rp, nw, bl, ic);
      indication.started;
      // initialized
      wrPointer <= wp;
      rdPointer <= rp;
      numWords  <= nw;
      iterCnt   <= ic;
      burstLen  <= bl;
   endmethod

endmodule


Fixed interrupt in RVUart

Fixed interrupt in RVUart

// Copyright (c) 2017 Massachusetts Institute of Technology

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

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

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

import BuildVector::*;
import ClientServer::*;
import GetPut::*;
import RS232::*;
import Vector::*;

import ConcatReg::*;
import Ehr::*;
import RegUtil::*;

import MemoryMappedServer::*;

import Abstraction::*;

interface RVUart#(numeric type cores);
    // Internal connections
    interface UncachedMemServer memifc;

    // external connections for rx/tx (to be connected to a UART
    (* prefix = "" *)
    interface RS232 uart_pins;
    method Bit#(16) divisor;
    method Bool interrupt;
endinterface

module mkRVUart_RV32#(Bit#(16) divisor)(RVUart#(1));
    Bool verbose = False;

    // memory mapped registers
    Reg#(Maybe#(Bit#(8))) txDataReg <- mkReg(tagged Invalid);
    Reg#(Maybe#(Bit#(8))) rxDataReg <- mkReg(tagged Invalid);
    Reg#(Bit#(32)) txCtrlReg <- mkReg(0);
    Reg#(Bit#(32)) rxCtrlReg <- mkReg(0);
    Reg#(Bit#(16)) divReg <- mkReg(divisor);

    Vector#(5, Reg#(Bit#(32))) memoryMappedRegisters =
        vec(
            concatReg3(readOnlyReg(pack(isValid(txDataReg))), readOnlyReg(0), fromMaybeReg(0, txDataReg)),
            concatReg3(readOnlyReg(pack(isValid(rxDataReg))), readOnlyReg(0), fromMaybeReg(0, rxDataReg)),
            txCtrlReg,
            rxCtrlReg,
            zeroExtendReg(divReg)
        );
    Server#(UncachedMemReq, UncachedMemResp) memoryMappedIfc <- mkMemoryMappedServer(memoryMappedRegisters);

    UART#(16) uart <- mkUART(8, NONE, STOP_1, divReg);

    rule doTxData (txDataReg matches tagged Valid .x);
        // There is an implicit guard on the Fifo for uart.put
        uart.rx.put(x);
        txDataReg <= tagged Invalid;
    endrule

    rule doRxData (rxDataReg matches tagged Invalid .x);
        // There is an implicit guard on the Fifo for uart.get
        let data <- uart.tx.get;
        rxDataReg <= Valid(data);
    endrule

    interface UncachedMemServer memifc = memoryMappedIfc;

    interface RS232 uart_pins = uart.rs232;
    method Bit#(16) divisor = divReg;
    method Bool interrupt = isValid(rxDataReg);
endmodule

// Copyright (c) 2017 Massachusetts Institute of Technology

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

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

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

import BuildVector::*;
import ClientServer::*;
import GetPut::*;
import RS232::*;
import Vector::*;

import ConcatReg::*;
import Ehr::*;
import RegUtil::*;

import MemoryMappedServer::*;

import Abstraction::*;

interface RVUart#(numeric type cores);
    // Internal connections
    interface UncachedMemServer memifc;

    // external connections for rx/tx (to be connected to a UART
    (* prefix = "" *)
    interface RS232 uart_pins;
    //method Action rx (Bit#(1) x);
    // method Bit#(1) tx;
    method Bit#(16) divisor;
    method Vector#(cores, Bool) receiveInterrupt;
endinterface

module mkRVUart_RV32#(Bit#(16) divisor)(RVUart#(1));
    Bool verbose = False;

    // memory mapped registers
    Reg#(Maybe#(Bit#(8))) txDataReg <- mkReg(tagged Invalid);
    Reg#(Maybe#(Bit#(8))) rxDataReg <- mkReg(tagged Invalid);
    Reg#(Bit#(32)) txCtrlReg <- mkReg(0);
    Reg#(Bit#(32)) rxCtrlReg <- mkReg(0);
    Reg#(Bit#(16)) divReg <- mkReg(divisor);

    Vector#(5, Reg#(Bit#(32))) memoryMappedRegisters =
        vec(
            concatReg3(readOnlyReg(pack(isValid(txDataReg))), readOnlyReg(0), fromMaybeReg(0, txDataReg)),
            concatReg3(readOnlyReg(pack(isValid(rxDataReg))), readOnlyReg(0), fromMaybeReg(0, rxDataReg)),
            txCtrlReg,
            rxCtrlReg,
            zeroExtendReg(divReg)
        );
    Server#(UncachedMemReq, UncachedMemResp) memoryMappedIfc <- mkMemoryMappedServer(memoryMappedRegisters);

    UART#(16) uart <- mkUART(8, NONE, STOP_1, divReg);

    Ehr#(2, Bool) interruptReg <- mkEhr(False);

    rule doTxData (txDataReg matches tagged Valid .x);
        // There is an implicit guard on the Fifo for uart.put
        uart.rx.put(x);
        txDataReg <= tagged Invalid;
    endrule

    rule doRxData (rxDataReg matches tagged Invalid .x);
        // There is an implicit guard on the Fifo for uart.get
        let data <- uart.tx.get;
        rxDataReg <= Valid(data);
        interruptReg[0] <= True;
    endrule

    interface UncachedMemServer memifc = memoryMappedIfc;

    interface RS232 uart_pins = uart.rs232;
    method Bit#(16) divisor = divReg;
    method Vector#(1, Bool) receiveInterrupt = vec(interruptReg[0]);
endmodule