added mkMemServer, which can take nil for read or write clients, and fixed compilation of mkSimpleMemServer

// 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 FIFO::*;
import Vector::*;
import List::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import StmtFSM::*;

// CONNECTAL Libraries
import HostInterface::*;
import MemTypes::*;
import ConnectalMemory::*;
import MMU::*;
import MemServerInternal::*;

function Put#(t) null_put();
   return (interface Put;
              method Action put(t x) if (False);
                 noAction;
              endmethod
           endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
              method ActionValue#(t) get() if (False);
                 return ?;
              endmethod
           endinterface);
endfunction

function  PhysMemWriteClient#(addrWidth, busWidth) null_phys_mem_write_client();
   return (interface PhysMemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  PhysMemReadClient#(addrWidth, busWidth) null_phys_mem_read_client();
   return (interface PhysMemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

function  MemWriteClient#(busWidth) null_mem_write_client();
   return (interface MemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  MemReadClient#(busWidth) null_mem_read_client();
   return (interface MemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

interface MemServer#(numeric type addrWidth, numeric type dataWidth, numeric type nMasters);
   interface MemServerRequest request;
   interface Vector#(nMasters,PhysMemMaster#(addrWidth, dataWidth)) masters;
endinterface

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

module mkMemServer#(Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
		    Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
		    Vector#(numMMUs,MMU#(PhysAddrWidth)) mmus,
		    MemServerIndication indication)
   (MemServer#(PhysAddrWidth, dataWidth, nMasters))

   provisos (Max#(nMasters,numReadClients,numReadClientsActual),
	     Add#(numReadClients,numReadClientsNull,numReadClientsActual),
	     Mul#(a__, nMasters, numReadClientsActual),
	     Max#(nMasters,numWriteClients,numWriteClientsActual),
	     Add#(numWriteClients,numWriteClientsNull,numWriteClientsActual),
	     Mul#(b__, nMasters, numWriteClientsActual),
	     Add#(1,c__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(TLog#(TDiv#(dataWidth, 8)), d__, BurstLenSize),
	     Mul#(h__, nMasters, TMax#(nMasters, numReadClientsActual)),
	     Mul#(i__, nMasters, TMax#(nMasters, numWriteClientsActual)),
	     Add#(e__, TLog#(b__), 6),
	     Add#(f__, TLog#(a__), 6),
	     Mul#(g__, nMasters, TMax#(nMasters, TMax#(nMasters, numWriteClientsActual))),
	     Add#(j__, TLog#(i__), 6),
	     Mul#(k__, nMasters, TMax#(nMasters, TMax#(nMasters, numReadClientsActual))),
	     Add#(l__, TLog#(h__), 6),
	     Mul#(m__, nMasters, TMax#(nMasters, nMasters))
      );

   Vector#(numReadClientsNull, MemReadClient#(dataWidth)) nullReadClients = replicate(null_mem_read_client());
   Vector#(numWriteClientsNull, MemWriteClient#(dataWidth)) nullWriteClients = replicate(null_mem_write_client());

   MemServer#(PhysAddrWidth,dataWidth,nMasters) reader <- mkMemServerR(indication, append(readClients,nullReadClients), mmus);
   MemServer#(PhysAddrWidth,dataWidth,nMasters) writer <- mkMemServerW(indication, append(writeClients,nullWriteClients), mmus);

   function PhysMemMaster#(PhysAddrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(PhysAddrWidth,dataWidth);
								 interface PhysMemReadClient read_client = reader.masters[i].read_client;
								 interface PhysMemWriteClient write_client = writer.masters[i].write_client;
							      endinterface);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Read)
	    reader.request.stateDbg(rc);
	 else
	    writer.request.stateDbg(rc);
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Read)
	    reader.request.memoryTraffic(rc);
	 else
	    writer.request.memoryTraffic(rc);
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 writer.request.addrTrans(pointer,offset);
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkMemServerRW#(MemServerIndication indication,
		      Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
		      Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
		      Vector#(numMMUs,MMU#(PhysAddrWidth)) mmus)
   (MemServer#(PhysAddrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(nwc, nMasters, numWriteClients),
	     Mul#(nrc, nMasters, numReadClients),
	     Add#(b__, TLog#(nrc), 6),
	     Add#(c__, TLog#(nwc), 6),
	     Add#(TLog#(TDiv#(dataWidth, 8)), d__, BurstLenSize)
	     );

   MemServer#(PhysAddrWidth,dataWidth,nMasters) reader <- mkMemServerR(indication,  readClients, mmus);
   MemServer#(PhysAddrWidth,dataWidth,nMasters) writer <- mkMemServerW(indication, writeClients, mmus);

   function PhysMemMaster#(PhysAddrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(PhysAddrWidth,dataWidth);
								 interface PhysMemReadClient read_client = reader.masters[i].read_client;
								 interface PhysMemWriteClient write_client = writer.masters[i].write_client;
							      endinterface);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Read)
	    reader.request.stateDbg(rc);
	 else
	    writer.request.stateDbg(rc);
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Read)
	    reader.request.memoryTraffic(rc);
	 else
	    writer.request.memoryTraffic(rc);
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 writer.request.addrTrans(pointer,offset);
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkMemServerR#(MemServerIndication indication,
		       Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
		       Vector#(numMMUs,MMU#(addrWidth)) mmus)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(nrc, nMasters, numReadClients),
	     Add#(b__, TLog#(nrc), 6),
	     Add#(TLog#(TDiv#(dataWidth, 8)), c__, BurstLenSize)
	     ,Add#(d__, addrWidth, 64)
	     ,Add#(e__, 12, addrWidth)
	     ,Add#(1, e__, f__)
	     );

   FIFO#(Bit#(32))   addrReqFifo <- mkFIFO;
   Reg#(Bit#(8)) dbgPtr <- mkReg(0);
   Reg#(Bit#(8)) trafficPtr <- mkReg(0);
   Reg#(Bit#(64)) trafficAccum <- mkReg(0);

   function a selectClient(Vector#(n, a) in, Integer r, Integer i, Integer j); return in[j * r + i]; endfunction
   function Vector#(nrc, a) selectClients(Vector#(numReadClients, a) vec, Integer m);
      return genWith(selectClient(vec, valueOf(nMasters), m));
   endfunction
   Vector#(nMasters,Vector#(nrc, MemReadClient#(dataWidth))) client_bins = genWith(selectClients(readClients));

   module foo#(Integer i) (MMUAddrServer#(addrWidth,nMasters));
      let rv <- mkMMUAddrServer(mmus[i].addr[0]);
      return rv;
   endmodule
   Vector#(numMMUs,MMUAddrServer#(addrWidth,nMasters)) mmu_servers <- mapM(foo,genVector);

   Vector#(nMasters,MemReadInternal#(addrWidth,dataWidth,MemServerTags)) readers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1) begin
      Vector#(numMMUs,Server#(ReqTup,Bit#(addrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      readers[i] <- mkMemReadInternal(client_bins[i],indication,ss);
   end

   rule mmuEntry;
      addrReqFifo.deq;
      let physAddr <- mmus[addrReqFifo.first[31:16]].addr[0].response.get;
      indication.addrResponse(zeroExtend(physAddr));
   endrule

   function PhysMemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(addrWidth,dataWidth);
								 interface PhysMemReadClient read_client = readers[i].read_client;
								 interface PhysMemWriteClient write_client = null_phys_mem_write_client;
							      endinterface);

   Stmt dbgStmt = seq
		     for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(nMasters)); dbgPtr <= dbgPtr+1)
			(action
			    let rv <- readers[dbgPtr].dbg.dbg;
			    indication.reportStateDbg(rv);
			 endaction);
		  endseq;
   FSM dbgFSM <- mkFSM(dbgStmt);

   Stmt trafficStmt = seq
			 trafficAccum <= 0;
			 for(trafficPtr <= 0; trafficPtr < fromInteger(valueOf(nMasters)); trafficPtr <= trafficPtr+1)
			    (action
				let rv <- readers[trafficPtr].dbg.getMemoryTraffic();
				trafficAccum <= trafficAccum + rv;
			     endaction);
			 indication.reportMemoryTraffic(trafficAccum);
		      endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Read)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Read)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[0].request.put(ReqTup{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkMemServerW#(MemServerIndication indication,
		     Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
		     Vector#(numMMUs,MMU#(PhysAddrWidth)) mmus)
   (MemServer#(PhysAddrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(nwc, nMasters, numWriteClients),
	     Add#(b__, TLog#(nwc), 6)
	     );

   FIFO#(Bit#(32))   addrReqFifo <- mkFIFO;
   Reg#(Bit#(8)) dbgPtr <- mkReg(0);
   Reg#(Bit#(8)) trafficPtr <- mkReg(0);
   Reg#(Bit#(64)) trafficAccum <- mkReg(0);

   function a selectClient(Vector#(n, a) in, Integer r, Integer i, Integer j); return in[j * r + i]; endfunction
   function Vector#(nwc, a) selectClients(Vector#(numWriteClients, a) vec, Integer m);
      return genWith(selectClient(vec, valueOf(nMasters), m));
   endfunction
   Vector#(nMasters,Vector#(nwc, MemWriteClient#(dataWidth))) client_bins = genWith(selectClients(writeClients));

   module foo#(Integer i) (MMUAddrServer#(PhysAddrWidth,nMasters));
      let rv <- mkMMUAddrServer(mmus[i].addr[1]);
      return rv;
   endmodule
   Vector#(numMMUs,MMUAddrServer#(PhysAddrWidth,nMasters)) mmu_servers <- mapM(foo,genVector);

   Vector#(nMasters,MemWriteInternal#(PhysAddrWidth,dataWidth,MemServerTags)) writers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1) begin
      Vector#(numMMUs,Server#(ReqTup,Bit#(PhysAddrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      writers[i] <- mkMemWriteInternal(client_bins[i], indication, ss);
   end

   rule mmuEntry;
      addrReqFifo.deq;
      let physAddr <- mmus[addrReqFifo.first[31:16]].addr[1].response.get;
      indication.addrResponse(zeroExtend(physAddr));
   endrule

   function PhysMemMaster#(PhysAddrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(PhysAddrWidth,dataWidth);
								 interface PhysMemReadClient read_client = null_phys_mem_read_client;
								 interface PhysMemWriteClient write_client = writers[i].write_client;
							      endinterface);

   Stmt dbgStmt = seq
		     for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(nMasters)); dbgPtr <= dbgPtr+1)
			(action
			    let rv <- writers[dbgPtr].dbg.dbg;
			    indication.reportStateDbg(rv);
			 endaction);
		  endseq;
   FSM dbgFSM <- mkFSM(dbgStmt);

   Stmt trafficStmt = seq
			 trafficAccum <= 0;
			 for(trafficPtr <= 0; trafficPtr < fromInteger(valueOf(nMasters)); trafficPtr <= trafficPtr+1)
			    (action
				let rv <- writers[trafficPtr].dbg.getMemoryTraffic();
				trafficAccum <= trafficAccum + rv;
			     endaction);
			 indication.reportMemoryTraffic(trafficAccum);
		      endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Write)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Write)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[1].request.put(ReqTup{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

interface SimpleMemServer#(numeric type addrWidth, numeric type dataWidth, numeric type nMasters);
   interface MemServerRequest memServerRequest;
   interface MMURequest mmuRequest;
   interface Vector#(nMasters,PhysMemMaster#(addrWidth, dataWidth)) masters;
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

module mkSimpleMemServer#(Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
			  Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
			  MemServerIndication indication,
			  MMUIndication mmuIndication)(SimpleMemServer#(PhysAddrWidth, dataWidth,nMasters))
   provisos (Max#(nMasters,numReadClients,numReadClientsActual),
	     Add#(numReadClients,numReadClientsNull,numReadClientsActual),
	     Mul#(a__, nMasters, numReadClientsActual),
	     Max#(nMasters,numWriteClients,numWriteClientsActual),
	     Add#(numWriteClients,numWriteClientsNull,numWriteClientsActual),
	     Mul#(b__, nMasters, numWriteClientsActual),
	     Add#(1,c__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(TLog#(TDiv#(dataWidth, 8)), d__, BurstLenSize),
	     Mul#(h__, nMasters, TMax#(nMasters, numReadClientsActual)),
	     Mul#(i__, nMasters, TMax#(nMasters, numWriteClientsActual)),

	     Add#(e__, TLog#(a__), 6),
	     Add#(f__, TLog#(b__), 6)

	     );

   MMU#(PhysAddrWidth) hostMMU <- mkMMU(0, True, mmuIndication);

   Vector#(numReadClientsNull, MemReadClient#(dataWidth)) nullReadClients = replicate(null_mem_read_client());
   Vector#(numWriteClientsNull, MemWriteClient#(dataWidth)) nullWriteClients = replicate(null_mem_write_client());

   // if this is implemented in terms of mkMemServer, then we go into loop where the compiler keeps asking for more provisos...
   MemServer#(PhysAddrWidth,dataWidth,nMasters) dma <- mkMemServerRW(indication, append(readClients,nullReadClients), append(writeClients,nullWriteClients), cons(hostMMU,nil));

   interface MemServerRequest memServerRequest = dma.request;
   interface MMURequest mmuRequest = hostMMU.request;
   interface Vector masters = dma.masters;
   interface Vector addr = hostMMU.addr;
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 FIFO::*;
import Vector::*;
import List::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import StmtFSM::*;

// CONNECTAL Libraries
import HostInterface::*;
import MemTypes::*;
import ConnectalMemory::*;
import MMU::*;
import MemServerInternal::*;

function Put#(t) null_put();
   return (interface Put;
              method Action put(t x) if (False);
                 noAction;
              endmethod
           endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
              method ActionValue#(t) get() if (False);
                 return ?;
              endmethod
           endinterface);
endfunction

function  PhysMemWriteClient#(addrWidth, busWidth) null_phys_mem_write_client();
   return (interface PhysMemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  PhysMemReadClient#(addrWidth, busWidth) null_phys_mem_read_client();
   return (interface PhysMemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

function  MemWriteClient#(busWidth) null_mem_write_client();
   return (interface MemWriteClient;
              interface Get writeReq = null_get;
              interface Get writeData = null_get;
              interface Put writeDone = null_put;
           endinterface);
endfunction

function  MemReadClient#(busWidth) null_mem_read_client();
   return (interface MemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

interface MemServer#(numeric type addrWidth, numeric type dataWidth, numeric type nMasters);
   interface MemServerRequest request;
   interface Vector#(nMasters,PhysMemMaster#(addrWidth, dataWidth)) masters;
endinterface

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

module mkMemServerRW#(MemServerIndication indication,
		      Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
		      Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
		      Vector#(numMMUs,MMU#(PhysAddrWidth)) mmus)
   (MemServer#(PhysAddrWidth, dataWidth, nMasters))

   provisos (Max#(nMasters,numReadClients,numReadClientsActual),
	     Add#(numReadClients,numReadClientsNull,numReadClientsActual),
	     Mul#(a__, nMasters, numReadClientsActual),
	     Max#(nMasters,numWriteClients,numWriteClientsActual),
	     Add#(numWriteClients,numWriteClientsNull,numWriteClientsActual),
	     Mul#(b__, nMasters, numWriteClientsActual),
	     Add#(1,c__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(TLog#(TDiv#(dataWidth, 8)), d__, BurstLenSize),
	     Mul#(h__, nMasters, TMax#(nMasters, numReadClientsActual)),
	     Mul#(i__, nMasters, TMax#(nMasters, numWriteClientsActual)),
	     Add#(e__, TLog#(b__), 6),
	     Add#(f__, TLog#(a__), 6)
      );

   Vector#(numReadClientsNull, MemReadClient#(dataWidth)) nullReadClients = replicate(null_mem_read_client());
   Vector#(numWriteClientsNull, MemWriteClient#(dataWidth)) nullWriteClients = replicate(null_mem_write_client());

   MemServer#(PhysAddrWidth,dataWidth,nMasters) reader <- mkMemServerR(indication, append(readClients,nullReadClients), mmus);
   MemServer#(PhysAddrWidth,dataWidth,nMasters) writer <- mkMemServerW(indication, append(writeClients,nullWriteClients), mmus);

   function PhysMemMaster#(PhysAddrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(PhysAddrWidth,dataWidth);
								 interface PhysMemReadClient read_client = reader.masters[i].read_client;
								 interface PhysMemWriteClient write_client = writer.masters[i].write_client;
							      endinterface);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Read)
	    reader.request.stateDbg(rc);
	 else
	    writer.request.stateDbg(rc);
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Read)
	    reader.request.memoryTraffic(rc);
	 else
	    writer.request.memoryTraffic(rc);
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 writer.request.addrTrans(pointer,offset);
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkMemServerR#(MemServerIndication indication,
		       Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
		       Vector#(numMMUs,MMU#(addrWidth)) mmus)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(nrc, nMasters, numReadClients),
	     Add#(b__, TLog#(nrc), 6),
	     Add#(TLog#(TDiv#(dataWidth, 8)), c__, BurstLenSize)
	     ,Add#(d__, addrWidth, 64)
	     ,Add#(e__, 12, addrWidth)
	     ,Add#(1, e__, f__)
	     );

   FIFO#(Bit#(32))   addrReqFifo <- mkFIFO;
   Reg#(Bit#(8)) dbgPtr <- mkReg(0);
   Reg#(Bit#(8)) trafficPtr <- mkReg(0);
   Reg#(Bit#(64)) trafficAccum <- mkReg(0);

   function a selectClient(Vector#(n, a) in, Integer r, Integer i, Integer j); return in[j * r + i]; endfunction
   function Vector#(nrc, a) selectClients(Vector#(numReadClients, a) vec, Integer m);
      return genWith(selectClient(vec, valueOf(nMasters), m));
   endfunction
   Vector#(nMasters,Vector#(nrc, MemReadClient#(dataWidth))) client_bins = genWith(selectClients(readClients));

   module foo#(Integer i) (MMUAddrServer#(addrWidth,nMasters));
      let rv <- mkMMUAddrServer(mmus[i].addr[0]);
      return rv;
   endmodule
   Vector#(numMMUs,MMUAddrServer#(addrWidth,nMasters)) mmu_servers <- mapM(foo,genVector);

   Vector#(nMasters,MemReadInternal#(addrWidth,dataWidth,MemServerTags)) readers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1) begin
      Vector#(numMMUs,Server#(ReqTup,Bit#(addrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      readers[i] <- mkMemReadInternal(client_bins[i],indication,ss);
   end

   rule mmuEntry;
      addrReqFifo.deq;
      let physAddr <- mmus[addrReqFifo.first[31:16]].addr[0].response.get;
      indication.addrResponse(zeroExtend(physAddr));
   endrule

   function PhysMemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(addrWidth,dataWidth);
								 interface PhysMemReadClient read_client = readers[i].read_client;
								 interface PhysMemWriteClient write_client = null_phys_mem_write_client;
							      endinterface);

   Stmt dbgStmt = seq
		     for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(nMasters)); dbgPtr <= dbgPtr+1)
			(action
			    let rv <- readers[dbgPtr].dbg.dbg;
			    indication.reportStateDbg(rv);
			 endaction);
		  endseq;
   FSM dbgFSM <- mkFSM(dbgStmt);

   Stmt trafficStmt = seq
			 trafficAccum <= 0;
			 for(trafficPtr <= 0; trafficPtr < fromInteger(valueOf(nMasters)); trafficPtr <= trafficPtr+1)
			    (action
				let rv <- readers[trafficPtr].dbg.getMemoryTraffic();
				trafficAccum <= trafficAccum + rv;
			     endaction);
			 indication.reportMemoryTraffic(trafficAccum);
		      endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Read)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Read)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[0].request.put(ReqTup{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkMemServerW#(MemServerIndication indication,
		     Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
		     Vector#(numMMUs,MMU#(PhysAddrWidth)) mmus)
   (MemServer#(PhysAddrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(nwc, nMasters, numWriteClients),
	     Add#(b__, TLog#(nwc), 6)
	     );

   FIFO#(Bit#(32))   addrReqFifo <- mkFIFO;
   Reg#(Bit#(8)) dbgPtr <- mkReg(0);
   Reg#(Bit#(8)) trafficPtr <- mkReg(0);
   Reg#(Bit#(64)) trafficAccum <- mkReg(0);

   function a selectClient(Vector#(n, a) in, Integer r, Integer i, Integer j); return in[j * r + i]; endfunction
   function Vector#(nwc, a) selectClients(Vector#(numWriteClients, a) vec, Integer m);
      return genWith(selectClient(vec, valueOf(nMasters), m));
   endfunction
   Vector#(nMasters,Vector#(nwc, MemWriteClient#(dataWidth))) client_bins = genWith(selectClients(writeClients));

   module foo#(Integer i) (MMUAddrServer#(PhysAddrWidth,nMasters));
      let rv <- mkMMUAddrServer(mmus[i].addr[1]);
      return rv;
   endmodule
   Vector#(numMMUs,MMUAddrServer#(PhysAddrWidth,nMasters)) mmu_servers <- mapM(foo,genVector);

   Vector#(nMasters,MemWriteInternal#(PhysAddrWidth,dataWidth,MemServerTags)) writers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1) begin
      Vector#(numMMUs,Server#(ReqTup,Bit#(PhysAddrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      writers[i] <- mkMemWriteInternal(client_bins[i], indication, ss);
   end

   rule mmuEntry;
      addrReqFifo.deq;
      let physAddr <- mmus[addrReqFifo.first[31:16]].addr[1].response.get;
      indication.addrResponse(zeroExtend(physAddr));
   endrule

   function PhysMemMaster#(PhysAddrWidth,dataWidth) mkm(Integer i) = (interface PhysMemMaster#(PhysAddrWidth,dataWidth);
								 interface PhysMemReadClient read_client = null_phys_mem_read_client;
								 interface PhysMemWriteClient write_client = writers[i].write_client;
							      endinterface);

   Stmt dbgStmt = seq
		     for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(nMasters)); dbgPtr <= dbgPtr+1)
			(action
			    let rv <- writers[dbgPtr].dbg.dbg;
			    indication.reportStateDbg(rv);
			 endaction);
		  endseq;
   FSM dbgFSM <- mkFSM(dbgStmt);

   Stmt trafficStmt = seq
			 trafficAccum <= 0;
			 for(trafficPtr <= 0; trafficPtr < fromInteger(valueOf(nMasters)); trafficPtr <= trafficPtr+1)
			    (action
				let rv <- writers[trafficPtr].dbg.getMemoryTraffic();
				trafficAccum <= trafficAccum + rv;
			     endaction);
			 indication.reportMemoryTraffic(trafficAccum);
		      endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface MemServerRequest request;
      method Action stateDbg(ChannelType rc);
	 if (rc == Write)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == Write)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[1].request.put(ReqTup{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

interface SimpleMemServer#(numeric type addrWidth, numeric type dataWidth, numeric type nMasters);
   interface MemServerRequest memServerRequest;
   interface MMURequest mmuRequest;
   interface Vector#(nMasters,PhysMemMaster#(addrWidth, dataWidth)) masters;
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

module mkSimpleMemServer#(Vector#(numReadClients, MemReadClient#(dataWidth)) readClients,
			  Vector#(numWriteClients, MemWriteClient#(dataWidth)) writeClients,
			  MemServerIndication indication,
			  MMUIndication mmuIndication)(SimpleMemServer#(PhysAddrWidth, dataWidth,nMasters))
   provisos (Mul#(a__, nMasters, TMax#(nMasters, numReadClients)),
	     Mul#(b__, nMasters, TMax#(nMasters, numWriteClients)),
	     Add#(1, c__, dataWidth),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(TLog#(TDiv#(dataWidth, 8)), d__, BurstLenSize),
	     Mul#(e__, nMasters, TMax#(nMasters, TMax#(nMasters, numReadClients))),
	     Mul#(f__, nMasters, TMax#(nMasters, TMax#(nMasters, numWriteClients))),
	     Add#(g__, TLog#(b__), 6),
	     Add#(h__, TLog#(a__), 6)
	     );

   MMU#(PhysAddrWidth) hostMMU <- mkMMU(0, True, mmuIndication);

   MemServer#(PhysAddrWidth,dataWidth,nMasters) dma <- mkMemServerRW(indication, readClients, writeClients, cons(hostMMU,nil));

   interface MemServerRequest memServerRequest = dma.request;
   interface MMURequest mmuRequest = hostMMU.request;
   interface Vector masters = dma.masters;
   interface Vector addr = hostMMU.addr;
endmodule


MetadataT -> StructDefines

MetadataT -> StructDefines

import DefaultValue::*;
import Ethernet::*;
import Utils::*;
import Vector::*;

typedef struct {
  PacketInstance pkt;
  MetadataT meta;
} MetadataRequest deriving (Bits, Eq, FShow);
typedef struct {
  PacketInstance pkt;
  MetadataT meta;
} MetadataResponse deriving (Bits, Eq, FShow);

typedef union tagged {
  void NotPresent;
  void Forward;
  void Delete;
  void Insert;
  void Processed;
  } HeaderState
deriving (Bits, Eq, FShow);

typedef struct {
   HeaderState state;
   hdrType hdr;
} Header#(type hdrType) deriving (Bits, Eq, FShow);
instance DefaultValue#(Header#(t))
   provisos(Bits#(StructDefines::Header#(t), a__));
   defaultValue = unpack(0);
endinstance

//NOTE: MetadataT struct based on v1model
typedef struct {
    Headers hdr;
    Metadata meta;
    //StandardMetadataT standard_metadata;
} MetadataT deriving (Bits, Eq, FShow);
instance DefaultValue#(MetadataT);
    defaultValue = unpack(0);
endinstance

`include "StructGenerated.bsv"

import DefaultValue::*;
import Ethernet::*;
import Utils::*;
import Vector::*;

typedef struct {
  PacketInstance pkt;
  MetadataT meta;
} MetadataRequest deriving (Bits, Eq, FShow);
typedef struct {
  PacketInstance pkt;
  MetadataT meta;
} MetadataResponse deriving (Bits, Eq, FShow);

typedef union tagged {
  void NotPresent;
  void Forward;
  void Delete;
  void Insert;
  void Processed;
  } HeaderState
deriving (Bits, Eq, FShow);

`include "StructGenerated.bsv"


decouple dmaIndication.dmaError in SGList

// 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 PortalMemory::*;

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

interface SGListMMU#(numeric type addrWidth);
   method Action sglist(Bit#(32) pointer, Bit#(40) paddr, Bit#(32) len);
   method Action region(Bit#(32) ptr, Bit#(36) barr8, Bit#(36) barr4, Bit#(36) barr0);
   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#(ObjectOffsetSize,SGListPageShift0)) Page;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) Page4;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) Page8;

typedef struct {
   Bit#(28) barrier;
   Bit#(8) idxOffset;
   } Region deriving (Eq,Bits,FShow);

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

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

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

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- 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#(8),Bit#(8),Bit#(8)))) 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#(8)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(8)))    idxOffsets1 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))         ptrs1 <- replicateM(mkFIFOF);

   // stage 4 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page) 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();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, -1, 0);
   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;
	 let req <- toGet(incomingReqs[i]).get();
	 match { .ptr, .off } = req;
	 portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr), datain:?});
	 portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr), datain:?});
	 portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr), datain:?});
	 reqs0[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2;
	 let req <- toGet(reqs0[i]).get;
	 match {.ptr,.offreq} = req;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;

         Page off = truncate(offreq >> valueOf(SGListPageShift0));
         Page4 off4 = truncate(offreq >> valueOf(SGListPageShift4));
         Page4 off8 = truncate(offreq >> valueOf(SGListPageShift8));
	 let cond8 = off8 < truncate(region8.barrier);
	 let cond4 = off4 < truncate(region4.barrier);
	 let cond0 = off < region0.barrier;

	 conds[i].enq(tuple3(cond8,cond4,cond0));
	 idxOffsets0[i].enq(tuple3(region8.idxOffset,region4.idxOffset, region0.idxOffset));
	 reqs1[i].enq(req);
      endrule
      rule stage3;
	 match{.ptr,.off} <- toGet(reqs1[i]).get;
	 Offset o = Offset{pageSize: 0, value: truncate(off)};
	 Bit#(8) pbase = 0;
	 Bit#(8) idxOffset = 0;

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

	 if (cond8) begin
	    //$display("request: ptr=%h off=%h", ptr, off);
	    o.pageSize = 3;
	    pbase = truncate(off>>page_shift8);
	    idxOffset = idxOffset8;
	 end
	 else if (cond4) begin
	    //$display("request: ptr=%h off=%h", ptr, off);
	    o.pageSize = 2;
	    pbase = truncate(off>>page_shift4);
	    idxOffset = idxOffset4;
	 end
	 else if (cond0) begin
	    //$display("request: ptr=%h off=%h", ptr, off);
	    o.pageSize = 1;
	    pbase = truncate(off>>page_shift0);
	    idxOffset = idxOffset0;
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets1[i].enq(idxOffset);
	 ptrs1[i].enq(ptr);
      endrule
      rule stage4;
	 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#(8) p = pbase + idxOffset;
	 if (off.pageSize == 0) begin
	    //FIXME offset
	    //$display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadAddrTrans, pref: extend(ptr) });
	 end
	 //$display("p ages[%d].read %h", i, rp[i].first());
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:{ptr,p}, datain:?});
	 offs1[i].enq(off);
      endrule
      rule stage5;
	 Page page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 //$display("p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(ObjectOffsetSize) 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();
      dmaIndication.configResp(extend(ptr));
   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();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   // FIXME: split this into three methods?
   method Action region(Bit#(32) ptr, Bit#(36) barr8, Bit#(36) barr4, Bit#(36) barr0);
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(ptr), datain: unpack(barr8)});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(ptr), datain: unpack(barr4)});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(ptr), datain: unpack(barr0)});
      //$display("region ptr=%d off8=%h off4=%h off0=%h", ptr, off8, off4, off0);
      configRespFifo.enq(truncate(ptr));
   endmethod

   method Action sglist(Bit#(32) ptr, Bit#(40) paddr, Bit#(32) len);
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(ptr)}, datain:truncate(paddr)});
   endmethod
   interface addr = addrServers;

