include ConnectalProjectConfig.bsv in SharedBuffMemServer

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import FIFO::*;
import Vector::*;
import List::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Connectable::*;
import HostInterface::*;
import MemTypes::*;
import ConnectalConfig::*;
import ConnectalMemory::*;
import SharedBuffMMU::*;
import SharedBuffMemServerInternal::*;
`include "ConnectalProjectConfig.bsv"

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

interface MemServerWithMMU#(numeric type addrWidth, numeric type busWidth, numeric type nMasters);
   interface MemServerRequest memServerRequest;
   interface Vector#(nMasters,PhysMemMaster#(addrWidth, busWidth)) masters;
   interface MMURequest mmuRequest;
endinterface

interface MemServerRead#(numeric type addrWidth, numeric type busWidth, numeric type numClients, numeric type numServers);
   interface MemServerRequest request;
   interface Vector#(numClients, PhysMemReadClient#(addrWidth,busWidth)) clients;
   interface Vector#(numServers, MemReadServer#(busWidth)) servers;
endinterface

interface MemServerWrite#(numeric type addrWidth, numeric type busWidth, numeric type numClients, numeric type numServers);
   interface MemServerRequest request;
   interface Vector#(numClients, PhysMemWriteClient#(addrWidth,busWidth)) clients;
   interface Vector#(numServers, MemWriteServer#(busWidth)) servers;
endinterface

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

module mkMemServer#(Vector#(numReadClients, MemReadClient#(busWidth)) readClients,
		    Vector#(numWriteClients, MemWriteClient#(busWidth)) writeClients,
		    Vector#(numMMUs,MMU#(addrWidth)) mmus,
		    MemServerIndication indication)
   (MemServer#(addrWidth, busWidth, nMasters))
   provisos(Mul#(TDiv#(numWriteClients, nMasters),nMasters,nws)
	    ,Mul#(TDiv#(numReadClients, nMasters),nMasters,nrs)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), a__, 8)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), b__, BurstLenSize)
	    ,Add#(c__, addrWidth, 64)
	    ,Add#(numWriteClients, d__, nws)
	    ,Add#(numReadClients, e__, nrs)
`ifdef BYTE_ENABLES
	    ,Add#(f__, TDiv#(busWidth, 8), ByteEnableSize)
`endif
	    );

   MemServerRead#(addrWidth,busWidth,nMasters,nrs)  reader <- mkMemServerRead(indication, mmus);
   MemServerWrite#(addrWidth,busWidth,nMasters,nws) writer <- mkMemServerWrite(indication, mmus);

   zipWithM_(mkConnection,readClients,take(reader.servers));
   zipWithM_(mkConnection,writeClients,take(writer.servers));

   function PhysMemMaster#(addrWidth,busWidth) mkm(Integer i) = (interface PhysMemMaster#(addrWidth,busWidth);
		     interface PhysMemReadClient read_client = reader.clients[i];
		     interface PhysMemWriteClient write_client = writer.clients[i];
		  endinterface);

   interface MemServerRequest request;
      method Action setTileState(TileControl tc);
	 reader.request.setTileState(tc);
	 writer.request.setTileState(tc);
      endmethod
      method Action stateDbg(ChannelType rc);
	 if (rc == ChannelType_Read)
	    reader.request.stateDbg(rc);
	 else
	    writer.request.stateDbg(rc);
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == ChannelType_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 mkMemServerRead#(MemServerIndication indication,
			Vector#(numMMUs,MMU#(addrWidth)) mmus)
   (MemServerRead#(addrWidth, busWidth, numClients, numServers))
   provisos(Mul#(nrc, numClients, numServers)
	    ,Add#(a__, addrWidth, 64)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), b__, 8)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), c__, BurstLenSize)
`ifdef BYTE_ENABLES
	    ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
`endif
	    );

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

   function Server#(AddrTransRequest,AddrTransResponse#(addrWidth)) selectMMUPort(Integer i);
      return mmus[i].addr[0];
   endfunction
   Vector#(numMMUs,ArbitratedMMU#(addrWidth,numClients)) mmu_servers <- mapM(mkArbitratedMMU,map(selectMMUPort,genVector));
   Vector#(numClients,MemReadInternal#(addrWidth,busWidth,MemServerTags,nrc)) readers;
   Vector#(numClients, PhysMemReadClient#(addrWidth,busWidth)) read_clients;
   Vector#(numServers, MemReadServer#(busWidth)) read_servers;

   for(Integer i = 0; i < valueOf(numClients); i = i+1) begin
      Vector#(numMMUs,Server#(AddrTransRequest,AddrTransResponse#(addrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      readers[i] <- mkMemReadInternal(indication,ss);
      read_clients[i] = readers[i].client;
      for(Integer j = 0; j < valueOf(nrc); j=j+1)
	 read_servers[i*valueOf(nrc)+j] = readers[i].servers[j];
   end

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

   Stmt dbgStmt =
   seq
      for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(numClients)); 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(numClients)); trafficPtr <= trafficPtr+1)
	 (action
	     let rv <- readers[trafficPtr].dbg.getMemoryTraffic();
	     trafficAccum <= trafficAccum + rv;
	  endaction);
      indication.reportMemoryTraffic(trafficAccum);
   endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface servers = read_servers;
   interface clients = read_clients;
   interface MemServerRequest request;
      method Action setTileState(TileControl tc);
	 for(Integer i = 0; i < valueOf(numClients); i=i+1)
	    readers[i].tileControl.put(tc);
      endmethod
      method Action stateDbg(ChannelType rc);
	 if (rc == ChannelType_Read)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == ChannelType_Read)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[0].request.put(AddrTransRequest{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
endmodule

module mkMemServerWrite#(MemServerIndication indication,
		     Vector#(numMMUs,MMU#(addrWidth)) mmus)
   (MemServerWrite#(addrWidth, busWidth, numClients, numServers))
   provisos(Mul#(nwc, numClients, numServers)
	    ,Add#(a__, addrWidth, 64)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), b__, 8)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), c__, BurstLenSize)
`ifdef BYTE_ENABLES
	    ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