endmodule

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

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(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 PortalMemory::*;

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

interface SGListMMU#(numeric type addrWidth);
   method Action sglist(Bit#(32) pointer, Bit#(40) paddr, Bit#(32) len);
   method Action region(Bit#(32) ptr, Bit#(36) barr8, Bit#(36) barr4, Bit#(36) barr0);
   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#(ObjectOffsetSize,SGListPageShift0)) Page;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) Page4;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) Page8;

typedef struct {
   Bit#(28) barrier;
   Bit#(8) idxOffset;
   } Region deriving (Eq,Bits,FShow);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

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

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- 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#(8),Bit#(8),Bit#(8)))) 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#(8)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(8)))    idxOffsets1 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))         ptrs1 <- replicateM(mkFIFOF);

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

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

   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;
	 let req <- toGet(incomingReqs[i]).get();
	 match { .ptr, .off } = req;
	 portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr), datain:?});
	 portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr), datain:?});
	 portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr), datain:?});
	 reqs0[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2;
	 let req <- toGet(reqs0[i]).get;
	 match {.ptr,.offreq} = req;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;

         Page off = truncate(offreq >> valueOf(SGListPageShift0));
         Page4 off4 = truncate(offreq >> valueOf(SGListPageShift4));
         Page4 off8 = truncate(offreq >> valueOf(SGListPageShift8));
	 let cond8 = off8 < truncate(region8.barrier);
	 let cond4 = off4 < truncate(region4.barrier);
	 let cond0 = off < region0.barrier;

	 conds[i].enq(tuple3(cond8,cond4,cond0));
	 idxOffsets0[i].enq(tuple3(region8.idxOffset,region4.idxOffset, region0.idxOffset));
	 reqs1[i].enq(req);
      endrule
      rule stage3;
	 match{.ptr,.off} <- toGet(reqs1[i]).get;
	 Offset o = Offset{pageSize: 0, value: truncate(off)};
	 Bit#(8) pbase = 0;
	 Bit#(8) idxOffset = 0;

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

	 if (cond8) begin
	    //$display("request: ptr=%h off=%h", ptr, off);
	    o.pageSize = 3;
	    pbase = truncate(off>>page_shift8);
	    idxOffset = idxOffset8;
	 end
	 else if (cond4) begin
	    //$display("request: ptr=%h off=%h", ptr, off);
	    o.pageSize = 2;
	    pbase = truncate(off>>page_shift4);
	    idxOffset = idxOffset4;
	 end
	 else if (cond0) begin
	    //$display("request: ptr=%h off=%h", ptr, off);
	    o.pageSize = 1;
	    pbase = truncate(off>>page_shift0);
	    idxOffset = idxOffset0;
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets1[i].enq(idxOffset);
	 ptrs1[i].enq(ptr);
      endrule
      rule stage4;
	 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#(8) p = pbase + idxOffset;
	 if (off.pageSize == 0) begin
	    //FIXME offset
	    //$display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaIndication.dmaError(extend(pack(DmaErrorBadAddrTrans)), extend(ptr), -1, 0);
	 end
	 //$display("p ages[%d].read %h", i, rp[i].first());
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:{ptr,p}, datain:?});
	 offs1[i].enq(off);
      endrule
      rule stage5;
	 Page page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 //$display("p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(ObjectOffsetSize) 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();
      dmaIndication.configResp(extend(ptr));
   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();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   // FIXME: split this into three methods?
   method Action region(Bit#(32) ptr, Bit#(36) barr8, Bit#(36) barr4, Bit#(36) barr0);
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(ptr), datain: unpack(barr8)});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(ptr), datain: unpack(barr4)});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(ptr), datain: unpack(barr0)});
      //$display("region ptr=%d off8=%h off4=%h off0=%h", ptr, off8, off4, off0);
      configRespFifo.enq(truncate(ptr));
   endmethod

   method Action sglist(Bit#(32) ptr, Bit#(40) paddr, Bit#(32) len);
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(ptr)}, datain:truncate(paddr)});
   endmethod
   interface addr = addrServers;