`endif
	    );

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

   function Server#(AddrTransRequest,AddrTransResponse#(addrWidth)) selectMMUPort(Integer i);
      return mmus[i].addr[1];
   endfunction
   Vector#(numMMUs,ArbitratedMMU#(addrWidth,numClients)) mmu_servers <- mapM(mkArbitratedMMU,map(selectMMUPort,genVector));
   Vector#(numClients,MemWriteInternal#(addrWidth,busWidth,MemServerTags,nwc)) writers;
   Vector#(numClients, PhysMemWriteClient#(addrWidth,busWidth)) write_clients;
   Vector#(numServers, MemWriteServer#(busWidth)) write_servers;

   for(Integer i = 0; i < valueOf(numClients); i = i+1) begin
      Vector#(numMMUs,Server#(AddrTransRequest,AddrTransResponse#(addrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      writers[i] <- mkMemWriteInternal(indication, ss);
      write_clients[i] = writers[i].client;
      for(Integer j = 0; j < valueOf(nwc); j=j+1)
	 write_servers[i*valueOf(nwc)+j] = writers[i].servers[j];
   end

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

   Stmt dbgStmt =
   seq
      for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(numClients)); 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(numClients)); trafficPtr <= trafficPtr+1)
	 (action
	     let rv <- writers[trafficPtr].dbg.getMemoryTraffic();
	     trafficAccum <= trafficAccum + rv;
	  endaction);
      indication.reportMemoryTraffic(trafficAccum);
   endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface servers = write_servers;
   interface clients = write_clients;
   interface MemServerRequest request;
      method Action setTileState(TileControl tc);
	 for(Integer i = 0; i < valueOf(numClients); i=i+1)
	    writers[i].tileControl.put(tc);
      endmethod
      method Action stateDbg(ChannelType rc);
	 if (rc == ChannelType_Write)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == ChannelType_Write)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[1].request.put(AddrTransRequest{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
endmodule

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import FIFO::*;
import Vector::*;
import List::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Connectable::*;
import HostInterface::*;
import MemTypes::*;
import ConnectalConfig::*;
import ConnectalMemory::*;
import SharedBuffMMU::*;
import SharedBuffMemServerInternal::*;

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

interface MemServerWithMMU#(numeric type addrWidth, numeric type busWidth, numeric type nMasters);
   interface MemServerRequest memServerRequest;
   interface Vector#(nMasters,PhysMemMaster#(addrWidth, busWidth)) masters;
   interface MMURequest mmuRequest;
endinterface

interface MemServerRead#(numeric type addrWidth, numeric type busWidth, numeric type numClients, numeric type numServers);
   interface MemServerRequest request;
   interface Vector#(numClients, PhysMemReadClient#(addrWidth,busWidth)) clients;
   interface Vector#(numServers, MemReadServer#(busWidth)) servers;
endinterface

interface MemServerWrite#(numeric type addrWidth, numeric type busWidth, numeric type numClients, numeric type numServers);
   interface MemServerRequest request;
   interface Vector#(numClients, PhysMemWriteClient#(addrWidth,busWidth)) clients;
   interface Vector#(numServers, MemWriteServer#(busWidth)) servers;
endinterface

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

module mkMemServer#(Vector#(numReadClients, MemReadClient#(busWidth)) readClients,
		    Vector#(numWriteClients, MemWriteClient#(busWidth)) writeClients,
		    Vector#(numMMUs,MMU#(addrWidth)) mmus,
		    MemServerIndication indication)
   (MemServer#(addrWidth, busWidth, nMasters))
   provisos(Mul#(TDiv#(numWriteClients, nMasters),nMasters,nws)
	    ,Mul#(TDiv#(numReadClients, nMasters),nMasters,nrs)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), a__, 8)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), b__, BurstLenSize)
	    ,Add#(c__, addrWidth, 64)
	    ,Add#(numWriteClients, d__, nws)
	    ,Add#(numReadClients, e__, nrs)
	    ,Add#(f__, TDiv#(busWidth, 8), ByteEnableSize)
	    );

   MemServerRead#(addrWidth,busWidth,nMasters,nrs)  reader <- mkMemServerRead(indication, mmus);
   MemServerWrite#(addrWidth,busWidth,nMasters,nws) writer <- mkMemServerWrite(indication, mmus);

   zipWithM_(mkConnection,readClients,take(reader.servers));
   zipWithM_(mkConnection,writeClients,take(writer.servers));

   function PhysMemMaster#(addrWidth,busWidth) mkm(Integer i) = (interface PhysMemMaster#(addrWidth,busWidth);
		     interface PhysMemReadClient read_client = reader.clients[i];
		     interface PhysMemWriteClient write_client = writer.clients[i];
		  endinterface);

   interface MemServerRequest request;
      method Action setTileState(TileControl tc);
	 reader.request.setTileState(tc);
	 writer.request.setTileState(tc);
      endmethod
      method Action stateDbg(ChannelType rc);
	 if (rc == ChannelType_Read)
	    reader.request.stateDbg(rc);
	 else
	    writer.request.stateDbg(rc);
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == ChannelType_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 mkMemServerRead#(MemServerIndication indication,
			Vector#(numMMUs,MMU#(addrWidth)) mmus)
   (MemServerRead#(addrWidth, busWidth, numClients, numServers))
   provisos(Mul#(nrc, numClients, numServers)
	    ,Add#(a__, addrWidth, 64)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), b__, 8)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), c__, BurstLenSize)
	    ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
	    );

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

   function Server#(AddrTransRequest,AddrTransResponse#(addrWidth)) selectMMUPort(Integer i);
      return mmus[i].addr[0];
   endfunction
   Vector#(numMMUs,ArbitratedMMU#(addrWidth,numClients)) mmu_servers <- mapM(mkArbitratedMMU,map(selectMMUPort,genVector));
   Vector#(numClients,MemReadInternal#(addrWidth,busWidth,MemServerTags,nrc)) readers;
   Vector#(numClients, PhysMemReadClient#(addrWidth,busWidth)) read_clients;
   Vector#(numServers, MemReadServer#(busWidth)) read_servers;

   for(Integer i = 0; i < valueOf(numClients); i = i+1) begin
      Vector#(numMMUs,Server#(AddrTransRequest,AddrTransResponse#(addrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      readers[i] <- mkMemReadInternal(indication,ss);
      read_clients[i] = readers[i].client;
      for(Integer j = 0; j < valueOf(nrc); j=j+1)
	 read_servers[i*valueOf(nrc)+j] = readers[i].servers[j];
   end

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

   Stmt dbgStmt =
   seq
      for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(numClients)); 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(numClients)); trafficPtr <= trafficPtr+1)
	 (action
	     let rv <- readers[trafficPtr].dbg.getMemoryTraffic();
	     trafficAccum <= trafficAccum + rv;
	  endaction);
      indication.reportMemoryTraffic(trafficAccum);
   endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface servers = read_servers;
   interface clients = read_clients;
   interface MemServerRequest request;
      method Action setTileState(TileControl tc);
	 for(Integer i = 0; i < valueOf(numClients); i=i+1)
	    readers[i].tileControl.put(tc);
      endmethod
      method Action stateDbg(ChannelType rc);
	 if (rc == ChannelType_Read)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == ChannelType_Read)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[0].request.put(AddrTransRequest{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
endmodule

module mkMemServerWrite#(MemServerIndication indication,
		     Vector#(numMMUs,MMU#(addrWidth)) mmus)
   (MemServerWrite#(addrWidth, busWidth, numClients, numServers))
   provisos(Mul#(nwc, numClients, numServers)
	    ,Add#(a__, addrWidth, 64)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), b__, 8)
	    ,Add#(TLog#(TDiv#(busWidth, 8)), c__, BurstLenSize)
	    ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
	    );

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

   function Server#(AddrTransRequest,AddrTransResponse#(addrWidth)) selectMMUPort(Integer i);
      return mmus[i].addr[1];
   endfunction
   Vector#(numMMUs,ArbitratedMMU#(addrWidth,numClients)) mmu_servers <- mapM(mkArbitratedMMU,map(selectMMUPort,genVector));
   Vector#(numClients,MemWriteInternal#(addrWidth,busWidth,MemServerTags,nwc)) writers;
   Vector#(numClients, PhysMemWriteClient#(addrWidth,busWidth)) write_clients;
   Vector#(numServers, MemWriteServer#(busWidth)) write_servers;

   for(Integer i = 0; i < valueOf(numClients); i = i+1) begin
      Vector#(numMMUs,Server#(AddrTransRequest,AddrTransResponse#(addrWidth))) ss;
      for(Integer j = 0; j < valueOf(numMMUs); j=j+1)
	 ss[j] = mmu_servers[j].servers[i];
      writers[i] <- mkMemWriteInternal(indication, ss);
      write_clients[i] = writers[i].client;
      for(Integer j = 0; j < valueOf(nwc); j=j+1)
	 write_servers[i*valueOf(nwc)+j] = writers[i].servers[j];
   end

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

   Stmt dbgStmt =
   seq
      for(dbgPtr <= 0; dbgPtr < fromInteger(valueOf(numClients)); 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(numClients)); trafficPtr <= trafficPtr+1)
	 (action
	     let rv <- writers[trafficPtr].dbg.getMemoryTraffic();
	     trafficAccum <= trafficAccum + rv;
	  endaction);
      indication.reportMemoryTraffic(trafficAccum);
   endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface servers = write_servers;
   interface clients = write_clients;
   interface MemServerRequest request;
      method Action setTileState(TileControl tc);
	 for(Integer i = 0; i < valueOf(numClients); i=i+1)
	    writers[i].tileControl.put(tc);
      endmethod
      method Action stateDbg(ChannelType rc);
	 if (rc == ChannelType_Write)
	    dbgFSM.start;
      endmethod
      method Action memoryTraffic(ChannelType rc);
	 if (rc == ChannelType_Write)
	    trafficFSM.start;
      endmethod
      method Action addrTrans(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(pointer);
	 mmus[pointer[31:16]].addr[1].request.put(AddrTransRequest{id:truncate(pointer), off:extend(offset)});
      endmethod
   endinterface
endmodule


Data -> Bit#(64) in MemoryMappedCSRs

Data -> Bit#(64) in MemoryMappedCSRs

// Copyright (c) 2016 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 ClientServer::*;
import GetPut::*;
import Vector::*;

import CompareProvisos::*;
import Ehr::*;

import Abstraction::*;
import RVTypes::*;

interface MemoryMappedCSRs#(numeric type cores);
    // memory-mapped interface
    // 0x0000 = timer
    // 0x0008 = timecmp0
    // 0x0010 = timecmp1
    //  ...
    // 0x1000 = ipi0
    // 0x2000 = ipi1
    //  ...
    interface UncachedMemServer memifc;
    method Bit#(64) timerValue;
    method Vector#(cores, Bool) timerInterrupt;
    method Vector#(cores, Bool) ipi;
endinterface

// TODO: needs to support single-word writes to support RV32
module mkMemoryMappedCSRs#(Addr baseaddr)(MemoryMappedCSRs#(cores)) provisos (LT#(cores, 16));
    // this doesn't work for 16 or more cores since it assumes a 16 bit address space
    Reg#(Maybe#(UncachedMemResp)) resp <- mkReg(tagged Invalid);

    Reg#(Bit#(10)) subTimer <- mkReg(0);
    Reg#(Bit#(64)) timer <- mkReg(0);
    Ehr#(2, Maybe#(Bit#(64))) newTimeEhr <- mkEhr(tagged Invalid);
    Vector#(cores, Reg#(Bit#(64))) timeCmp <- replicateM(mkReg('1));
    Vector#(cores, Reg#(Bool)) ipiReg <- replicateM(mkReg(False));

    rule incrementTimer;
        if (newTimeEhr[1] matches tagged Valid .validNewTime) begin
            subTimer <= 0;
            timer <= validNewTime;
        end else begin
            Bool overflow = subTimer == 999;
            subTimer <= overflow ? 0 : subTimer + 1;
            timer <= overflow ? timer + 1 : timer;
        end
        newTimeEhr[1] <= tagged Invalid;
    endrule

    interface UncachedMemServer memifc;
        interface Put request;
            method Action put(UncachedMemReq req) if (!isValid(resp));
                UncachedMemResp newResp = UncachedMemResp{write: req.write, data: 0};
                Bit#(16) addr = truncate(req.addr - baseaddr);
                if (addr < 16'h1000) begin
                    // RTC registers
                    if (((addr & 16'h0007) == 0) && (req.size == D)) begin
                        let index = addr >> 3;
                        if (index <= fromInteger(valueof(cores))) begin
                            if (index == 0) begin
                                if (req.write) begin
                                    newTimeEhr[0] <= tagged Valid req.data;
                                end else begin
                                    newResp.data = timer;
                                end
                            end else begin
                                if (req.write) begin
                                    timeCmp[index] <= req.data;
                                end else begin
                                    newResp.data = timeCmp[index];
                                end
                            end
                        end else begin
                            $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                        end
                    end else begin
                        $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                    end
                end else begin
                    // IPI registers
                    if ((addr & 16'h0FFF) == 0) begin
                        let index = addr >> 12;
                        if (index < fromInteger(valueof(cores))) begin
                            if (req.write) begin
                                ipiReg[index] <= unpack(req.data[0]);
                            end else begin
                                newResp.data = zeroExtend(pack(ipiReg[index]));
                            end
                        end else begin
                            $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                        end
                    end else begin
                        $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                    end
                end
                resp <= tagged Valid newResp;
            endmethod
        endinterface
        interface Get response;
            method ActionValue#(UncachedMemResp) get if (resp matches tagged Valid .validResp);
                resp <= tagged Invalid;
                return validResp;
            endmethod
        endinterface
    endinterface
    method Bit#(64) timerValue = timer;
    method Vector#(cores, Bool) timerInterrupt = zipWith( \>= , replicate(timer), readVReg(timeCmp));
    method Vector#(cores, Bool) ipi = readVReg(ipiReg);
endmodule

// Copyright (c) 2016 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 ClientServer::*;
import GetPut::*;
import Vector::*;

import CompareProvisos::*;
import Ehr::*;

import Abstraction::*;
import RVTypes::*;

interface MemoryMappedCSRs#(numeric type cores);
    // memory-mapped interface
    // 0x0000 = timer
    // 0x0008 = timecmp0
    // 0x0010 = timecmp1
    //  ...
    // 0x1000 = ipi0
    // 0x2000 = ipi1
    //  ...
    interface UncachedMemServer memifc;
    method Data timerValue;
    method Vector#(cores, Bool) timerInterrupt;
    method Vector#(cores, Bool) ipi;
endinterface

module mkMemoryMappedCSRs#(Addr baseaddr)(MemoryMappedCSRs#(cores)) provisos (LT#(cores, 16));
    // this doesn't work for 16 or more cores since it assumes a 16 bit address space
    Reg#(Maybe#(UncachedMemResp)) resp <- mkReg(tagged Invalid);

    Reg#(Bit#(10)) subTimer <- mkReg(0);
    Reg#(Data) timer <- mkReg(0);
    Ehr#(2, Maybe#(Data)) newTimeEhr <- mkEhr(tagged Invalid);
    Vector#(cores, Reg#(Data)) timeCmp <- replicateM(mkReg('1));
    Vector#(cores, Reg#(Bool)) ipiReg <- replicateM(mkReg(False));

    rule incrementTimer;
        if (newTimeEhr[1] matches tagged Valid .validNewTime) begin
            subTimer <= 0;
            timer <= validNewTime;
        end else begin
            Bool overflow = subTimer == 999;
            subTimer <= overflow ? 0 : subTimer + 1;
            timer <= overflow ? timer + 1 : timer;
        end
        newTimeEhr[1] <= tagged Invalid;
    endrule

    interface UncachedMemServer memifc;
        interface Put request;
            method Action put(UncachedMemReq req) if (!isValid(resp));
                UncachedMemResp newResp = UncachedMemResp{write: req.write, data: 0};
                Bit#(16) addr = truncate(req.addr - baseaddr);
                if (addr < 16'h1000) begin
                    // RTC registers
                    if (((addr & 16'h0007) == 0) && (req.size == D)) begin
                        let index = addr >> 3;
                        if (index <= fromInteger(valueof(cores))) begin
                            if (index == 0) begin
                                if (req.write) begin
                                    newTimeEhr[0] <= tagged Valid req.data;
                                end else begin
                                    newResp.data = timer;
                                end
                            end else begin
                                if (req.write) begin
                                    timeCmp[index] <= req.data;
                                end else begin
                                    newResp.data = timeCmp[index];
                                end
                            end
                        end else begin
                            $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                        end
                    end else begin
                        $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                    end
                end else begin
                    // IPI registers
                    if ((addr & 16'h0FFF) == 0) begin
                        let index = addr >> 12;
                        if (index < fromInteger(valueof(cores))) begin
                            if (req.write) begin
                                ipiReg[index] <= unpack(req.data[0]);
                            end else begin
                                newResp.data = zeroExtend(pack(ipiReg[index]));
                            end
                        end else begin
                            $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                        end
                    end else begin
                        $fdisplay(stderr, "[ERROR] MemoryMappedCSRs: unexpected mem request: ", fshow(req));
                    end
                end
                resp <= tagged Valid newResp;
            endmethod
        endinterface
        interface Get response;
            method ActionValue#(UncachedMemResp) get if (resp matches tagged Valid .validResp);
                resp <= tagged Invalid;
                return validResp;
            endmethod
        endinterface
    endinterface
    method Data timerValue = timer;
    method Vector#(cores, Bool) timerInterrupt = zipWith( \>= , replicate(timer), readVReg(timeCmp));
    method Vector#(cores, Bool) ipi = readVReg(ipiReg);
endmodule


bugfix: missing declaring dataInSecondTlp

typo fix: quar -> quad

// 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 Vector       :: *;
import GetPut       :: *;
import Connectable  :: *;
import MIMO         :: *;
import PCIE         :: *;
import DefaultValue :: *;
import ClientServer :: *;
import MemTypes     :: *;

//
// Top interface: PCIe transaction level packets (TLPs)
// Bottom interface: MemMaster that sends read/write requests to an MemSlave
// Also sources interrupt MSIX requests
interface MemMasterEngine;
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemMaster#(32,32) master;
endinterface

`ifdef XILINX
   `define AXI
`elsif BSIM
   `define AXI
`elsif ALTERA
   `define AVALON
`elsif VSIM
   `define AVALON
`endif