endmodule

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

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(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


bugfix on asymmetric bram

bugfix on asymmetric bram

/*-
 * Copyright (c) 2013, 2014 Alexandre Joannou
 * Copyright (c) 2015 Han Wang
 * All rights reserved.
 *
 * This software was developed by SRI International and the University of
 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
 * ("MRC2"), as part of the DARPA MRC research programme.
 *
 * @BERI_LICENSE_HEADER_START@
 *
 * Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.  BERI licenses this
 * file to you under the BERI Hardware-Software License, Version 1.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at:
 *
 *   http://www.beri-open-systems.org/legal/license-1-0.txt
 *
 * Unless required by applicable law or agreed to in writing, Work distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @BERI_LICENSE_HEADER_END@
 */

package AsymmetricBRAM;

import Connectable::*;
import ClientServer::*;
import FIFO :: *;
import FIFOF :: *;
import GetPut::*;
import SpecialFIFOs :: *;
import ConfigReg :: * ;
import Vector :: * ;
import Pipe::*;

// Interface to the asymmetric ram
interface AsymmetricBRAM#(  type rAddrT, type rDataT,
                            type wAddrT, type wDataT);
   interface Put#(Tuple2#(wAddrT, wDataT)) writeServer;
   interface Server#(rAddrT, rDataT) readServer;