(* synthesize *)
module mkMemMasterEngine#(PciId my_id)(MemMasterEngine);
    Reg#(Bit#(7)) hitReg <- mkReg(0);
    FIFOF#(TLPMemoryIO3DWHeader) readHeaderFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPMemoryIO3DWHeader) readDataFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPMemoryIO3DWHeader) writeHeaderFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPMemoryIO3DWHeader) writeDataFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPData#(16)) tlpOutFifo <- mkSizedFIFOF(8);
    Reg#(TLPTag) tlpTag <- mkReg(0);

    MIMOConfiguration mimoCfg = defaultValue;
    MIMO#(1,4,4,Bit#(32)) completionMimo <- mkMIMO(mimoCfg);
   Reg#(TLPLength)             readBurstCount <- mkReg(0);
   Reg#(LUInt#(4))     completionMimoDeqCount <- mkReg(0);
   Reg#(Bool)      readBurstCountGreaterThan4 <- mkReg(False);
   Reg#(Bool)                  readInProgress <- mkReg(False);
   Reg#(Bit#(7))               address <- mkReg(0);

   function Bool isQuadWordAligned(Bit#(7) lower_addr);
      return (lower_addr[2:0]==3'b0);
   endfunction

   rule completionHeader if (!readInProgress && readDataFifo.notEmpty() && completionMimo.deqReadyN(1));
      let hdr = readDataFifo.first;
      TLPLength rbc = hdr.length;

      Vector#(4, Bit#(32)) dvec = unpack(0);
`ifdef AXI
      dvec = completionMimo.first();
      completionMimo.deq(1);
`elsif AVALON
      let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr.addr, hdr.firstbe));
      // if quad-word aligned, insert bubble.
      if (!quadWordAligned) begin
         dvec = completionMimo.first();
         completionMimo.deq(1);
      end
`endif
      //$display("completionHeader length=%d rbc=%d addr=%x", hdr.length, rbc, hdr.addr);
      TLPCompletionHeader completion = defaultValue;
      completion.format = MEM_WRITE_3DW_DATA;
      completion.pkttype = COMPLETION;
      completion.relaxed = hdr.relaxed;
      completion.nosnoop = hdr.nosnoop;
      completion.length = hdr.length;
      completion.tclass = hdr.tclass;
      completion.cmplid = my_id;
      completion.tag = truncate(hdr.tag);
      completion.bytecount = 4;
      completion.reqid = hdr.reqid;
      completion.loweraddr = getLowerAddr(hdr.addr, hdr.firstbe);
`ifdef AXI
      completion.data = byteSwap(dvec[0]);
`elsif AVALON
      if (!quadWordAligned) begin
         completion.data = (dvec[0]);
      end
      else begin
         completion.data = unpack(0);
      end
`endif
      TLPData#(16) tlp = defaultValue;
      tlp.data = pack(completion);
      tlp.sof = True;

`ifdef AXI
      tlp.eof = (rbc == 1) ? True : False;
`elsif AVALON
      tlp.eof = (rbc == 1 && !quadWordAligned) ? True : False;
`endif
      tlp.be = 16'hFFFF;
      tlp.hit = hitReg;
      tlpOutFifo.enq(tlp);

`ifdef AXI
      rbc = rbc - 1;
`elsif AVALON
      if (!quadWordAligned) begin
         rbc = rbc - 1;
      end
`endif
      readBurstCount <= rbc;
      completionMimoDeqCount <= truncate(min(4,unpack(rbc)));
      readInProgress <= (rbc != 0);
      readBurstCountGreaterThan4 <= (rbc > 4);
      if (rbc == 0) begin
	 readDataFifo.deq;
      end
   endrule

    function Bit#(16) tlpBe(TLPLength len);
       if (len == 0)
	  return 0;
       else if (len == 1)
	  return 16'hf000;
       else if (len == 2)
	  return 16'hff00;
       else if (len == 3)
	  return 16'hfff0;
       else
	  return 16'hffff;
    endfunction

   rule continuation if (readInProgress && completionMimo.deqReadyN(completionMimoDeqCount));
      let rbc = readBurstCount;
      TLPData#(16) tlp = defaultValue;
      Vector#(4, Bit#(32)) dvec = unpack(0);
      tlp.sof = False;
      dvec = completionMimo.first();
      completionMimo.deq(completionMimoDeqCount);

      if (readBurstCountGreaterThan4) begin
	 rbc = rbc - 4;
	 tlp.be = tlpBe(4);
	 tlp.eof = False;
      end
      else begin
	 tlp.be = tlpBe(rbc);
	 //$display("tlp.data=%h tlp.be=%h", tlp.data, tlp.be);
	 tlp.eof = True;
	 rbc = 0;
      end

      readBurstCount <= rbc;
      completionMimoDeqCount <= truncate(min(4,unpack(rbc)));
      readBurstCountGreaterThan4 <= (rbc > 4);
      if (!readBurstCountGreaterThan4) begin
	 readDataFifo.deq();
	 readInProgress <= False;
      end
      for (Integer i = 0; i < 4; i = i + 1)
`ifdef AXI
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(dvec[3-i]);
`elsif AVALON
	 tlp.data[(i+1)*32-1:i*32] = (dvec[3-i]);
         tlp.hit = hitReg;
`endif
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
    interface Put response;
        method Action put(TLPData#(16) tlp);
	    //$display("MemMasterEngine.put tlp=%h", tlp);
	    TLPMemoryIO3DWHeader h = unpack(tlp.data);
	    hitReg <= tlp.hit;
	    TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
`ifdef AVALON
            // For Altera, the position of payload in a 3DW TLP depends on alignment.
            let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
`endif
	    if (tlp.sof && hdr_3dw.format == MEM_READ_3DW_NO_DATA) begin
	       if (readHeaderFifo.notFull())
	          readHeaderFifo.enq(hdr_3dw);
	       else begin
		  // FIXME: should generate a response or host will lock up
	       end
	    end
	    else begin
               //FIXME: should rewrite to allow burst write.
               if (tlp.sof && writeHeaderFifo.notFull())
		  writeHeaderFifo.enq(hdr_3dw);
	    end
	endmethod
    endinterface
    interface Get request = toGet(tlpOutFifo);
    endinterface: tlp
    interface PhysMemMaster master;
    interface PhysMemWriteClient write_client;
        interface Get    writeReq;
	  method ActionValue#(PhysMemRequest#(32)) get();
	     let hdr = writeHeaderFifo.first;
	     writeHeaderFifo.deq;
	     writeDataFifo.enq(hdr);
	     let burstLen = truncate(hdr.length << 2);
	     return PhysMemRequest { addr: extend(writeHeaderFifo.first.addr) << 2, burstLen: burstLen, tag: truncate(writeHeaderFifo.first.tag)};
	  endmethod
       endinterface
        interface Get writeData;
	  method ActionValue#(MemData#(32)) get();
	     let hdr <- toGet(writeDataFifo).get();
`ifdef AXI
	     let data = byteSwap(hdr.data);