endinterface

// Interface to the verilog module (using an altsyncram component)
interface VAsymBRAMIfc#(    type rAddrT,type rDataT,
                            type wAddrT, type wDataT);
    method Action read(rAddrT read_addr);
    method rDataT getRead();
    method Action write(wAddrT write_addr, wDataT write_data);
endinterface

// Assume narrower write port
// Wrapper for the verilog
`ifndef SIMULATION
`ifdef ALTERA
import "BVI" AsymmetricBRAM_Altera =
`endif
`ifdef XILINX
import "BVI" AsymmetricBRAM_Xilinx =
`endif
module vAsymBRAM#(Bool hasOutputRegister)
                 (VAsymBRAMIfc#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz)
    );

    default_clock (CLK);
    default_reset no_reset;

    parameter   PIPELINED   = Bit#(1)'(pack(hasOutputRegister));
    parameter   WADDR_WIDTH = valueOf(waddr_sz);
    parameter   WDATA_WIDTH = valueOf(wdata_sz);
    parameter   RADDR_WIDTH = valueOf(raddr_sz);
    parameter   RDATA_WIDTH = valueOf(rdata_sz);
    parameter   MEMSIZE     = valueOf(TExp#(waddr_sz));

    method read(RADDR) enable(REN);
    method RDATA getRead();
    method write(WADDR,WDATA) enable(WEN);

    schedule (getRead) SBR (read, write);
    schedule (read)  C (read);
    schedule (write) C (write);
    schedule (getRead) CF (getRead);
    schedule (write) CF (read);

endmodule
`endif

module mkAsymmetricBRAM#(Bool hasOutputRegister, Bool hasForwarding, String name)
                               (AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz),
        Div#(rdata_sz,wdata_sz,ratio),
        Log#(ratio,offset_sz),
        Add#(raddr_sz,offset_sz,waddr_sz),
        Bits#(Vector#(ratio, wdata_t), rdata_sz)
    );
    AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t) ret_ifc;
    `ifndef SIMULATION
        ret_ifc <- mkAsymmetricBRAMVerilog(hasOutputRegister, hasForwarding);
    `else
        ret_ifc <- mkAsymmetricBRAMBluesim(hasOutputRegister, hasForwarding, name);
    `endif
    return ret_ifc;
endmodule

`ifndef SIMULATION
module mkAsymmetricBRAMVerilog#(Bool hasOutputRegister, Bool hasForwarding)
                               (AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz),
        Div#(rdata_sz,wdata_sz,ratio),
        Log#(ratio,offset_sz),
        Add#(raddr_sz,offset_sz,waddr_sz),
        Bits#(Vector#(ratio, wdata_t), rdata_sz)
    );
    FIFO#(Tuple2#(waddr_t, wdata_t)) writeReqFifo <- mkFIFO;
    FIFO#(raddr_t) readReqFifo <- mkFIFO;
    FIFO#(rdata_t) readDataFifo <- mkFIFO;
    FIFO#(void) readCtrlFifo <- mkFIFO;

    VAsymBRAMIfc#(raddr_t, rdata_t, waddr_t, wdata_t) bram <- vAsymBRAM(hasOutputRegister);

    rule do_read;
       let v <- toGet(readReqFifo).get;
       bram.read(v);
       readCtrlFifo.enq(?);
    endrule

    rule do_reponse;
       let v <- toGet(readCtrlFifo).get;
       let addr = bram.getRead;
       readDataFifo.enq(addr);
    endrule

    rule do_write;
       let v <- toGet(writeReqFifo).get;
       let addr = tpl_1(v);
       let data = tpl_2(v);
       bram.write(addr, data);
    endrule

    interface Put writeServer = toPut(writeReqFifo);
    interface readServer = (interface Server;
      interface Put request;
         method Action put(raddr_t addr);
            readReqFifo.enq(addr);
         endmethod
      endinterface
      interface Get response = toGet(readDataFifo);
   endinterface);