`elsif AVALON
	     let data = hdr.data;
`endif
	     return MemData { data: data, tag: truncate(hdr.tag), last: True};
	  endmethod
       endinterface
        interface Put       writeDone;
	  method Action put(Bit#(MemTagSize) resp);
	  endmethod
       endinterface
     endinterface
    interface PhysMemReadClient read_client;
        interface Get    readReq;
	  method ActionValue#(PhysMemRequest#(32)) get();
	     let hdr = readHeaderFifo.first;
	     readHeaderFifo.deq;
	     //$display("req_ar hdr.length=%d hdr.addr=%h", hdr.length, hdr.addr);
	     readDataFifo.enq(hdr);
	     let burstLen = truncate(hdr.length << 2);
	     return PhysMemRequest { addr: extend(readHeaderFifo.first.addr) << 2, burstLen: burstLen, tag: truncate(readHeaderFifo.first.tag)};
	    endmethod
       endinterface
        interface Put readData;
	  method Action put(MemData#(32) resp) if (completionMimo.enqReadyN(1));
	     Vector#(1, Bit#(32)) vec = cons(resp.data, nil);
	     completionMimo.enq(1, vec);
	  endmethod
	endinterface
    endinterface
    endinterface: master
endmodule: mkMemMasterEngine

interface MemInterrupt;
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface Put#(Tuple2#(Bit#(64),Bit#(32))) interruptRequest;
    interface Get#(Tuple2#(Bit#(64),Bit#(32))) interruptTrace;
endinterface

typedef struct {
   Bit#(64) addr;
   Bit#(32) data;
   Bool     mswIsZero;
   Bool     lswIsZero;
   } InterruptRequest deriving (Bits);

(* synthesize *)
module mkMemInterrupt#(PciId my_id)(MemInterrupt);
    FIFOF#(InterruptRequest) interruptRequestFifo <- mkFIFOF();
    FIFOF#(InterruptRequest) interruptTraceFifo <- mkSizedFIFOF(4);
    Reg#(Maybe#(Bit#(32))) interruptSecondHalf <- mkReg(tagged Invalid);
    Reg#(TLPTag) tlpTag <- mkReg(0);
    FIFOF#(TLPData#(16)) tlpOutFifo <- mkSizedFIFOF(8);

    function Bool isQuadWordAligned(Bit#(7) lower_addr);
       return (lower_addr[2:0]==3'b0);
    endfunction

    rule interruptTlpOut if (interruptRequestFifo.notEmpty &&& interruptSecondHalf matches tagged Invalid);
       TLPData#(16) tlp = defaultValue;
       tlp.sof = True;
       tlp.eof = False;
       tlp.hit = 7'h00;
       tlp.be = 16'hffff;

       let deqInterruptRequestFifo = False;
       let sendInterrupt = False;

       let interruptRequest = interruptRequestFifo.first;
       let interruptAddr = interruptRequest.addr;
       let interruptData = interruptRequest.data;
       let mswIsZero = interruptRequest.mswIsZero;
       let lswIsZero = interruptRequest.lswIsZero;

`ifdef AXI
       let dataInSecondTlp = False;
`elsif AVALON
       let quadWordAligned = isQuadWordAligned(truncate(interruptAddr));
       let dataInSecondTlp = quadWordAligned;
`endif

       if (mswIsZero && lswIsZero) begin
	  // do not write to 0 -- it wedges the host
	  deqInterruptRequestFifo = True;
       end
       else if (mswIsZero) begin
          TLPMemoryIO3DWHeader hdr_3dw = defaultValue();
          hdr_3dw.format = MEM_WRITE_3DW_DATA;
	  //hdr_3dw.pkttype = MEM_READ_WRITE;
          hdr_3dw.tag = tlpTag;
          hdr_3dw.reqid = my_id;
          hdr_3dw.length = 1;
          hdr_3dw.firstbe = '1;
          hdr_3dw.lastbe = '0;
          hdr_3dw.addr = interruptAddr[31:2];
`ifdef AXI
	  hdr_3dw.data = byteSwap(interruptData);
`elsif AVALON
	  hdr_3dw.data = interruptData;
`endif

	  tlp.data = pack(hdr_3dw);
          if (dataInSecondTlp) begin
	     tlp.eof = False;
             interruptSecondHalf <= tagged Valid interruptData;
          end
	  else begin
	     tlp.eof = True;
	     deqInterruptRequestFifo = True;
	  end
	  sendInterrupt = True;
       end
       else begin
	  TLPMemory4DWHeader hdr_4dw = defaultValue;
	  hdr_4dw.format = MEM_WRITE_4DW_DATA;
	  //hdr_4dw.pkttype = MEM_READ_WRITE;
	  hdr_4dw.tag = tlpTag;
	  hdr_4dw.reqid = my_id;
	  hdr_4dw.nosnoop = SNOOPING_REQD;
	  hdr_4dw.addr = interruptAddr[40-1:2];
	  hdr_4dw.length = 1;
	  hdr_4dw.firstbe = 4'hf;
	  hdr_4dw.lastbe = 0;
	  tlp.data = pack(hdr_4dw);

	  sendInterrupt = True;
	  interruptSecondHalf <= tagged Valid interruptData;
       end

       if (deqInterruptRequestFifo) begin
	  interruptRequestFifo.deq();
       end
       if (sendInterrupt)
	  tlpOutFifo.enq(tlp);
    endrule

    rule interruptTlpDataOut if (interruptSecondHalf matches tagged Valid .interruptData);
       TLPData#(16) tlp = defaultValue;
       tlp.sof = False;
       tlp.eof = True;
       tlp.hit = 7'h00;
       tlp.be = 16'hf000;
`ifdef AXI
       tlp.data[7+8*15:8*12] = byteSwap(interruptData);
`elsif AVALON
       tlp.data[7+8*15:8*12] = interruptData;
`endif
       tlpOutFifo.enq(tlp);
       interruptSecondHalf <= tagged Invalid;
       interruptRequestFifo.deq();
    endrule

    interface Client        tlp;
    interface Put response;
        method Action put(TLPData#(16) tlp);
	endmethod
    endinterface
    interface Get request = toGet(tlpOutFifo);
    endinterface: tlp
    interface Put interruptRequest;
       method Action put(Tuple2#(Bit#(64),Bit#(32)) intr);
	  match { .addr, .data } = intr;
	  Bool mswIsZero = (addr[63:32] == 0);
	  Bool lswIsZero = (addr[31:0] == 0);
	  let interruptRequest = InterruptRequest { addr: addr, data: data, mswIsZero: mswIsZero, lswIsZero: lswIsZero };
          interruptRequestFifo.enq(interruptRequest);
	  if (interruptTraceFifo.notFull())
	      interruptTraceFifo.enq(interruptRequest);
       endmethod
    endinterface
    interface Get interruptTrace;
       method ActionValue#(Tuple2#(Bit#(64),Bit#(32))) get();
           let req = interruptTraceFifo.first();
           interruptTraceFifo.deq();
	   return tuple2(req.addr, req.data);
       endmethod
    endinterface
endmodule: mkMemInterrupt

// 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 Vector       :: *;
import GetPut       :: *;
import Connectable  :: *;
import MIMO         :: *;
import PCIE         :: *;
import DefaultValue :: *;
import ClientServer :: *;
import MemTypes     :: *;

//
// Top interface: PCIe transaction level packets (TLPs)
// Bottom interface: MemMaster that sends read/write requests to an MemSlave
// Also sources interrupt MSIX requests
interface MemMasterEngine;
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemMaster#(32,32) master;
endinterface

`ifdef XILINX
   `define AXI
`elsif BSIM
   `define AXI
`elsif ALTERA
   `define AVALON
`elsif VSIM
   `define AVALON
`endif

(* synthesize *)
module mkMemMasterEngine#(PciId my_id)(MemMasterEngine);
    Reg#(Bit#(7)) hitReg <- mkReg(0);
    FIFOF#(TLPMemoryIO3DWHeader) readHeaderFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPMemoryIO3DWHeader) readDataFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPMemoryIO3DWHeader) writeHeaderFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPMemoryIO3DWHeader) writeDataFifo <- mkSizedFIFOF(8);
    FIFOF#(TLPData#(16)) tlpOutFifo <- mkSizedFIFOF(8);
    Reg#(TLPTag) tlpTag <- mkReg(0);

    MIMOConfiguration mimoCfg = defaultValue;
    MIMO#(1,4,4,Bit#(32)) completionMimo <- mkMIMO(mimoCfg);
   Reg#(TLPLength)             readBurstCount <- mkReg(0);
   Reg#(LUInt#(4))     completionMimoDeqCount <- mkReg(0);
   Reg#(Bool)      readBurstCountGreaterThan4 <- mkReg(False);
   Reg#(Bool)                  readInProgress <- mkReg(False);
   Reg#(Bit#(7))               address <- mkReg(0);

   function Bool isQuarWordAligned(Bit#(7) lower_addr);
      return (lower_addr[2:0]==3'b0);
   endfunction

   rule completionHeader if (!readInProgress && readDataFifo.notEmpty() && completionMimo.deqReadyN(1));
      let hdr = readDataFifo.first;
      TLPLength rbc = hdr.length;

      Vector#(4, Bit#(32)) dvec = unpack(0);
`ifdef AXI
      dvec = completionMimo.first();
      completionMimo.deq(1);
`elsif AVALON
      let quadWordAligned = isQuarWordAligned(getLowerAddr(hdr.addr, hdr.firstbe));
      // if quad-word aligned, insert bubble.
      if (!quadWordAligned) begin
         dvec = completionMimo.first();
         completionMimo.deq(1);
      end
`endif
      //$display("completionHeader length=%d rbc=%d addr=%x", hdr.length, rbc, hdr.addr);
      TLPCompletionHeader completion = defaultValue;
      completion.format = MEM_WRITE_3DW_DATA;
      completion.pkttype = COMPLETION;
      completion.relaxed = hdr.relaxed;
      completion.nosnoop = hdr.nosnoop;
      completion.length = hdr.length;
      completion.tclass = hdr.tclass;
      completion.cmplid = my_id;
      completion.tag = truncate(hdr.tag);
      completion.bytecount = 4;
      completion.reqid = hdr.reqid;
      completion.loweraddr = getLowerAddr(hdr.addr, hdr.firstbe);
`ifdef AXI
      completion.data = byteSwap(dvec[0]);
`elsif AVALON
      if (!quadWordAligned) begin
         completion.data = (dvec[0]);
      end
      else begin
         completion.data = unpack(0);
      end
`endif
      TLPData#(16) tlp = defaultValue;
      tlp.data = pack(completion);
      tlp.sof = True;

`ifdef AXI
      tlp.eof = (rbc == 1) ? True : False;
`elsif AVALON
      tlp.eof = (rbc == 1 && !quadWordAligned) ? True : False;
`endif
      tlp.be = 16'hFFFF;
      tlp.hit = hitReg;
      tlpOutFifo.enq(tlp);

`ifdef AXI
      rbc = rbc - 1;
`elsif AVALON
      if (!quadWordAligned) begin
         rbc = rbc - 1;
      end
`endif
      readBurstCount <= rbc;
      completionMimoDeqCount <= truncate(min(4,unpack(rbc)));
      readInProgress <= (rbc != 0);
      readBurstCountGreaterThan4 <= (rbc > 4);
      if (rbc == 0) begin
	 readDataFifo.deq;
      end
   endrule

    function Bit#(16) tlpBe(TLPLength len);
       if (len == 0)
	  return 0;
       else if (len == 1)
	  return 16'hf000;
       else if (len == 2)
	  return 16'hff00;
       else if (len == 3)
	  return 16'hfff0;
       else
	  return 16'hffff;
    endfunction

   rule continuation if (readInProgress && completionMimo.deqReadyN(completionMimoDeqCount));
      let rbc = readBurstCount;
      TLPData#(16) tlp = defaultValue;
      Vector#(4, Bit#(32)) dvec = unpack(0);
      tlp.sof = False;
      dvec = completionMimo.first();
      completionMimo.deq(completionMimoDeqCount);

      if (readBurstCountGreaterThan4) begin
	 rbc = rbc - 4;
	 tlp.be = tlpBe(4);
	 tlp.eof = False;
      end
      else begin
	 tlp.be = tlpBe(rbc);
	 //$display("tlp.data=%h tlp.be=%h", tlp.data, tlp.be);
	 tlp.eof = True;
	 rbc = 0;
      end

      readBurstCount <= rbc;
      completionMimoDeqCount <= truncate(min(4,unpack(rbc)));
      readBurstCountGreaterThan4 <= (rbc > 4);
      if (!readBurstCountGreaterThan4) begin
	 readDataFifo.deq();
	 readInProgress <= False;
      end
      for (Integer i = 0; i < 4; i = i + 1)
`ifdef AXI
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(dvec[3-i]);
`elsif AVALON
	 tlp.data[(i+1)*32-1:i*32] = (dvec[3-i]);
         tlp.hit = hitReg;
`endif
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
    interface Put response;
        method Action put(TLPData#(16) tlp);
	    //$display("MemMasterEngine.put tlp=%h", tlp);
	    TLPMemoryIO3DWHeader h = unpack(tlp.data);
	    hitReg <= tlp.hit;
	    TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
`ifdef AVALON
            // For Altera, the position of payload in a 3DW TLP depends on alignment.
            let quadWordAligned = isQuarWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
`endif
	    if (tlp.sof && hdr_3dw.format == MEM_READ_3DW_NO_DATA) begin
	       if (readHeaderFifo.notFull())
	          readHeaderFifo.enq(hdr_3dw);
	       else begin
		  // FIXME: should generate a response or host will lock up
	       end
	    end
	    else begin
               //FIXME: should rewrite to allow burst write.
               if (tlp.sof && writeHeaderFifo.notFull())
		  writeHeaderFifo.enq(hdr_3dw);
	    end
	endmethod
    endinterface
    interface Get request = toGet(tlpOutFifo);
    endinterface: tlp
    interface PhysMemMaster master;
    interface PhysMemWriteClient write_client;
        interface Get    writeReq;
	  method ActionValue#(PhysMemRequest#(32)) get();
	     let hdr = writeHeaderFifo.first;
	     writeHeaderFifo.deq;
	     writeDataFifo.enq(hdr);
	     let burstLen = truncate(hdr.length << 2);
	     return PhysMemRequest { addr: extend(writeHeaderFifo.first.addr) << 2, burstLen: burstLen, tag: truncate(writeHeaderFifo.first.tag)};
	  endmethod
       endinterface
        interface Get writeData;
	  method ActionValue#(MemData#(32)) get();
	     let hdr <- toGet(writeDataFifo).get();
`ifdef AXI
	     let data = byteSwap(hdr.data);
`elsif AVALON
	     let data = hdr.data;
`endif
	     return MemData { data: data, tag: truncate(hdr.tag), last: True};
	  endmethod
       endinterface
        interface Put       writeDone;
	  method Action put(Bit#(MemTagSize) resp);
	  endmethod
       endinterface
     endinterface
    interface PhysMemReadClient read_client;
        interface Get    readReq;
	  method ActionValue#(PhysMemRequest#(32)) get();
	     let hdr = readHeaderFifo.first;
	     readHeaderFifo.deq;
	     //$display("req_ar hdr.length=%d hdr.addr=%h", hdr.length, hdr.addr);
	     readDataFifo.enq(hdr);
	     let burstLen = truncate(hdr.length << 2);
	     return PhysMemRequest { addr: extend(readHeaderFifo.first.addr) << 2, burstLen: burstLen, tag: truncate(readHeaderFifo.first.tag)};
	    endmethod
       endinterface
        interface Put readData;
	  method Action put(MemData#(32) resp) if (completionMimo.enqReadyN(1));
	     Vector#(1, Bit#(32)) vec = cons(resp.data, nil);
	     completionMimo.enq(1, vec);
	  endmethod
	endinterface
    endinterface
    endinterface: master
endmodule: mkMemMasterEngine

interface MemInterrupt;
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface Put#(Tuple2#(Bit#(64),Bit#(32))) interruptRequest;
    interface Get#(Tuple2#(Bit#(64),Bit#(32))) interruptTrace;
endinterface

typedef struct {
   Bit#(64) addr;
   Bit#(32) data;
   Bool     mswIsZero;
   Bool     lswIsZero;
   } InterruptRequest deriving (Bits);

(* synthesize *)
module mkMemInterrupt#(PciId my_id)(MemInterrupt);
    FIFOF#(InterruptRequest) interruptRequestFifo <- mkFIFOF();
    FIFOF#(InterruptRequest) interruptTraceFifo <- mkSizedFIFOF(4);
    Reg#(Maybe#(Bit#(32))) interruptSecondHalf <- mkReg(tagged Invalid);
    Reg#(TLPTag) tlpTag <- mkReg(0);
    FIFOF#(TLPData#(16)) tlpOutFifo <- mkSizedFIFOF(8);

    function Bool isQuarWordAligned(Bit#(7) lower_addr);
       return (lower_addr[2:0]==3'b0);
    endfunction

    rule interruptTlpOut if (interruptRequestFifo.notEmpty &&& interruptSecondHalf matches tagged Invalid);
       TLPData#(16) tlp = defaultValue;
       tlp.sof = True;
       tlp.eof = False;
       tlp.hit = 7'h00;
       tlp.be = 16'hffff;

       let deqInterruptRequestFifo = False;
       let sendInterrupt = False;

       let interruptRequest = interruptRequestFifo.first;
       let interruptAddr = interruptRequest.addr;
       let interruptData = interruptRequest.data;
       let mswIsZero = interruptRequest.mswIsZero;
       let lswIsZero = interruptRequest.lswIsZero;

`ifdef AXI
       let dataInSecondTlp = False;
`elsif AVALON
       let dataInSecondTlp = isQuarWordAligned(truncate(interruptAddr));
`endif

       if (mswIsZero && lswIsZero) begin
	  // do not write to 0 -- it wedges the host
	  deqInterruptRequestFifo = True;
       end
       else if (mswIsZero) begin
          TLPMemoryIO3DWHeader hdr_3dw = defaultValue();
          hdr_3dw.format = MEM_WRITE_3DW_DATA;
	  //hdr_3dw.pkttype = MEM_READ_WRITE;
          hdr_3dw.tag = tlpTag;
          hdr_3dw.reqid = my_id;
          hdr_3dw.length = 1;
          hdr_3dw.firstbe = '1;
          hdr_3dw.lastbe = '0;
          hdr_3dw.addr = interruptAddr[31:2];
`ifdef AXI
	  hdr_3dw.data = byteSwap(interruptData);
`elsif AVALON
	  hdr_3dw.data = interruptData;
`endif

	  tlp.data = pack(hdr_3dw);
          if (dataInSecondTlp) begin
	     tlp.eof = False;
             interruptSecondHalf <= tagged Valid interruptData;
          end
	  else begin
	     tlp.eof = True;
	     deqInterruptRequestFifo = True;
	  end
	  sendInterrupt = True;
       end
       else begin
	  TLPMemory4DWHeader hdr_4dw = defaultValue;
	  hdr_4dw.format = MEM_WRITE_4DW_DATA;
	  //hdr_4dw.pkttype = MEM_READ_WRITE;
	  hdr_4dw.tag = tlpTag;
	  hdr_4dw.reqid = my_id;
	  hdr_4dw.nosnoop = SNOOPING_REQD;
	  hdr_4dw.addr = interruptAddr[40-1:2];
	  hdr_4dw.length = 1;
	  hdr_4dw.firstbe = 4'hf;
	  hdr_4dw.lastbe = 0;
	  tlp.data = pack(hdr_4dw);

	  sendInterrupt = True;
	  interruptSecondHalf <= tagged Valid interruptData;
       end

       if (deqInterruptRequestFifo) begin
	  interruptRequestFifo.deq();
       end
       if (sendInterrupt)
	  tlpOutFifo.enq(tlp);
    endrule

    rule interruptTlpDataOut if (interruptSecondHalf matches tagged Valid .interruptData);
       TLPData#(16) tlp = defaultValue;
       tlp.sof = False;
       tlp.eof = True;
       tlp.hit = 7'h00;
       tlp.be = 16'hf000;
`ifdef AXI
       tlp.data[7+8*15:8*12] = byteSwap(interruptData);
`elsif AVALON
       tlp.data[7+8*15:8*12] = interruptData;
`endif
       tlpOutFifo.enq(tlp);
       interruptSecondHalf <= tagged Invalid;
       interruptRequestFifo.deq();
    endrule

    interface Client        tlp;
    interface Put response;
        method Action put(TLPData#(16) tlp);
	endmethod
    endinterface
    interface Get request = toGet(tlpOutFifo);
    endinterface: tlp
    interface Put interruptRequest;
       method Action put(Tuple2#(Bit#(64),Bit#(32)) intr);
	  match { .addr, .data } = intr;
	  Bool mswIsZero = (addr[63:32] == 0);
	  Bool lswIsZero = (addr[31:0] == 0);
	  let interruptRequest = InterruptRequest { addr: addr, data: data, mswIsZero: mswIsZero, lswIsZero: lswIsZero };
          interruptRequestFifo.enq(interruptRequest);
	  if (interruptTraceFifo.notFull())
	      interruptTraceFifo.enq(interruptRequest);
       endmethod
    endinterface
    interface Get interruptTrace;
       method ActionValue#(Tuple2#(Bit#(64),Bit#(32))) get();
           let req = interruptTraceFifo.first();
           interruptTraceFifo.deq();
	   return tuple2(req.addr, req.data);
       endmethod
    endinterface
endmodule: mkMemInterrupt


Minor tweaks to PLIC_16_2_7.bsv

Minor tweaks to PLIC_16_2_7.bsv


mutex on readEngine.data between header and data reads

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

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

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

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

typedef enum {
   Idle,
   HeadRequested,
   TailRequested,
   RequestMessage,
   MessageHeaderRequested,
   MessageRequested,
   Drain,
   UpdateTail,
   UpdateHead,
   UpdateHead2,
   Waiting,
   SendHeader,
   SendMessage,
   SendPadding,
   Stop
   } SharedMemoryPortalState deriving (Bits,Eq);

module mkSharedMemoryRequestPortal#(PipePortal#(numRequests, numIndications, 32) portal,
    MemreadServer#(64) readEngine, MemwriteServer#(64) writeEngine)(SharedMemoryPortal#(64));
   // read the head and tail pointers, if they are different, then read a request
   Reg#(Bit#(32)) limitReg <- mkReg(0);
   Reg#(Bit#(32)) headReg <- mkReg(0);
   Reg#(Bit#(32)) tailReg <- mkReg(0);
   Reg#(Bit#(16)) countReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   MIFO#(4,1,4,Bit#(32)) readMifo <- mkMIFO();

   let verbose = False;

   rule updateReqHeadTail if (state == Idle && readyReg);
      readEngine.request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= HeadRequested;
   endrule

   rule receiveReqHeadTail if (state == HeadRequested || state == TailRequested);
      let v <- toGet(readEngine.data).get();
      let w0 = v.data[31:0];
      let w1 = v.data[63:32];
      let head = headReg;
      let tail = tailReg;
      if (state == HeadRequested) begin
         limitReg <= w0;
         headReg <= w1;
         head = w1;
         state <= TailRequested;
      end
      else begin
         if (tailReg == 0) begin
            tail = w0;
            tailReg <= tail;
         end
         if (tail != headReg)
            state <= RequestMessage;
         else
            state <= Idle;
      end
      if (verbose)
         $display("receiveReqHeadTail state=%d w0=%x w1=%x head=%d tail=%d limit=%d", state, w0, w1, head, tail, limitReg);
   endrule

   rule requestMessage if (state == RequestMessage);
      Bit#(32) wordCount = headReg - tailReg;
      if ((tailReg & 1) == 1) begin
         $display("WARNING requestMessage: reqTail=%d is odd.", tailReg);
      end
      let tail = tailReg + wordCount;
      if (headReg < tailReg) begin
         $display("requestMessage wrapped: head=%d tail=%d", headReg, tailReg);
         wordCount = limitReg - tailReg;
         tail = 4;
      end
      if (verbose) $display("requestMessage id=%d tail=%h head=%h wordCount=%d", sglIdReg, tailReg, headReg, wordCount);
      tailReg <= tail;
      countReg <= truncate(wordCount);
      readEngine.request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(tailReg << 2), burstLen: 16, len: wordCount << 2, tag: 0});
      state <= MessageHeaderRequested;
   endrule

   rule demuxwords if (state != HeadRequested && state != TailRequested && readMifo.enqReady());
      let v <- toGet(readEngine.data).get();
      Vector#(2,Bit#(32)) dvec = unpack(v.data);
      let enqCount = 2;
      Vector#(4,Bit#(32)) dvec4;
      dvec4[0] = dvec[0];
      dvec4[1] = dvec[1];
      dvec4[2] = 0;
      dvec4[3] = 0;
      readMifo.enq(enqCount, dvec4);
   endrule

   rule receiveMessageHeader if (state == MessageHeaderRequested);
      let vec <- toGet(readMifo).get();
      let hdr = vec[0];
      let methodId = hdr[31:16];
      let messageWords = hdr[15:0];
      methodIdReg <= methodId;
      if (verbose)
         $display("receiveMessageHeader hdr=%x methodId=%x messageWords=%d wordCount=%d", hdr, methodId, messageWords, countReg);
      countReg <= countReg - 1;
      messageWordsReg <= messageWords - 1;
      if (hdr == 0) begin
         if (countReg == 1)
            state <= UpdateTail;
         else
            state <= Drain;
      end
      else if (countReg == 1)
         state <= UpdateTail;
      else if (messageWords == 1)
         state <= MessageHeaderRequested;
      else
         state <= MessageRequested;
   endrule

   rule drain if (state == Drain);
      let vec <- toGet(readMifo).get();
      if (countReg == 1)
         state <= UpdateTail;
      countReg <= countReg - 1;
   endrule

   rule receiveMessage if (state == MessageRequested);
      let vec <- toGet(readMifo).get();
      let data = vec[0];
      if (verbose)
         $display("receiveMessage data=%x messageWords=%d wordCount=%d", data, messageWordsReg, countReg);
      if (methodIdReg != 16'hFFFF)
         portal.requests[methodIdReg].enq(data);
      messageWordsReg <= messageWordsReg - 1;
      countReg <= countReg - 1;
      if (messageWordsReg == 1)
         state <= MessageHeaderRequested;
      else if (countReg <= 1)
         state <= UpdateTail;
   endrule

   rule updateTail if (state == UpdateTail);
      if (verbose)
         $display("updateTail: tail=%d", tailReg);
      // update the tail pointer
      writeEngine.request.put(
          MemengineCmd {sglId: sglIdReg, base: 8, len: 8, burstLen: 8, tag: 0});
      writeEngine.data.enq(extend(tailReg));
      state <= Waiting;
   endrule

   rule waiting if (state == Waiting);
      let done <- writeEngine.done.get();
      state <= Idle;
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
endmodule

module mkSharedMemoryIndicationPortal#(PipePortal#(numRequests, numIndications, 32) portal,
    MemreadServer#(64) readEngine, MemwriteServer#(64) writeEngine)(SharedMemoryPortal#(64));
   let defaultClock <- exposeCurrentClock;
   let defaultReset <- exposeCurrentReset;
   // read the head and tail pointers, if they are different, then read a request
   Reg#(Bit#(16)) limitReg <- mkReg(0);
   Reg#(Bit#(16)) headReg <- mkReg(0);
   Reg#(Bit#(16)) tailReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(Bool) paddingReg <- mkReg(False);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, portal.indications);
   Bool      interruptStatus = False;
   Bit#(16)  readyChannel = -1;
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Gearbox#(1,2,Bit#(32)) gb <- mk1toNGearbox(defaultClock, defaultReset, defaultClock, defaultReset);

   let verbose = True;

   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule updateIndHeadTail if (state == Idle && readyReg);
      readEngine.request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= HeadRequested;
   endrule

   rule receiveIndHeadTail if (state == HeadRequested || state == TailRequested);
      let md <- toGet(readEngine.data).get();
      let data = md.data;
      let w0 = data[31:0];
      let w1 = data[63:32];
      let head = headReg;
      let tail = tailReg;
      if (state == HeadRequested) begin
         limitReg <= truncate(w0);
         headReg <= truncate(w1);
         head = truncate(w1);
         state <= TailRequested;
      end
      else begin
         if (tailReg == 0) begin
            tail = truncate(w0);
            tailReg <= tail;
         end
         //if (tail != headReg)
            state <= SendHeader;
         //else
            //state <= Idle;
      end
      if (verbose)
         $display("receiveIndHeadTail state=%d w0=%x w1=%x head=%d tail=%d limit=%d", state, w0, w1, head, tail, limitReg);
   endrule

   rule send64bits;
      let v = gb.first;
      gb.deq();
      writeEngine.data.enq(pack(v));
   endrule

   rule sendHeader if (state == SendHeader && interruptStatus);
      Bit#(16) messageBits = portal.messageSize.size(readyChannel);
      Bit#(16) roundup = messageBits[4:0] == 0 ? 0 : 1;
      Bit#(16) numWords = (messageBits >> 5) + roundup;
      Bit#(16) totalWords = numWords + 1;
      Bit#(32) hdr = extend(readyChannel) << 16 | extend(numWords + 1);
      if (numWords[0] == 0)
         totalWords = numWords + 2;
      paddingReg <= numWords[0] == 0;
      $display("sendHeader hdr=%h messageBits=%d numWords=%d totalWords=%d paddingReg=%d headReg=%h", hdr, messageBits, numWords, totalWords, paddingReg, headReg);
      headReg <= headReg + totalWords;
      messageWordsReg <= numWords;
      methodIdReg <= readyChannel;
      gb.enq(replicate(hdr));
      writeEngine.request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(headReg) << 2, burstLen: 8, len: extend(totalWords) << 2, tag: 0});
      state <= SendMessage;
   endrule

   rule sendMessage if (state == SendMessage);
      messageWordsReg <= messageWordsReg - 1;
      let v = portal.indications[methodIdReg].first;
      portal.indications[methodIdReg].deq();
      gb.enq(replicate(v));
      $display("sendMessage v=%h messageWords=%d", v, messageWordsReg);
      if (messageWordsReg == 1) begin
         if (paddingReg)
            state <= SendPadding;
         else
            state <= UpdateHead;
      end
   endrule

   rule sendPadding if (state == SendPadding);
      $display("sendPadding");
      gb.enq(replicate(32'hffff0001));
      state <= UpdateHead;
   endrule

   rule updateHead if (state == UpdateHead);
      $display("updateIndHead limit=%d head=%d", limitReg, headReg);
      gb.enq(replicate(extend(limitReg)));
      writeEngine.request.put(
             MemengineCmd {sglId: sglIdReg, base: 0 << 2, burstLen: 8, len: 2 << 2, tag: 0});
      state <= UpdateHead2;
   endrule

   rule updateHead2 if (state == UpdateHead2);
      $display("updateIndHead2");
      gb.enq(replicate(extend(headReg)));
      state <= SendHeader;
   endrule

   rule done;
      let done <- writeEngine.done.get();
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
endmodule

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

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

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

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

typedef enum {
   Idle,
   HeadRequested,
   TailRequested,
   RequestMessage,
   MessageHeaderRequested,
   MessageRequested,
   Drain,
   UpdateTail,
   UpdateHead,
   UpdateHead2,
   Waiting,
   SendHeader,
   SendMessage,
   SendPadding,
   Stop
   } SharedMemoryPortalState deriving (Bits,Eq);

module mkSharedMemoryRequestPortal#(PipePortal#(numRequests, numIndications, 32) portal,
    MemreadServer#(64) readEngine, MemwriteServer#(64) writeEngine)(SharedMemoryPortal#(64));
   // read the head and tail pointers, if they are different, then read a request
   Reg#(Bit#(32)) limitReg <- mkReg(0);
   Reg#(Bit#(32)) headReg <- mkReg(0);
   Reg#(Bit#(32)) tailReg <- mkReg(0);
   Reg#(Bit#(16)) countReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   MIFO#(4,1,4,Bit#(32)) readMifo <- mkMIFO();

   let verbose = False;

   rule updateReqHeadTail if (state == Idle && readyReg);
      readEngine.request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= HeadRequested;
   endrule

   rule receiveReqHeadTail if (state == HeadRequested || state == TailRequested);
      let v <- toGet(readEngine.data).get();
      let w0 = v.data[31:0];
      let w1 = v.data[63:32];
      let head = headReg;
      let tail = tailReg;
      if (state == HeadRequested) begin
         limitReg <= w0;
         headReg <= w1;
         head = w1;
         state <= TailRequested;
      end
      else begin
         if (tailReg == 0) begin
            tail = w0;
            tailReg <= tail;
         end
         if (tail != headReg)
            state <= RequestMessage;
         else
            state <= Idle;
      end
      if (verbose)
         $display("receiveReqHeadTail state=%d w0=%x w1=%x head=%d tail=%d limit=%d", state, w0, w1, head, tail, limitReg);
   endrule

   rule requestMessage if (state == RequestMessage);
      Bit#(32) wordCount = headReg - tailReg;
      if ((tailReg & 1) == 1) begin
         $display("WARNING requestMessage: reqTail=%d is odd.", tailReg);
      end
      let tail = tailReg + wordCount;
      if (headReg < tailReg) begin
         $display("requestMessage wrapped: head=%d tail=%d", headReg, tailReg);
         wordCount = limitReg - tailReg;
         tail = 4;
      end
      if (verbose) $display("requestMessage id=%d tail=%h head=%h wordCount=%d", sglIdReg, tailReg, headReg, wordCount);
      tailReg <= tail;
      countReg <= truncate(wordCount);
      readEngine.request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(tailReg << 2), burstLen: 16, len: wordCount << 2, tag: 0});
      state <= MessageHeaderRequested;
   endrule

   rule demuxwords if (readMifo.enqReady());
      let v <- toGet(readEngine.data).get();
      Vector#(2,Bit#(32)) dvec = unpack(v.data);
      let enqCount = 2;
      Vector#(4,Bit#(32)) dvec4;
      dvec4[0] = dvec[0];
      dvec4[1] = dvec[1];
      dvec4[2] = 0;
      dvec4[3] = 0;
      readMifo.enq(enqCount, dvec4);
   endrule

   rule receiveMessageHeader if (state == MessageHeaderRequested);
      let vec <- toGet(readMifo).get();
      let hdr = vec[0];
      let methodId = hdr[31:16];
      let messageWords = hdr[15:0];
      methodIdReg <= methodId;
      if (verbose)
         $display("receiveMessageHeader hdr=%x methodId=%x messageWords=%d wordCount=%d", hdr, methodId, messageWords, countReg);
      countReg <= countReg - 1;
      messageWordsReg <= messageWords - 1;
      if (hdr == 0) begin
         if (countReg == 1)
            state <= UpdateTail;
         else
            state <= Drain;
      end
      else if (countReg == 1)
         state <= UpdateTail;
      else if (messageWords == 1)
         state <= MessageHeaderRequested;
      else
         state <= MessageRequested;
   endrule

   rule drain if (state == Drain);
      let vec <- toGet(readMifo).get();
      if (countReg == 1)
         state <= UpdateTail;
      countReg <= countReg - 1;
   endrule

   rule receiveMessage if (state == MessageRequested);
      let vec <- toGet(readMifo).get();
      let data = vec[0];
      if (verbose)
         $display("receiveMessage data=%x messageWords=%d wordCount=%d", data, messageWordsReg, countReg);
      if (methodIdReg != 16'hFFFF)
         portal.requests[methodIdReg].enq(data);
      messageWordsReg <= messageWordsReg - 1;
      countReg <= countReg - 1;
      if (messageWordsReg == 1)
         state <= MessageHeaderRequested;
      else if (countReg <= 1)
         state <= UpdateTail;
   endrule

   rule updateTail if (state == UpdateTail);
      if (verbose)
         $display("updateTail: tail=%d", tailReg);
      // update the tail pointer
      writeEngine.request.put(
          MemengineCmd {sglId: sglIdReg, base: 8, len: 8, burstLen: 8, tag: 0});
      writeEngine.data.enq(extend(tailReg));
      state <= Waiting;
   endrule

   rule waiting if (state == Waiting);
      let done <- writeEngine.done.get();
      state <= Idle;
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
endmodule

module mkSharedMemoryIndicationPortal#(PipePortal#(numRequests, numIndications, 32) portal,
    MemreadServer#(64) readEngine, MemwriteServer#(64) writeEngine)(SharedMemoryPortal#(64));
   let defaultClock <- exposeCurrentClock;
   let defaultReset <- exposeCurrentReset;
   // read the head and tail pointers, if they are different, then read a request
   Reg#(Bit#(16)) limitReg <- mkReg(0);
   Reg#(Bit#(16)) headReg <- mkReg(0);
   Reg#(Bit#(16)) tailReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(Bool) paddingReg <- mkReg(False);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, portal.indications);
   Bool      interruptStatus = False;
   Bit#(16)  readyChannel = -1;
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Gearbox#(1,2,Bit#(32)) gb <- mk1toNGearbox(defaultClock, defaultReset, defaultClock, defaultReset);

   let verbose = True;

   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule updateIndHeadTail if (state == Idle && readyReg);
      readEngine.request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= HeadRequested;
   endrule

   rule receiveIndHeadTail if (state == HeadRequested || state == TailRequested);
      let md <- toGet(readEngine.data).get();
      let data = md.data;
      let w0 = data[31:0];
      let w1 = data[63:32];
      let head = headReg;
      let tail = tailReg;
      if (state == HeadRequested) begin
         limitReg <= truncate(w0);
         headReg <= truncate(w1);
         head = truncate(w1);
         state <= TailRequested;
      end
      else begin
         if (tailReg == 0) begin
            tail = truncate(w0);
            tailReg <= tail;
         end
         //if (tail != headReg)
            state <= SendHeader;
         //else
            //state <= Idle;
      end
      if (verbose)
         $display("receiveIndHeadTail state=%d w0=%x w1=%x head=%d tail=%d limit=%d", state, w0, w1, head, tail, limitReg);
   endrule

   rule send64bits;
      let v = gb.first;
      gb.deq();
      writeEngine.data.enq(pack(v));
   endrule

   rule sendHeader if (state == SendHeader && interruptStatus);
      Bit#(16) messageBits = portal.messageSize.size(readyChannel);
      Bit#(16) roundup = messageBits[4:0] == 0 ? 0 : 1;
      Bit#(16) numWords = (messageBits >> 5) + roundup;
      Bit#(16) totalWords = numWords + 1;
      Bit#(32) hdr = extend(readyChannel) << 16 | extend(numWords + 1);
      if (numWords[0] == 0)
         totalWords = numWords + 2;
      paddingReg <= numWords[0] == 0;
      $display("sendHeader hdr=%h messageBits=%d numWords=%d totalWords=%d paddingReg=%d headReg=%h", hdr, messageBits, numWords, totalWords, paddingReg, headReg);
      headReg <= headReg + totalWords;
      messageWordsReg <= numWords;
      methodIdReg <= readyChannel;
      gb.enq(replicate(hdr));
      writeEngine.request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(headReg) << 2, burstLen: 8, len: extend(totalWords) << 2, tag: 0});
      state <= SendMessage;
   endrule

   rule sendMessage if (state == SendMessage);
      messageWordsReg <= messageWordsReg - 1;
      let v = portal.indications[methodIdReg].first;
      portal.indications[methodIdReg].deq();
      gb.enq(replicate(v));
      $display("sendMessage v=%h messageWords=%d", v, messageWordsReg);
      if (messageWordsReg == 1) begin
         if (paddingReg)
            state <= SendPadding;
         else
            state <= UpdateHead;
      end
   endrule

   rule sendPadding if (state == SendPadding);
      $display("sendPadding");
      gb.enq(replicate(32'hffff0001));
      state <= UpdateHead;
   endrule

   rule updateHead if (state == UpdateHead);
      $display("updateIndHead limit=%d head=%d", limitReg, headReg);
      gb.enq(replicate(extend(limitReg)));
      writeEngine.request.put(
             MemengineCmd {sglId: sglIdReg, base: 0 << 2, burstLen: 8, len: 2 << 2, tag: 0});
      state <= UpdateHead2;
   endrule

   rule updateHead2 if (state == UpdateHead2);
      $display("updateIndHead2");
      gb.enq(replicate(extend(headReg)));
      state <= SendHeader;
   endrule

   rule done;
      let done <- writeEngine.done.get();
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
endmodule


added filterPhase, copied along with the filter coefficients. This signal, when 1, means that the filter cycle is starting, so zero the accumulator

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

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

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

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

import Complex::*;
import FixedPoint::*;
import Pipe::*;

typedef FixedPoint#(2,16) Signal;
typedef FixedPoint#(2,23) Coeff;
typedef FixedPoint#(4,39) Product;

typedef struct {
		Complex#(Coeff) a;
		Bit#(1) filterPhase;
		} CoeffData;

typedef struct {
		Complex#(Product) y;
		Bit#(1) filterPhase;
		} ProductData;

interface FPCMult;
   interface PipeIn#(Complex#(Signal)) x;
   interface PipeIn#(CoeffData) a;
   interface PipeOut#(ProductData) y;
endinterface

module mkFPCMult(FPCMult);
   /* input registers */
   Reg#(Complex#(Signal)) xin <- mkReg(?);
   Reg#(CoeffData) ain <- mkReg(?);
   /* pipeline registers at output of multipliers */
   Reg#(Product) arxr <- mkReg(?);
   Reg#(Product) aixi <- mkReg(?);
   Reg#(Product) arxi <- mkReg(?);
   Reg#(Product) aixr <- mkReg(?);
   Reg#(Bit#(1)) multstage <- mkReg(?);
   /* result registers */
   Reg#(ProductData) yout <- mkReg(?);

   rule work;
      /* compute multiplies */
      arxr <= fxptMult(ain.a.r, xin.r);
      aixi <= fxptMult(ain.a.i, xin.i);
      arxi <= fxptMult(ain.a.r, xin.i);
      aixr <= fxptMult(ain.a.i, xin.r);
      multFilterPhase <= ain.filterPhase;
      /* combine into outputs */
      yout <= ProductData{y: Complex{r: arxr - aixi, i: arxi + aixr}, filterPhase: multstage};
   endrule

   interface PipeOut y = toPipeOut(yout);
   interface PipeIn x;
      method Action enq(Complex#(Signal) v);
         xin <= v;
      endmethod
      method Bool notFull();
         return (True);
      endmethod
   endinterface
   interface PipeIn a;
      method Action enq(CoeffData v);
         ain <= v;
      endmethod
      method Bool notFull();
         return (True);
      endmethod
   endinterface

endmodule;

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

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

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

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

import Complex::*;
import FixedPoint::*;
import Pipe::*;

typedef FixedPoint#(2,16) Signal;
typedef FixedPoint#(2,23) Coeff;
typedef FixedPoint#(4,39) Product;

interface FPCMult;
   interface PipeIn#(Complex#(Signal)) x;
   interface PipeIn#(Complex#(Coeff)) a;
   interface PipeOut#(Complex#(Product)) y;
endinterface

module mkFPCMult(FPCMult);
   /* input registers */
   Reg#(Complex#(Signal)) xin <- mkReg(?);
   Reg#(Complex#(Coeff)) ain <- mkReg(?);
   /* pipeline registers at output of multipliers */
   Reg#(Product) arxr <- mkReg(?);
   Reg#(Product) aixi <- mkReg(?);
   Reg#(Product) arxi <- mkReg(?);
   Reg#(Product) aixr <- mkReg(?);
   /* result registers */
   Reg#(Complex#(Product)) yout <- mkReg(?);

   rule work;
      /* compute multiplies */
      arxr <= fxptMult(ain.r, xin.r);
      aixi <= fxptMult(ain.i, xin.i);
      arxi <= fxptMult(ain.r, xin.i);
      aixr <= fxptMult(ain.i, xin.r);
      /* combine into outputs */
      yout <= Complex{r: arxr - aixi, i: arxi + aixr};
   endrule

   interface PipeOut y = toPipeOut(yout);
   interface PipeIn x;
      method Action enq(Complex#(Signal) v);
         xin <= v;
      endmethod
      method Bool notFull();
         return (True);
      endmethod
   endinterface
   interface PipeIn a;
      method Action enq(Complex#(Coeff) v);
         ain <= v;
      endmethod
      method Bool notFull();
         return (True);
      endmethod
   endinterface

endmodule;