endmodule
`endif

import "BDPI" mem_create    = function ActionValue#(Bit#(64)) mem_create(msize_t size, rsize_t rsize, wsize_t wsize)
                              provisos (Bits#(msize_t, msize_sz),
                                        Bits#(rsize_t, rsize_sz),
                                        Bits#(wsize_t, wsize_sz));
import "BDPI" mem_clean     = function Action mem_clean(Bit#(64) mem_ptr);
import "BDPI" mem_read      = function ActionValue#(rdata_t) mem_read(Bit#(64) mem_ptr, raddr_t raddr)
                              provisos (Bits#(raddr_t, raddr_sz),
                                        Bits#(rdata_t, rdata_sz));
import "BDPI" mem_write     = function Action mem_write(Bit#(64) mem_ptr, waddr_t waddr, wdata_t wdata)
                              provisos (Bits#(waddr_t, waddr_sz),
                                        Bits#(wdata_t, wdata_sz));

module mkAsymmetricBRAMBluesim#(Bool hasOutputRegister, Bool hasForwarding, String name)
                               (AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz),
        Div#(rdata_sz,wdata_sz,ratio),
        Log#(ratio,offset_sz),
        Add#(raddr_sz,offset_sz,waddr_sz),
        Bits#(Vector#(ratio, wdata_t), rdata_sz)
    );
    let verbose = False;
    FIFO#(Tuple2#(waddr_t, wdata_t)) writeReqFifo <- mkFIFO;
    FIFO#(raddr_t) readReqFifo <- mkFIFO;
    FIFO#(rdata_t) readDataFifo <- mkFIFO;

    Reg#(Bit#(64))  mem_ptr         <- mkRegU();
    Reg#(Bool)      isInitialized   <- mkReg(False);

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

    (* execution_order = "do_read, do_write" *)
    rule do_read (isInitialized);
       let v <- toGet(readReqFifo).get;
       rdata_t rdata  <- mem_read(mem_ptr, v);
       readDataFifo.enq(rdata);
       if (verbose) $display("%s %d: read data from %x with index %x = %x", name, cntr, mem_ptr, v, rdata);
    endrule

    rule do_write (isInitialized);
       let v <- toGet(writeReqFifo).get;
       let writeAddr = tpl_1(v);
       let writeData = tpl_2(v);
       mem_write(mem_ptr, writeAddr, writeData);
       if (verbose) $display("%s %d: write data to %x with index %x = %x", name, cntr, mem_ptr, writeAddr, writeData);
    endrule

    rule do_init (!isInitialized);
       let tmp <- mem_create(fromInteger(valueOf(TExp#(waddr_sz))),
                             fromInteger(valueOf(rdata_sz)),
                             fromInteger(valueOf(wdata_sz)));
       mem_ptr <= tmp;
       isInitialized <= True;

       if (valueOf(raddr_sz) > 64) begin
          $display("raddr_sz larger than 64 is not supported");
       end
    endrule

   interface Put writeServer = toPut(writeReqFifo);
   interface readServer = (interface Server;
      interface Put request;
         method Action put(raddr_t addr);
            readReqFifo.enq(addr);
         endmethod
      endinterface
      interface Get response = toGet(readDataFifo);
   endinterface);
endmodule

endpackage

/*-
 * Copyright (c) 2013, 2014 Alexandre Joannou
 * Copyright (c) 2015 Han Wang
 * All rights reserved.
 *
 * This software was developed by SRI International and the University of
 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249
 * ("MRC2"), as part of the DARPA MRC research programme.
 *
 * @BERI_LICENSE_HEADER_START@
 *
 * Licensed to BERI Open Systems C.I.C. (BERI) under one or more contributor
 * license agreements.  See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.  BERI licenses this
 * file to you under the BERI Hardware-Software License, Version 1.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at:
 *
 *   http://www.beri-open-systems.org/legal/license-1-0.txt
 *
 * Unless required by applicable law or agreed to in writing, Work distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @BERI_LICENSE_HEADER_END@
 */

package AsymmetricBRAM;

import Connectable::*;
import ClientServer::*;
import FIFO :: *;
import FIFOF :: *;
import GetPut::*;
import SpecialFIFOs :: *;
import ConfigReg :: * ;
import Vector :: * ;
import Pipe::*;

// Interface to the asymmetric ram
interface AsymmetricBRAM#(  type rAddrT, type rDataT,
                            type wAddrT, type wDataT);
   interface Put#(Tuple2#(wAddrT, wDataT)) writeServer;
   interface Server#(rAddrT, rDataT) readServer;
endinterface

// Interface to the verilog module (using an altsyncram component)
interface VAsymBRAMIfc#(    type rAddrT,type rDataT,
                            type wAddrT, type wDataT);
    method Action read(rAddrT read_addr);
    method rDataT getRead();
    method Action write(wAddrT write_addr, wDataT write_data);
endinterface

// Assume narrower write port
// Wrapper for the verilog
`ifdef ALTERA
import "BVI" AsymmetricBRAM_Altera =
`else
import "BVI" AsymmetricBRAM_Xilinx =
module vAsymBRAM#(Bool hasOutputRegister)
                 (VAsymBRAMIfc#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz)
    );

    default_clock (CLK);
    default_reset no_reset;

    parameter   PIPELINED   = Bit#(1)'(pack(hasOutputRegister));
    parameter   WADDR_WIDTH = valueOf(waddr_sz);
    parameter   WDATA_WIDTH = valueOf(wdata_sz);
    parameter   RADDR_WIDTH = valueOf(raddr_sz);
    parameter   RDATA_WIDTH = valueOf(rdata_sz);
    parameter   MEMSIZE     = valueOf(TExp#(waddr_sz));

    method read(RADDR) enable(REN);
    method RDATA getRead();
    method write(WADDR,WDATA) enable(WEN);

    schedule (getRead) SBR (read, write);
    schedule (read)  C (read);
    schedule (write) C (write);
    schedule (getRead) CF (getRead);
    schedule (write) CF (read);

endmodule
`endif

module mkAsymmetricBRAM#(Bool hasOutputRegister, Bool hasForwarding, String name)
                               (AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz),
        Div#(rdata_sz,wdata_sz,ratio),
        Log#(ratio,offset_sz),
        Add#(raddr_sz,offset_sz,waddr_sz),
        Bits#(Vector#(ratio, wdata_t), rdata_sz)
    );
    AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t) ret_ifc;
    `ifndef SIMULATION
        ret_ifc <- mkAsymmetricBRAMVerilog(hasOutputRegister, hasForwarding);
    `else
        ret_ifc <- mkAsymmetricBRAMBluesim(hasOutputRegister, hasForwarding, name);
    `endif
    return ret_ifc;
endmodule

module mkAsymmetricBRAMVerilog#(Bool hasOutputRegister, Bool hasForwarding)
                               (AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz),
        Div#(rdata_sz,wdata_sz,ratio),
        Log#(ratio,offset_sz),
        Add#(raddr_sz,offset_sz,waddr_sz),
        Bits#(Vector#(ratio, wdata_t), rdata_sz)
    );
    FIFO#(Tuple2#(waddr_t, wdata_t)) writeReqFifo <- mkFIFO;
    FIFO#(raddr_t) readReqFifo <- mkFIFO;
    FIFO#(rdata_t) readDataFifo <- mkFIFO;
    FIFO#(void) readCtrlFifo <- mkFIFO;

    VAsymBRAMIfc#(raddr_t, rdata_t, waddr_t, wdata_t) bram <- vAsymBRAM(hasOutputRegister);

    rule do_read;
       let v <- toGet(readReqFifo).get;
       bram.read(v);
       readCtrlFifo.enq(?);
    endrule

    rule do_reponse;
       let v <- toGet(readCtrlFifo).get;
       let addr = bram.getRead;
       readDataFifo.enq(addr);
    endrule

    rule do_write;
       let v <- toGet(writeReqFifo).get;
       let addr = tpl_1(v);
       let data = tpl_2(v);
       bram.write(addr, data);
    endrule

    interface Put writeServer = toPut(writeReqFifo);
    interface readServer = (interface Server;
      interface Put request;
         method Action put(raddr_t addr);
            readReqFifo.enq(addr);
         endmethod
      endinterface
      interface Get response = toGet(readDataFifo);
   endinterface);

endmodule

import "BDPI" mem_create    = function ActionValue#(Bit#(64)) mem_create(msize_t size, rsize_t rsize, wsize_t wsize)
                              provisos (Bits#(msize_t, msize_sz),
                                        Bits#(rsize_t, rsize_sz),
                                        Bits#(wsize_t, wsize_sz));
import "BDPI" mem_clean     = function Action mem_clean(Bit#(64) mem_ptr);
import "BDPI" mem_read      = function ActionValue#(rdata_t) mem_read(Bit#(64) mem_ptr, raddr_t raddr)
                              provisos (Bits#(raddr_t, raddr_sz),
                                        Bits#(rdata_t, rdata_sz));
import "BDPI" mem_write     = function Action mem_write(Bit#(64) mem_ptr, waddr_t waddr, wdata_t wdata)
                              provisos (Bits#(waddr_t, waddr_sz),
                                        Bits#(wdata_t, wdata_sz));

module mkAsymmetricBRAMBluesim#(Bool hasOutputRegister, Bool hasForwarding, String name)
                               (AsymmetricBRAM#(raddr_t, rdata_t, waddr_t, wdata_t))
    provisos(
        Bits#(raddr_t, raddr_sz),
        Bits#(rdata_t, rdata_sz),
        Bits#(waddr_t, waddr_sz),
        Bits#(wdata_t, wdata_sz),
        Div#(rdata_sz,wdata_sz,ratio),
        Log#(ratio,offset_sz),
        Add#(raddr_sz,offset_sz,waddr_sz),
        Bits#(Vector#(ratio, wdata_t), rdata_sz)
    );
    let verbose = False;
    FIFO#(Tuple2#(waddr_t, wdata_t)) writeReqFifo <- mkFIFO;
    FIFO#(raddr_t) readReqFifo <- mkFIFO;
    FIFO#(rdata_t) readDataFifo <- mkFIFO;

    Reg#(Bit#(64))  mem_ptr         <- mkRegU();
    Reg#(Bool)      isInitialized   <- mkReg(False);

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

    (* execution_order = "do_read, do_write" *)
    rule do_read (isInitialized);
       let v <- toGet(readReqFifo).get;
       rdata_t rdata  <- mem_read(mem_ptr, v);
       readDataFifo.enq(rdata);
       if (verbose) $display("%s %d: read data from %x with index %x = %x", name, cntr, mem_ptr, v, rdata);
    endrule

    rule do_write (isInitialized);
       let v <- toGet(writeReqFifo).get;
       let writeAddr = tpl_1(v);
       let writeData = tpl_2(v);
       mem_write(mem_ptr, writeAddr, writeData);
       if (verbose) $display("%s %d: write data to %x with index %x = %x", name, cntr, mem_ptr, writeAddr, writeData);
    endrule

    rule do_init (!isInitialized);
       let tmp <- mem_create(fromInteger(valueOf(TExp#(waddr_sz))),
                             fromInteger(valueOf(rdata_sz)),
                             fromInteger(valueOf(wdata_sz)));
       mem_ptr <= tmp;
       isInitialized <= True;

       if (valueOf(raddr_sz) > 64) begin
          $display("raddr_sz larger than 64 is not supported");
       end
    endrule

   interface Put writeServer = toPut(writeReqFifo);
   interface readServer = (interface Server;
      interface Put request;
         method Action put(raddr_t addr);
            readReqFifo.enq(addr);
         endmethod
      endinterface
      interface Get response = toGet(readDataFifo);
   endinterface);
endmodule

endpackage