change msix_base in PcieCsr to match the value used in connectal-synth-pcie.tcl

// 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 BRAM           :: *;
import FIFOF          :: *;
import BRAMFIFO       :: *;
import GetPut         :: *;
import Connectable    :: *;
import PCIE           :: *;
import Clocks         :: *;
import PcieTracer     :: *;
import ConnectalMemTypes       :: *;
import AddressGenerator::*;
import Pipe           :: *;

`include "ConnectalProjectConfig.bsv"

`define msix_base 128

// An MSIX table entry, as defined in the PCIe spec
interface MSIX_Entry;
   interface Reg#(Bit#(32)) addr_lo;
   interface Reg#(Bit#(32)) addr_hi;
   interface Reg#(Bit#(32)) msg_data;
   interface Reg#(Bool)     masked;
endinterface

interface ReadOnly_MSIX_Entry;
   interface ReadOnly#(Bit#(32)) addr_lo;
   interface ReadOnly#(Bit#(32)) addr_hi;
   interface ReadOnly#(Bit#(32)) msg_data;
   interface ReadOnly#(Bool)     masked;
endinterface

function ReadOnly_MSIX_Entry toReadOnlyMsixEntry(MSIX_Entry msix);
   return (interface ReadOnly_MSIX_Entry;
	   interface ReadOnly addr_lo = regToReadOnly(msix.addr_lo);
	   interface ReadOnly addr_hi = regToReadOnly(msix.addr_hi);
	   interface ReadOnly msg_data = regToReadOnly(msix.msg_data);
	   interface ReadOnly masked = regToReadOnly(msix.masked);
	   endinterface);
endfunction

// control and status registers accessed from PCIe
interface PcieControlAndStatusRegs;
   interface PhysMemSlave#(32,32) memSlave;
   interface Vector#(16,ReadOnly_MSIX_Entry) msixEntry;
   interface PipeIn#(Bit#(64)) changes;
   interface TlpTraceClient traceClient;
endinterface: PcieControlAndStatusRegs

// This module encapsulates all of the logic for instantiating and
// accessing the control and status registers. It defines the
// registers, the address map, and how the registers respond to reads
// and writes.
(* synthesize *)
module mkPcieControlAndStatusRegs(PcieControlAndStatusRegs);

   // Utility for module creating all of the storage for a single MSIX
   // table entry
   module mkMSIXEntry(MSIX_Entry);
      Reg#(Bit#(32)) _addr_lo  <- mkReg(0);
      Reg#(Bit#(32)) _addr_hi  <- mkReg(0);
      Reg#(Bit#(32)) _msg_data <- mkReg(0);
      Reg#(Bool)     _masked   <- mkReg(True);

      interface addr_lo  = _addr_lo;
      interface addr_hi  = _addr_hi;
      interface msg_data = _msg_data;
      interface masked   = _masked;
   endmodule: mkMSIXEntry

   // Registers and their default values
   Vector#(16,MSIX_Entry) msix_entry              <- replicateM(mkMSIXEntry);
   Reg#(TimestampedTlpData) pcieTraceBramResponse <- mkReg(unpack(0));

   // Function to return a one-word slice of the tlpTraceBramResponse
   function Bit#(32) tlpTraceBramResponseSlice(Reg#(TimestampedTlpData) data, Integer i);
       Bit#(8) i8 = fromInteger(i);
       begin
           Bit#(TMul#(12,32)) v = extend(pack(data));
           return v[31 + (i8*32) : 0 + (i8*32)];
       end
   endfunction

   FIFOF#(BRAMRequest#(Bit#(TAdd#(TlpTraceAddrSize,1)),TimestampedTlpData)) bramRequestFifo <- mkFIFOF();
   FIFOF#(TimestampedTlpData)                                               bramResponseFifo <- mkFIFOF();
   Reg#(Bool)                   tlpTracingReg                <- mkReg(True);
   Reg#(Bit#(TlpTraceAddrSize)) tlpTraceLimitReg             <- mkReg(0);
   Reg#(Bit#(TlpTraceAddrSize)) tlpTraceBramWrAddrReg        <- mkReg(0);
   FIFOF#(Bit#(64))             changeFifo                   <- mkSizedBRAMFIFOF(256);

   // State used to actually service read and write requests
   rule brmMuxResponse;
       let v <- toGet(bramResponseFifo).get();
       pcieTraceBramResponse <= v;
   endrule

   AddressGenerator#(16,32)           csrRag <- mkAddressGenerator;
   AddressGenerator#(16,32)           csrWag <- mkAddressGenerator;
   FIFOF#(MemData#(32))     readResponseFifo <- mkFIFOF();
   FIFOF#(MemData#(32))        writeDataFifo <- mkFIFOF();
   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();

   FIFOF#(AddrBeat#(16)) csrRagBeatFifo <- mkFIFOF();
   FIFOF#(Bool)       csrIsMsixAddrFifo <- mkFIFOF();
   FIFOF#(Bit#(2))     csrOneHotFifo000 <- mkFIFOF();
   FIFOF#(Bit#(29))    csrOneHotFifo774 <- mkFIFOF();
   FIFOF#(Bit#(2))     csrOneHotFifo992 <- mkFIFOF();

   FIFOF#(AddrBeat#(16)) csrWagBeatFifo <- mkFIFOF();
   FIFOF#(Bool)       csrWagIsMsixAddrFifo <- mkFIFOF();
   FIFOF#(Bit#(8))     csrWagOneHotFifo768 <- mkFIFOF();
   FIFOF#(Bit#(3))     csrWagOneHotFifo792 <- mkFIFOF();

   rule readDataRule;
      let beat <- csrRag.addrBeat.get();
      let addr = beat.addr >> 2; // word address
      Bit#(32) data = 0;
      let modaddr = (addr % 8192);
      let msixaddr = modaddr - `msix_base;

      csrRagBeatFifo.enq(beat);
      csrIsMsixAddrFifo.enq(msixaddr >= 0 && msixaddr <= 63);
      Bit#(1024) onehot = (1 << addr[9:0]);
      csrOneHotFifo000.enq(onehot[1:0]);
      csrOneHotFifo774.enq(onehot[802:774]);
      csrOneHotFifo992.enq(onehot[993:992]);
   endrule
   rule readDataRule2;
      let beat       <- toGet(csrRagBeatFifo).get();
      let isMsixAddr <- toGet(csrIsMsixAddrFifo).get();
      let addr = beat.addr >> 2; // word address
      Bit#(32) data = 32'hbad0add0;
      let modaddr = (addr % 8192);
      let msix_base = `msix_base;
      let msixaddr = modaddr - msix_base;
      let oneHotDecode000 <- toGet(csrOneHotFifo000).get();
      let oneHotDecode774 <- toGet(csrOneHotFifo774).get();
      let oneHotDecode992 <- toGet(csrOneHotFifo992).get();

      if (isMsixAddr) begin
         begin
            let groupaddr = (msixaddr / 4);
            //******************************** msix_base has to match CONFIG.MXIx_Table_Offset in scripts/connectal-synth-pcie.tcl
            case (msixaddr % 4)
               0: data = msix_entry[groupaddr].addr_lo;
               1: data = msix_entry[groupaddr].addr_hi;
               2: data = msix_entry[groupaddr].msg_data;
               3: data = {'0, pack(msix_entry[groupaddr].masked)}; // vector control
               default: data = 32'hbad0add0;
	  //******************************** end of MSIX Table
            endcase
         end
      end
      else begin
	  // board identification
	  if (oneHotDecode000[0] == 1) data = 32'h65756c42; // Blue
	  if (oneHotDecode000[1] == 1) data = 32'h63657073; // spec

	  if (oneHotDecode774[774-774] == 1) data = fromInteger(2**valueOf(TAdd#(TlpTraceAddrSize,1)));
	  if (oneHotDecode774[775-774] == 1) data = (tlpTracingReg ? 1 : 0);
	  if (oneHotDecode774[776-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 0);
	  if (oneHotDecode774[777-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 1);
	  if (oneHotDecode774[778-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 2);
	  if (oneHotDecode774[779-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 3);
	  if (oneHotDecode774[780-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 4);
	  if (oneHotDecode774[781-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 5);
	  if (oneHotDecode774[792-774] == 1) data = extend(tlpTraceBramWrAddrReg);
	  if (oneHotDecode774[794-774] == 1) data = extend(tlpTraceLimitReg);
	  if (oneHotDecode774[795-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 6);
	  if (oneHotDecode774[796-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 7);
	  if (oneHotDecode774[797-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 8);
	  if (oneHotDecode774[798-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 9);
	  if (oneHotDecode774[799-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 10);
	  if (oneHotDecode774[800-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 11);
   	  if (oneHotDecode774[801-774] == 1) data = (changeFifo.notEmpty()) ? (changeFifo.first()[31:0]) : 0;
   	  if (oneHotDecode774[802-774] == 1) data = (changeFifo.notEmpty()) ? (changeFifo.first()[63:32]) : 0;

         //******************************** msix_base has to match CONFIG.MXIx_PBA_Offset in scripts/connectal-synth-pcie.tcl
	  // 4-bit MSIx pending bit field
	  if (oneHotDecode992[992-992] == 1) data = '0;                               // PBA structure (low)
	  if (oneHotDecode992[993-992] == 1) data = '0;                               // PBA structure (high)
	  //******************************** end of PBA Table
      end
      if (oneHotDecode774[802-774] == 1 && changeFifo.notEmpty())
	 changeFifo.deq();
      readResponseFifo.enq(MemData { data: data, tag: beat.tag, last: beat.last });
   endrule

   rule writeDataRule;
      let beat <- csrWag.addrBeat.get();
      let addr = beat.addr >> 2; // word address

      let modaddr = (addr % 8192);
      let msixaddr = modaddr - `msix_base;

      csrWagBeatFifo.enq(beat);
      csrWagIsMsixAddrFifo.enq(msixaddr >= 0 && msixaddr <= 63);
      Bit#(1024) onehot = (1 << addr[9:0]);
      $display("addr: %h", addr);
      csrWagOneHotFifo768.enq(onehot[775:768]);
      csrWagOneHotFifo792.enq(onehot[794:792]);
   endrule

   rule writeDataRule2;
      let memData <- toGet(writeDataFifo).get();
      let dword = memData.data;

      $display("data: %h, last: %h, tag: %h", dword, memData.last, memData.tag);
      let beat       <- toGet(csrWagBeatFifo).get();
      let isMsixAddr <- toGet(csrWagIsMsixAddrFifo).get();
      let addr = beat.addr >> 2; // word address
      let modaddr = (addr % 8192);
      let msix_base = `msix_base;
      let msixaddr = modaddr - msix_base;
      let oneHotDecode768 <- toGet(csrWagOneHotFifo768).get();
      let oneHotDecode792 <- toGet(csrWagOneHotFifo792).get();

      if (isMsixAddr)
         begin
            let groupaddr = (msixaddr / 4);
            //******************************** area referenced from xilinx_x7_pcie_wrapper.v
            case (msixaddr % 4)
               0: msix_entry[groupaddr].addr_lo  <= (dword & 32'hfffffffc);
               1: msix_entry[groupaddr].addr_hi  <= dword;
               2: msix_entry[groupaddr].msg_data <= dword;
               3: msix_entry[groupaddr].masked <= unpack(dword[0]);
            endcase
         end
      else begin
	 if (oneHotDecode768[775-768] == 1) tlpTracingReg <= (dword != 0) ? True : False;
	 if (oneHotDecode768[768-768] == 1)
	     bramRequestFifo.enq(BRAMRequest{ write: False, responseOnWrite: False, address: truncate(dword), datain: ?});
	 if (oneHotDecode792[792-792] == 1) tlpTraceBramWrAddrReg <= truncate(dword);
	 if (oneHotDecode792[794-792] == 1) tlpTraceLimitReg <= truncate(dword);
      end
      if (beat.last)
	 writeDoneFifo.enq(beat.tag);
   endrule

   interface PhysMemSlave memSlave;
      interface PhysMemReadServer read_server;
	 interface Put readReq;
	    method Action put(PhysMemRequest#(32,32) req);
	       csrRag.request.put(PhysMemRequest { addr: truncate(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						  , firstbe: req.firstbe, lastbe: req.lastbe
`endif
						  });
	    endmethod
	 endinterface
	 interface Get readData = toGet(readResponseFifo);
   endinterface: read_server

  interface PhysMemWriteServer write_server;
	 interface Put writeReq;
	    method Action put(PhysMemRequest#(32,32) req);
               $display("csrWag Request, addr=%h, burstLen=%h, tag=%h", req.addr, req.burstLen, req.tag);
	       csrWag.request.put(PhysMemRequest { addr: truncate(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						  , firstbe: req.firstbe, lastbe: req.lastbe
`endif
						  });
	    endmethod
	 endinterface
     interface Put writeData = toPut(writeDataFifo);
     interface Get writeDone = toGet(writeDoneFifo);
   endinterface: write_server
   endinterface
   interface changes = toPipeIn(changeFifo);
   interface TlpTraceClient traceClient;
      interface Reg tlpTracing = tlpTracingReg;
      interface Reg tlpTraceLimit = tlpTraceLimitReg;
      interface Reg tlpTraceBramWrAddr = tlpTraceBramWrAddrReg;
      interface BRAMClient bramClient;
         interface Get request = toGet(bramRequestFifo);
	 interface Put response = toPut(bramResponseFifo);
      endinterface: bramClient
   endinterface: traceClient
   interface Vector msixEntry = map(toReadOnlyMsixEntry, msix_entry);
endmodule: mkPcieControlAndStatusRegs

// 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 BRAM           :: *;
import FIFOF          :: *;
import BRAMFIFO       :: *;
import GetPut         :: *;
import Connectable    :: *;
import PCIE           :: *;
import Clocks         :: *;
import PcieTracer     :: *;
import ConnectalMemTypes       :: *;
import AddressGenerator::*;
import Pipe           :: *;

`include "ConnectalProjectConfig.bsv"

`define msix_base 1024

// An MSIX table entry, as defined in the PCIe spec
interface MSIX_Entry;
   interface Reg#(Bit#(32)) addr_lo;
   interface Reg#(Bit#(32)) addr_hi;
   interface Reg#(Bit#(32)) msg_data;
   interface Reg#(Bool)     masked;
endinterface

interface ReadOnly_MSIX_Entry;
   interface ReadOnly#(Bit#(32)) addr_lo;
   interface ReadOnly#(Bit#(32)) addr_hi;
   interface ReadOnly#(Bit#(32)) msg_data;
   interface ReadOnly#(Bool)     masked;
endinterface

function ReadOnly_MSIX_Entry toReadOnlyMsixEntry(MSIX_Entry msix);
   return (interface ReadOnly_MSIX_Entry;
	   interface ReadOnly addr_lo = regToReadOnly(msix.addr_lo);
	   interface ReadOnly addr_hi = regToReadOnly(msix.addr_hi);
	   interface ReadOnly msg_data = regToReadOnly(msix.msg_data);
	   interface ReadOnly masked = regToReadOnly(msix.masked);
	   endinterface);
endfunction

// control and status registers accessed from PCIe
interface PcieControlAndStatusRegs;
   interface PhysMemSlave#(32,32) memSlave;
   interface Vector#(16,ReadOnly_MSIX_Entry) msixEntry;
   interface PipeIn#(Bit#(64)) changes;
   interface TlpTraceClient traceClient;
endinterface: PcieControlAndStatusRegs

// This module encapsulates all of the logic for instantiating and
// accessing the control and status registers. It defines the
// registers, the address map, and how the registers respond to reads
// and writes.
(* synthesize *)
module mkPcieControlAndStatusRegs(PcieControlAndStatusRegs);

   // Utility for module creating all of the storage for a single MSIX
   // table entry
   module mkMSIXEntry(MSIX_Entry);
      Reg#(Bit#(32)) _addr_lo  <- mkReg(0);
      Reg#(Bit#(32)) _addr_hi  <- mkReg(0);
      Reg#(Bit#(32)) _msg_data <- mkReg(0);
      Reg#(Bool)     _masked   <- mkReg(True);

      interface addr_lo  = _addr_lo;
      interface addr_hi  = _addr_hi;
      interface msg_data = _msg_data;
      interface masked   = _masked;
   endmodule: mkMSIXEntry

   // Registers and their default values
   Vector#(16,MSIX_Entry) msix_entry              <- replicateM(mkMSIXEntry);
   Reg#(TimestampedTlpData) pcieTraceBramResponse <- mkReg(unpack(0));

   // Function to return a one-word slice of the tlpTraceBramResponse
   function Bit#(32) tlpTraceBramResponseSlice(Reg#(TimestampedTlpData) data, Integer i);
       Bit#(8) i8 = fromInteger(i);
       begin
           Bit#(TMul#(12,32)) v = extend(pack(data));
           return v[31 + (i8*32) : 0 + (i8*32)];
       end
   endfunction

   FIFOF#(BRAMRequest#(Bit#(TAdd#(TlpTraceAddrSize,1)),TimestampedTlpData)) bramRequestFifo <- mkFIFOF();
   FIFOF#(TimestampedTlpData)                                               bramResponseFifo <- mkFIFOF();
   Reg#(Bool)                   tlpTracingReg                <- mkReg(True);
   Reg#(Bit#(TlpTraceAddrSize)) tlpTraceLimitReg             <- mkReg(0);
   Reg#(Bit#(TlpTraceAddrSize)) tlpTraceBramWrAddrReg        <- mkReg(0);
   FIFOF#(Bit#(64))             changeFifo                   <- mkSizedBRAMFIFOF(256);

   // State used to actually service read and write requests
   rule brmMuxResponse;
       let v <- toGet(bramResponseFifo).get();
       pcieTraceBramResponse <= v;
   endrule

   AddressGenerator#(16,32)           csrRag <- mkAddressGenerator;
   AddressGenerator#(16,32)           csrWag <- mkAddressGenerator;
   FIFOF#(MemData#(32))     readResponseFifo <- mkFIFOF();
   FIFOF#(MemData#(32))        writeDataFifo <- mkFIFOF();
   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();

   FIFOF#(AddrBeat#(16)) csrRagBeatFifo <- mkFIFOF();
   FIFOF#(Bool)       csrIsMsixAddrFifo <- mkFIFOF();
   FIFOF#(Bit#(2))     csrOneHotFifo000 <- mkFIFOF();
   FIFOF#(Bit#(29))    csrOneHotFifo774 <- mkFIFOF();
   FIFOF#(Bit#(2))     csrOneHotFifo992 <- mkFIFOF();

   FIFOF#(AddrBeat#(16)) csrWagBeatFifo <- mkFIFOF();
   FIFOF#(Bool)       csrWagIsMsixAddrFifo <- mkFIFOF();
   FIFOF#(Bit#(8))     csrWagOneHotFifo768 <- mkFIFOF();
   FIFOF#(Bit#(3))     csrWagOneHotFifo792 <- mkFIFOF();

   rule readDataRule;
      let beat <- csrRag.addrBeat.get();
      let addr = beat.addr >> 2; // word address
      Bit#(32) data = 0;
      let modaddr = (addr % 8192);
      let msixaddr = modaddr - `msix_base;

      csrRagBeatFifo.enq(beat);
      csrIsMsixAddrFifo.enq(msixaddr >= 0 && msixaddr <= 63);
      Bit#(1024) onehot = (1 << addr[9:0]);
      csrOneHotFifo000.enq(onehot[1:0]);
      csrOneHotFifo774.enq(onehot[802:774]);
      csrOneHotFifo992.enq(onehot[993:992]);
   endrule
   rule readDataRule2;
      let beat       <- toGet(csrRagBeatFifo).get();
      let isMsixAddr <- toGet(csrIsMsixAddrFifo).get();
      let addr = beat.addr >> 2; // word address
      Bit#(32) data = 32'hbad0add0;
      let modaddr = (addr % 8192);
      let msix_base = `msix_base;
      let msixaddr = modaddr - msix_base;
      let oneHotDecode000 <- toGet(csrOneHotFifo000).get();
      let oneHotDecode774 <- toGet(csrOneHotFifo774).get();
      let oneHotDecode992 <- toGet(csrOneHotFifo992).get();

      if (isMsixAddr) begin
         begin
            let groupaddr = (msixaddr / 4);
            //******************************** msix_base has to match CONFIG.MXIx_Table_Offset in scripts/connectal-synth-pcie.tcl
            case (msixaddr % 4)
               0: data = msix_entry[groupaddr].addr_lo;
               1: data = msix_entry[groupaddr].addr_hi;
               2: data = msix_entry[groupaddr].msg_data;
               3: data = {'0, pack(msix_entry[groupaddr].masked)}; // vector control
               default: data = 32'hbad0add0;
	  //******************************** end of MSIX Table
            endcase
         end
      end
      else begin
	  // board identification
	  if (oneHotDecode000[0] == 1) data = 32'h65756c42; // Blue
	  if (oneHotDecode000[1] == 1) data = 32'h63657073; // spec

	  if (oneHotDecode774[774-774] == 1) data = fromInteger(2**valueOf(TAdd#(TlpTraceAddrSize,1)));
	  if (oneHotDecode774[775-774] == 1) data = (tlpTracingReg ? 1 : 0);
	  if (oneHotDecode774[776-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 0);
	  if (oneHotDecode774[777-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 1);
	  if (oneHotDecode774[778-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 2);
	  if (oneHotDecode774[779-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 3);
	  if (oneHotDecode774[780-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 4);
	  if (oneHotDecode774[781-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 5);
	  if (oneHotDecode774[792-774] == 1) data = extend(tlpTraceBramWrAddrReg);
	  if (oneHotDecode774[794-774] == 1) data = extend(tlpTraceLimitReg);
	  if (oneHotDecode774[795-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 6);
	  if (oneHotDecode774[796-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 7);
	  if (oneHotDecode774[797-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 8);
	  if (oneHotDecode774[798-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 9);
	  if (oneHotDecode774[799-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 10);
	  if (oneHotDecode774[800-774] == 1) data = tlpTraceBramResponseSlice(pcieTraceBramResponse, 11);
   	  if (oneHotDecode774[801-774] == 1) data = (changeFifo.notEmpty()) ? (changeFifo.first()[31:0]) : 0;
   	  if (oneHotDecode774[802-774] == 1) data = (changeFifo.notEmpty()) ? (changeFifo.first()[63:32]) : 0;

         //******************************** msix_base has to match CONFIG.MXIx_PBA_Offset in scripts/connectal-synth-pcie.tcl
	  // 4-bit MSIx pending bit field
	  if (oneHotDecode992[992-992] == 1) data = '0;                               // PBA structure (low)
	  if (oneHotDecode992[993-992] == 1) data = '0;                               // PBA structure (high)
	  //******************************** end of PBA Table
      end
      if (oneHotDecode774[802-774] == 1 && changeFifo.notEmpty())
	 changeFifo.deq();
      readResponseFifo.enq(MemData { data: data, tag: beat.tag, last: beat.last });
   endrule

   rule writeDataRule;
      let beat <- csrWag.addrBeat.get();
      let addr = beat.addr >> 2; // word address

      let modaddr = (addr % 8192);
      let msixaddr = modaddr - `msix_base;

      csrWagBeatFifo.enq(beat);
      csrWagIsMsixAddrFifo.enq(msixaddr >= 0 && msixaddr <= 63);
      Bit#(1024) onehot = (1 << addr[9:0]);
      $display("addr: %h", addr);
      csrWagOneHotFifo768.enq(onehot[775:768]);
      csrWagOneHotFifo792.enq(onehot[794:792]);
   endrule

   rule writeDataRule2;
      let memData <- toGet(writeDataFifo).get();
      let dword = memData.data;

      $display("data: %h, last: %h, tag: %h", dword, memData.last, memData.tag);
      let beat       <- toGet(csrWagBeatFifo).get();
      let isMsixAddr <- toGet(csrWagIsMsixAddrFifo).get();
      let addr = beat.addr >> 2; // word address
      let modaddr = (addr % 8192);
      let msix_base = `msix_base;
      let msixaddr = modaddr - msix_base;
      let oneHotDecode768 <- toGet(csrWagOneHotFifo768).get();
      let oneHotDecode792 <- toGet(csrWagOneHotFifo792).get();

      if (isMsixAddr)
         begin
            let groupaddr = (msixaddr / 4);
            //******************************** area referenced from xilinx_x7_pcie_wrapper.v
            case (msixaddr % 4)
               0: msix_entry[groupaddr].addr_lo  <= (dword & 32'hfffffffc);
               1: msix_entry[groupaddr].addr_hi  <= dword;
               2: msix_entry[groupaddr].msg_data <= dword;
               3: msix_entry[groupaddr].masked <= unpack(dword[0]);
            endcase
         end
      else begin
	 if (oneHotDecode768[775-768] == 1) tlpTracingReg <= (dword != 0) ? True : False;
	 if (oneHotDecode768[768-768] == 1)
	     bramRequestFifo.enq(BRAMRequest{ write: False, responseOnWrite: False, address: truncate(dword), datain: ?});
	 if (oneHotDecode792[792-792] == 1) tlpTraceBramWrAddrReg <= truncate(dword);
	 if (oneHotDecode792[794-792] == 1) tlpTraceLimitReg <= truncate(dword);
      end
      if (beat.last)
	 writeDoneFifo.enq(beat.tag);
   endrule

   interface PhysMemSlave memSlave;
      interface PhysMemReadServer read_server;
	 interface Put readReq;
	    method Action put(PhysMemRequest#(32,32) req);
	       csrRag.request.put(PhysMemRequest { addr: truncate(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						  , firstbe: req.firstbe, lastbe: req.lastbe
`endif
						  });
	    endmethod
	 endinterface
	 interface Get readData = toGet(readResponseFifo);
   endinterface: read_server

  interface PhysMemWriteServer write_server;
	 interface Put writeReq;
	    method Action put(PhysMemRequest#(32,32) req);
               $display("csrWag Request, addr=%h, burstLen=%h, tag=%h", req.addr, req.burstLen, req.tag);
	       csrWag.request.put(PhysMemRequest { addr: truncate(req.addr), burstLen: req.burstLen, tag: req.tag
`ifdef BYTE_ENABLES
						  , firstbe: req.firstbe, lastbe: req.lastbe
`endif
						  });
	    endmethod
	 endinterface
     interface Put writeData = toPut(writeDataFifo);
     interface Get writeDone = toGet(writeDoneFifo);
   endinterface: write_server
   endinterface
   interface changes = toPipeIn(changeFifo);
   interface TlpTraceClient traceClient;
      interface Reg tlpTracing = tlpTracingReg;
      interface Reg tlpTraceLimit = tlpTraceLimitReg;
      interface Reg tlpTraceBramWrAddr = tlpTraceBramWrAddrReg;
      interface BRAMClient bramClient;
         interface Get request = toGet(bramRequestFifo);
	 interface Put response = toPut(bramResponseFifo);
      endinterface: bramClient
   endinterface: traceClient
   interface Vector msixEntry = map(toReadOnlyMsixEntry, msix_entry);
endmodule: mkPcieControlAndStatusRegs


add timestamp to printTrace

add timestamp to printTrace

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

package PrintTrace;

// XXX: For now export everything
// export printTrace;
// export fprintTrace;
// export printTraceM;
// export fprintTraceM;

import ClientServer::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;
import Vector::*;

/**
 * How to use this package:
 *
 * # printTrace, fprintTrace
 *
 * Let's say you have an interface method in your module that is directly
 * connected to a submodule's interface method, but you want to add a print
 * statement to it. If you don't want to go through the trouble of writing a
 * method definition just to print a message and call the submodule, you can
 * use printTrace and/or fprintTrace to attach a message to the Action or
 * ActionValue interface method every time it is called.
 *
 * >  method Action clear = submodule.clear;
 *
 * becomes
 *
 * >  method Action clear = printTrace("clear", submodule.clear);
 *
 * This will print "clear" to stdout every time the clear method is called. To
 * print to a different file, you can use fprintTrace and specify the file.
 *
 * If your method takes in arguments, printTrace will print the values of the
 * arguments when it is callled. For example:
 *
 * >  method Action enq = printTrace("enq", submodule.enq);
 *
 * will print messages like this:
 *
 * >  enq(3)
 * >  enq(8)
 *
 * This only works if there is an appropriate instance of FShow for all the
 * argument types. You can use printTrace on method calls within a rule, but
 * depending on how you write it, you may or may not see the arguments used in
 * the method call. For example, if you have the original method call:
 *
 * >  m.foo(2, 9);
 *
 * Then writing this ........................ will print this
 * >  printTrace("m.foo", m.foo(2, 9))        >  submodule.foo
 * >  printTrace("m.foo", m.foo)(2, 9)        >  submodule.foo(2, 9)
 * >  printTrace("m.foo", m.foo, 2, 9)        >  submodule.foo(2, 9)
 *
 * # printTraceM, fprintTraceM
 *
 * Let's say you have a FIFO in your module, and you want to add print
 * statements to it's interface:
 *
 * >  FIFO#(Bit#(4)) myfifo <- mkFIFO;
 *
 * becomes
 *
 * >  FIFO#(Bit#(4)) myfifo <- printTraceM("myfifo", mkFIFO);
 *
 * Now everytime any of the action interface methods are called, a message is
 * printed to stdout like this:
 *
 * >  myfifo.enq(3) =
 * >  myfifo.enq(0) =
 * >  myfifo.deq = 3
 * >  myfifo.deq = 0
 * >  myfifo.enq(1) =
 * >  myfifo.deq = 1
 *
 * If you want to output that information to a file, you can use fprintTraceM:
 *
 * >  FIFO#(Bit#(4)) myfifo <- fprintTraceM(file, "myfifo", mkFIFO);
 *
 * You can print to stderr by specifying the file as stderr.
 *
 */

// TODO:
// * Figure out how to add an instance of HasFPrintTraceHelper for Action
//   (which is an alias for ActionValue#(void)) without breaking provisos for
//   other functions and instances using FShow#(t) to imply the existence of
//   ActionValue#(t).
// * Make real documentation.

typeclass HasTypeIsVoid#(type t);
    function Bool typeIsVoid(t x);
        return False;
    endfunction
endtypeclass
instance HasTypeIsVoid#(void);
    function Bool typeIsVoid(void x);
        return True;
    endfunction
endinstance

// internal typeclass
typeclass HasFPrintTraceHelper#(type t);
    function t fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, t x);
endtypeclass
// Base case: ActionValue#(t) (This covers Action since Action = ActionValue#(void))
instance HasFPrintTraceHelper#(ActionValue#(t)) provisos (FShow#(t));
    function ActionValue#(t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, ActionValue#(t) av);
        return (actionvalue
                t x <- av;
                if (printTimestamp) begin
                   $fdisplay(file, $time);
                end
                Fmt printFmt = callName;
                if (args matches tagged Valid .validArgs) begin
                    printFmt = printFmt + $format("(", validArgs, ")");
                end
                // if (t != void)
                void v = ?;
                if (typeOf(x) != typeOf(v)) begin
                    printFmt = printFmt + $format(" = ", fshow(x));
                end
                $fdisplay(file, printFmt);
                $fflush(file);
                return x;
            endactionvalue);
    endfunction
endinstance
// Adding an argument
instance HasFPrintTraceHelper#(function outT f(inT x)) provisos (HasFPrintTraceHelper#(outT), FShow#(inT));
    function (function outT f(inT x)) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, function outT func(inT x));
        function outT retFunc(inT x);
            Fmt newArgs = args matches tagged Valid .validArgs ? validArgs + $format(", ") + fshow(x) : fshow(x);
            return fprintTraceHelper(file, printTimestamp, callName, tagged Valid newArgs, func(x));
        endfunction
        return retFunc;
    endfunction
endinstance
// Some interfaces
instance HasFPrintTraceHelper#(Reg#(t)) provisos (FShow#(t));
    function Reg#(t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, Reg#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return (interface Reg;
                    method Action _write(t x) = fprintTraceHelper(file, printTimestamp, $format(newCallName, "._write"), newArgs, ifc._write, x);
                    method t _read = ifc._read;
                endinterface);
    endfunction
endinstance
instance HasFPrintTraceHelper#(Get#(t)) provisos (FShow#(t));
    function Get#(t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, Get#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toGet(fprintTraceHelper(file, printTimestamp, $format(newCallName, ".get"), newArgs, ifc.get));
    endfunction
endinstance
instance HasFPrintTraceHelper#(Put#(t)) provisos (FShow#(t));
    function Put#(t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, Put#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toPut(fprintTraceHelper(file, printTimestamp, $format(newCallName, ".put"), newArgs, ifc.put));
    endfunction
endinstance
instance HasFPrintTraceHelper#(Client#(t1,t2)) provisos (FShow#(t1), FShow#(t2));
    function Client#(t1,t2) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, Client#(t1,t2) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toGPClient(fprintTraceHelper(file, printTimestamp, $format(newCallName, ".request"), newArgs, ifc.request),
                          fprintTraceHelper(file, printTimestamp, $format(newCallName, ".response"), newArgs, ifc.response));
    endfunction
endinstance
instance HasFPrintTraceHelper#(Server#(t1,t2)) provisos (FShow#(t1), FShow#(t2));
    function Server#(t1,t2) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, Server#(t1,t2) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toGPServer(fprintTraceHelper(file, printTimestamp, $format(newCallName, ".request"), newArgs, ifc.request),
                          fprintTraceHelper(file, printTimestamp, $format(newCallName, ".response"), newArgs, ifc.response));
    endfunction
endinstance
instance HasFPrintTraceHelper#(FIFO#(t)) provisos (FShow#(t));
    function FIFO#(t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, FIFO#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return (interface FIFO;
                    method Action enq(t x); fprintTraceHelper(file, printTimestamp, $format(newCallName, ".enq"), newArgs, ifc.enq, x); endmethod
                    // when printing, make deq look like an action value so you can see the value of first
                    method Action deq = fprintTraceHelper(file, printTimestamp, $format(newCallName, ".deq = ", fshow(ifc.first)), newArgs, ifc.deq);
                    method t first = ifc.first;
                    method Action clear = fprintTraceHelper(file, printTimestamp, $format(newCallName, ".clear"), newArgs, ifc.clear);
                endinterface);
    endfunction
endinstance
instance HasFPrintTraceHelper#(FIFOF#(t)) provisos (FShow#(t));
    function FIFOF#(t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, FIFOF#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return (interface FIFOF;
                    method Action enq(t x) = fprintTraceHelper(file, printTimestamp, $format(newCallName, ".enq"), newArgs, ifc.enq, x);
                    // when printing, make deq look like an action value so you can see the value of first
                    method Action deq = fprintTraceHelper(file, printTimestamp, $format(newCallName, ".deq = ", fshow(ifc.first)), newArgs, ifc.deq);
                    method t first = ifc.first;
                    method Bool notFull = ifc.notFull;
                    method Bool notEmpty = ifc.notEmpty;
                    method Action clear = fprintTraceHelper(file, printTimestamp, $format(newCallName, ".clear"), newArgs, ifc.clear);
                endinterface);
    endfunction
endinstance
instance HasFPrintTraceHelper#(Vector#(n,t)) provisos (HasFPrintTraceHelper#(t));
    function Vector#(n,t) fprintTraceHelper(File file, Bool printTimestamp, Fmt callName, Maybe#(Fmt) args, Vector#(n,t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;

        function t genFunc(Integer i);
            return fprintTraceHelper(file, printTimestamp, $format(callName, "[%d]", i), tagged Invalid, ifc[i]);
        endfunction
        return genWith(genFunc);
    endfunction
endinstance

// external functions
function t fprintTrace(File file, String msg, t x)
        provisos (HasFPrintTraceHelper#(t));
    return fprintTraceHelper(file, False, $format(msg), tagged Invalid, x);
endfunction

function t printTrace(String msg, t x)
        provisos (HasFPrintTraceHelper#(t));
    return fprintTraceHelper(stdout, False, $format(msg), tagged Invalid, x);
endfunction

module [m] fprintTraceM#(File file, String msg, m#(t) mkM)(t)
        provisos (IsModule#(m, a__), HasFPrintTraceHelper#(t));
    (* hide *)
    t _m <- mkM();
    return fprintTraceHelper(file, False, $format(msg), tagged Invalid, _m);
endmodule

module [m] printTraceM#(String msg, m#(t) mkM)(t)
        provisos (IsModule#(m, a__), HasFPrintTraceHelper#(t));
    (* hide *)
    t _m <- mkM;
    return fprintTraceHelper(stdout, False, $format(msg), tagged Invalid, _m);
endmodule

module [m] printTimedTraceM#(String msg, m#(t) mkM)(t)
        provisos (IsModule#(m, a__), HasFPrintTraceHelper#(t));
    (* hide *)
    t _m <- mkM;
    return fprintTraceHelper(stdout, True, $format(msg), tagged Invalid, _m);
endmodule

endpackage

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

package PrintTrace;

// XXX: For now export everything
// export printTrace;
// export fprintTrace;
// export printTraceM;
// export fprintTraceM;

import ClientServer::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;
import Vector::*;

/**
 * How to use this package:
 *
 * # printTrace, fprintTrace
 *
 * Let's say you have an interface method in your module that is directly
 * connected to a submodule's interface method, but you want to add a print
 * statement to it. If you don't want to go through the trouble of writing a
 * method definition just to print a message and call the submodule, you can
 * use printTrace and/or fprintTrace to attach a message to the Action or
 * ActionValue interface method every time it is called.
 *
 * >  method Action clear = submodule.clear;
 *
 * becomes
 *
 * >  method Action clear = printTrace("clear", submodule.clear);
 *
 * This will print "clear" to stdout every time the clear method is called. To
 * print to a different file, you can use fprintTrace and specify the file.
 *
 * If your method takes in arguments, printTrace will print the values of the
 * arguments when it is callled. For example:
 *
 * >  method Action enq = printTrace("enq", submodule.enq);
 *
 * will print messages like this:
 *
 * >  enq(3)
 * >  enq(8)
 *
 * This only works if there is an appropriate instance of FShow for all the
 * argument types. You can use printTrace on method calls within a rule, but
 * depending on how you write it, you may or may not see the arguments used in
 * the method call. For example, if you have the original method call:
 *
 * >  m.foo(2, 9);
 *
 * Then writing this ........................ will print this
 * >  printTrace("m.foo", m.foo(2, 9))        >  submodule.foo
 * >  printTrace("m.foo", m.foo)(2, 9)        >  submodule.foo(2, 9)
 * >  printTrace("m.foo", m.foo, 2, 9)        >  submodule.foo(2, 9)
 *
 * # printTraceM, fprintTraceM
 *
 * Let's say you have a FIFO in your module, and you want to add print
 * statements to it's interface:
 *
 * >  FIFO#(Bit#(4)) myfifo <- mkFIFO;
 *
 * becomes
 *
 * >  FIFO#(Bit#(4)) myfifo <- printTraceM("myfifo", mkFIFO);
 *
 * Now everytime any of the action interface methods are called, a message is
 * printed to stdout like this:
 *
 * >  myfifo.enq(3) =
 * >  myfifo.enq(0) =
 * >  myfifo.deq = 3
 * >  myfifo.deq = 0
 * >  myfifo.enq(1) =
 * >  myfifo.deq = 1
 *
 * If you want to output that information to a file, you can use fprintTraceM:
 *
 * >  FIFO#(Bit#(4)) myfifo <- fprintTraceM(file, "myfifo", mkFIFO);
 *
 * You can print to stderr by specifying the file as stderr.
 *
 */

// TODO:
// * Figure out how to add an instance of HasFPrintTraceHelper for Action
//   (which is an alias for ActionValue#(void)) without breaking provisos for
//   other functions and instances using FShow#(t) to imply the existence of
//   ActionValue#(t).
// * Make real documentation.

typeclass HasTypeIsVoid#(type t);
    function Bool typeIsVoid(t x);
        return False;
    endfunction
endtypeclass
instance HasTypeIsVoid#(void);
    function Bool typeIsVoid(void x);
        return True;
    endfunction
endinstance

// internal typeclass
typeclass HasFPrintTraceHelper#(type t);
    function t fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, t x);
endtypeclass
// Base case: ActionValue#(t) (This covers Action since Action = ActionValue#(void))
instance HasFPrintTraceHelper#(ActionValue#(t)) provisos (FShow#(t));
    function ActionValue#(t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, ActionValue#(t) av);
        return (actionvalue
                t x <- av;
                Fmt printFmt = callName;
                if (args matches tagged Valid .validArgs) begin
                    printFmt = printFmt + $format("(", validArgs, ")");
                end
                // if (t != void)
                void v = ?;
                if (typeOf(x) != typeOf(v)) begin
                    printFmt = printFmt + $format(" = ", fshow(x));
                end
                $fdisplay(file, printFmt);
                $fflush(file);
                return x;
            endactionvalue);
    endfunction
endinstance
// Adding an argument
instance HasFPrintTraceHelper#(function outT f(inT x)) provisos (HasFPrintTraceHelper#(outT), FShow#(inT));
    function (function outT f(inT x)) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, function outT func(inT x));
        function outT retFunc(inT x);
            Fmt newArgs = args matches tagged Valid .validArgs ? validArgs + $format(", ") + fshow(x) : fshow(x);
            return fprintTraceHelper(file, callName, tagged Valid newArgs, func(x));
        endfunction
        return retFunc;
    endfunction
endinstance
// Some interfaces
instance HasFPrintTraceHelper#(Reg#(t)) provisos (FShow#(t));
    function Reg#(t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, Reg#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return (interface Reg;
                    method Action _write(t x) = fprintTraceHelper(file, $format(newCallName, "._write"), newArgs, ifc._write, x);
                    method t _read = ifc._read;
                endinterface);
    endfunction
endinstance
instance HasFPrintTraceHelper#(Get#(t)) provisos (FShow#(t));
    function Get#(t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, Get#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toGet(fprintTraceHelper(file, $format(newCallName, ".get"), newArgs, ifc.get));
    endfunction
endinstance
instance HasFPrintTraceHelper#(Put#(t)) provisos (FShow#(t));
    function Put#(t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, Put#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toPut(fprintTraceHelper(file, $format(newCallName, ".put"), newArgs, ifc.put));
    endfunction
endinstance
instance HasFPrintTraceHelper#(Client#(t1,t2)) provisos (FShow#(t1), FShow#(t2));
    function Client#(t1,t2) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, Client#(t1,t2) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toGPClient(fprintTraceHelper(file, $format(newCallName, ".request"), newArgs, ifc.request),
                          fprintTraceHelper(file, $format(newCallName, ".response"), newArgs, ifc.response));
    endfunction
endinstance
instance HasFPrintTraceHelper#(Server#(t1,t2)) provisos (FShow#(t1), FShow#(t2));
    function Server#(t1,t2) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, Server#(t1,t2) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return toGPServer(fprintTraceHelper(file, $format(newCallName, ".request"), newArgs, ifc.request),
                          fprintTraceHelper(file, $format(newCallName, ".response"), newArgs, ifc.response));
    endfunction
endinstance
instance HasFPrintTraceHelper#(FIFO#(t)) provisos (FShow#(t));
    function FIFO#(t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, FIFO#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return (interface FIFO;
                    method Action enq(t x); fprintTraceHelper(file, $format(newCallName, ".enq"), newArgs, ifc.enq, x); endmethod
                    // when printing, make deq look like an action value so you can see the value of first
                    method Action deq = fprintTraceHelper(file, $format(newCallName, ".deq = ", fshow(ifc.first)), newArgs, ifc.deq);
                    method t first = ifc.first;
                    method Action clear = fprintTraceHelper(file, $format(newCallName, ".clear"), newArgs, ifc.clear);
                endinterface);
    endfunction
endinstance
instance HasFPrintTraceHelper#(FIFOF#(t)) provisos (FShow#(t));
    function FIFOF#(t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, FIFOF#(t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;
        return (interface FIFOF;
                    method Action enq(t x) = fprintTraceHelper(file, $format(newCallName, ".enq"), newArgs, ifc.enq, x);
                    // when printing, make deq look like an action value so you can see the value of first
                    method Action deq = fprintTraceHelper(file, $format(newCallName, ".deq = ", fshow(ifc.first)), newArgs, ifc.deq);
                    method t first = ifc.first;
                    method Bool notFull = ifc.notFull;
                    method Bool notEmpty = ifc.notEmpty;
                    method Action clear = fprintTraceHelper(file, $format(newCallName, ".clear"), newArgs, ifc.clear);
                endinterface);
    endfunction
endinstance
instance HasFPrintTraceHelper#(Vector#(n,t)) provisos (HasFPrintTraceHelper#(t));
    function Vector#(n,t) fprintTraceHelper(File file, Fmt callName, Maybe#(Fmt) args, Vector#(n,t) ifc);
        // if there were arguments, add it to the callName
        Fmt newCallName = args matches tagged Valid .validArgs ? $format(callName, "(", validArgs, ")") : callName;
        Maybe#(Fmt) newArgs = tagged Invalid;

        function t genFunc(Integer i);
            return fprintTraceHelper(file, $format(callName, "[%d]", i), tagged Invalid, ifc[i]);
        endfunction
        return genWith(genFunc);
    endfunction
endinstance

// external functions
function t fprintTrace(File file, String msg, t x)
        provisos (HasFPrintTraceHelper#(t));
    return fprintTraceHelper(file, $format(msg), tagged Invalid, x);
endfunction

function t printTrace(String msg, t x)
        provisos (HasFPrintTraceHelper#(t));
    return fprintTraceHelper(stdout, $format(msg), tagged Invalid, x);
endfunction

module [m] fprintTraceM#(File file, String msg, m#(t) mkM)(t)
        provisos (IsModule#(m, a__), HasFPrintTraceHelper#(t));
    (* hide *)
    t _m <- mkM();
    return fprintTraceHelper(file, $format(msg), tagged Invalid, _m);
endmodule

module [m] printTraceM#(String msg, m#(t) mkM)(t)
        provisos (IsModule#(m, a__), HasFPrintTraceHelper#(t));
    (* hide *)
    t _m <- mkM;
    return fprintTraceHelper(stdout, $format(msg), tagged Invalid, _m);
endmodule

endpackage


decouple sglist() request from dmaError indication

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

// XBSV Libraries
import MemTypes::*;
import PortalMemory::*;
import SGList::*;
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  MemWriteClient#(addrWidth, 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#(addrWidth, busWidth) null_mem_read_client();
   return (interface MemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

`ifdef BSIM
`ifndef PCIE
import "BDPI" function ActionValue#(Bit#(32)) pareff(Bit#(32) handle, Bit#(32) size);
`endif
`endif

typedef 4 NUM_OO_TAGS;

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

module mkMemServer#(DmaIndication dmaIndication,
		    Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
		    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients),
	    Add#(i__, TLog#(nrc), 6),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients),
	    Add#(j__, TLog#(nwc), 6));

   Vector#(nMasters,TagGen#(nwc,nwc)) writeTagGens <- replicateM(mkTagGenIO);
   Vector#(nMasters,TagGen#(nrc,nrc)) readTagGens  <- replicateM(mkTagGenIO);
   let rv <- mkConfigMemServerRW(dmaIndication, readTagGens, writeTagGens, readClients, writeClients);
   return rv;

endmodule

module mkMemServerR#(DmaIndication dmaIndication,
		     Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients),
	    Add#(i__, TLog#(nrc), 6));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nrc,nrc)) readTagGens <- replicateM(mkTagGenIO);
   let rv <- mkConfigMemServerR(dmaIndication,readTagGens,readClients,sgl);
   return rv;

endmodule

module mkMemServerW#(DmaIndication dmaIndication,
		    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients),
	    Add#(i__, TLog#(nwc), 6));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nwc,nwc)) writeTagGens <- replicateM(mkTagGenIO);
   let rv <- mkConfigMemServerW(dmaIndication, writeTagGens, writeClients,sgl);
   return rv;

endmodule

module mkMemServerOO#(DmaIndication dmaIndication,
		      Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
		      Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients),
	    Add#(i__, TLog#(nrc), 6),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients),
	    Add#(j__, TLog#(nwc), 6));

   Vector#(nMasters,TagGen#(nwc,NUM_OO_TAGS)) writeTagGens <- replicateM(mkTagGenOO);
   Vector#(nMasters,TagGen#(nrc,NUM_OO_TAGS)) readTagGens <- replicateM(mkTagGenOO);
   let rv <- mkConfigMemServerRW(dmaIndication, readTagGens, writeTagGens, readClients, writeClients);
   return rv;

endmodule

module mkMemServerOOR#(DmaIndication dmaIndication,
		       Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nrc,NUM_OO_TAGS)) readTagGens <- replicateM(mkTagGenOO);
   let rv <- mkConfigMemServerR(dmaIndication,readTagGens,readClients,sgl);
   return rv;

endmodule

module mkMemServerOOW#(DmaIndication dmaIndication,
		    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nwc,NUM_OO_TAGS)) writeTagGens <- replicateM(mkTagGenOO);
   let rv <- mkConfigMemServerW(dmaIndication, writeTagGens,writeClients,sgl);
   return rv;

endmodule

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

module mkConfigMemServerRW#(DmaIndication dmaIndication,
			    Vector#(nMasters,TagGen#(nrc, numReadTags)) readTagGens,
			    Vector#(nMasters,TagGen#(nwc, numWriteTags)) writeTagGens,
			    Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
			    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Add#(b__, TSub#(addrWidth, 12), 32),
	     Add#(c__, 12, addrWidth),
	     Add#(d__, addrWidth, 64),
	     Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	     Add#(f__, c__, ObjectOffsetSize),
	     Add#(g__, addrWidth, 40),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(h__, TLog#(numReadTags), 6),
	     Add#(j__, TLog#(numWriteTags), 6),
	     Mul#(nwc, nMasters, numWriteClients),
	     Mul#(nrc, nMasters, numReadClients));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   MemServer#(addrWidth,dataWidth,nMasters) reader <- mkConfigMemServerR(dmaIndication, readTagGens,  readClients,  sgl);
   MemServer#(addrWidth,dataWidth,nMasters) writer <- mkConfigMemServerW(dmaIndication, writeTagGens, writeClients, sgl);

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   function MemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface MemMaster#(addrWidth,dataWidth);
								 interface MemReadClient read_client = reader.masters[i].read_client;
								 interface MemWriteClient write_client = writer.masters[i].write_client;
							      endinterface);

   interface DmaConfig request;
      method Action getStateDbg(ChannelType rc);
	 if (rc == Read)
	    reader.request.getStateDbg(rc);
	 else
	    writer.request.getStateDbg(rc);
      endmethod
      method Action getMemoryTraffic(ChannelType rc);
	 if (rc == Read)
	    reader.request.getMemoryTraffic(rc);
	 else
	    writer.request.getMemoryTraffic(rc);
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(64) addr, Bit#(32) len);
	 if (bad_pointer(pref))
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer1, pref: pref });
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pref, len);
`endif
`endif
	 sgl.sglist(pref, truncate(addr), len);
      endmethod
      method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(64) barr4, Bit#(64) barr0);
	 sgl.region(pointer,truncate(barr8),truncate(barr4),truncate(barr0));
      endmethod
      method Action addrRequest(Bit#(32) pointer, Bit#(32) offset);
	 writer.request.addrRequest(pointer,offset);
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkConfigMemServerR#(DmaIndication dmaIndication,
			   Vector#(nMasters,TagGen#(nrc, numReadTags)) readTagGens,
			   Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
			   SGListMMU#(addrWidth) sgl)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Add#(b__, TSub#(addrWidth, 12), 32),
	     Add#(c__, 12, addrWidth),
	     Add#(d__, addrWidth, 64),
	     Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	     Add#(f__, c__, ObjectOffsetSize),
	     Add#(g__, addrWidth, 40),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(h__, TLog#(numReadTags), 6),
	     Mul#(nrc, nMasters, numReadClients));

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

   Vector#(nMasters,List#(ObjectReadClient#(dataWidth))) client_bins = replicate(Nil);
   for(Integer i = 0; i < valueOf(numReadClients); i=i+1)
      client_bins[i%valueOf(nMasters)] = List::cons(readClients[i], client_bins[i%valueOf(nMasters)]);

   SglAddrServer#(addrWidth,nMasters) sgl_server <- mkSglAddrServer(sgl.addr[0]);
   Vector#(nMasters,MemReadInternal#(addrWidth,dataWidth)) readers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1)
      readers[i] <- mkMemReadInternal(i, toVector(client_bins[i]), dmaIndication, sgl_server.servers[i], readTagGens[i]);

   rule sglistEntry;
      addrReqFifo.deq;
      let physAddr <- sgl.addr[0].response.get;
      dmaIndication.addrResponse(zeroExtend(physAddr));
   endrule

   function MemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface MemMaster#(addrWidth,dataWidth);
								 interface MemReadClient read_client = readers[i].read_client;
								 interface MemWriteClient write_client = null_mem_write_client;
							      endinterface);

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

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   interface DmaConfig request;
      method Action getStateDbg(ChannelType rc);
	 if (rc == Read)
	    dbgFSM.start;
      endmethod
      method Action getMemoryTraffic(ChannelType rc);
	 if (rc == Read)
	    trafficFSM.start;
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(64) addr, Bit#(32) len);
	 if (bad_pointer(pref))
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer2, pref: pref });
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pref, len);
`endif
`endif
	 sgl.sglist(pref, truncate(addr), len);
      endmethod
      method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(64) barr4, Bit#(64) barr0);
	 sgl.region(pointer,truncate(barr8),truncate(barr4),truncate(barr0));
      endmethod
      method Action addrRequest(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(?);
	 sgl.addr[0].request.put(tuple2(truncate(pointer), extend(offset)));
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkConfigMemServerW#(DmaIndication dmaIndication,
			   Vector#(nMasters,TagGen#(nwc,numWriteTags)) writeTagGens,
			   Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients,
			   SGListMMU#(addrWidth) sgl)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Add#(b__, TSub#(addrWidth, 12), 32),
	     Add#(c__, 12, addrWidth),
	     Add#(d__, addrWidth, 64),
	     Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	     Add#(f__, c__, ObjectOffsetSize),
	     Add#(g__, addrWidth, 40),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(j__, TLog#(numWriteTags), 6),
	     Mul#(nwc, nMasters, numWriteClients));

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

   Vector#(nMasters,List#(ObjectWriteClient#(dataWidth))) client_bins = replicate(Nil);
   for(Integer i = 0; i < valueOf(numWriteClients); i=i+1)
      client_bins[i%valueOf(nMasters)] = List::cons(writeClients[i], client_bins[i%valueOf(nMasters)]);

   SglAddrServer#(addrWidth,nMasters) sgl_server <- mkSglAddrServer(sgl.addr[1]);
   Vector#(nMasters,MemWriteInternal#(addrWidth,dataWidth)) writers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1)
      writers[i] <- mkMemWriteInternal(i, toVector(client_bins[i]), dmaIndication, sgl_server.servers[i], writeTagGens[i]);

   rule sglistEntry;
      addrReqFifo.deq;
      let physAddr <- sgl.addr[1].response.get;
      dmaIndication.addrResponse(zeroExtend(physAddr));
   endrule

   function MemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface MemMaster#(addrWidth,dataWidth);
								 interface MemReadClient read_client = null_mem_read_client;
								 interface MemWriteClient 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;
			    dmaIndication.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);
			 dmaIndication.reportMemoryTraffic(trafficAccum);
		      endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   interface DmaConfig request;
      method Action getStateDbg(ChannelType rc);
	 if (rc == Write)
	    dbgFSM.start;
      endmethod
      method Action getMemoryTraffic(ChannelType rc);
	 if (rc == Write)
	    trafficFSM.start;
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(64) addr, Bit#(32) len);
	 if (bad_pointer(pref))
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer3, pref: pref });
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pref, len);
`endif
`endif
	 sgl.sglist(pref, truncate(addr), len);
      endmethod
      method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(64) barr4, Bit#(64) barr0);
	 sgl.region(pointer,truncate(barr8),truncate(barr4),truncate(barr0));
      endmethod
      method Action addrRequest(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(?);
	 sgl.addr[1].request.put(tuple2(truncate(pointer), extend(offset)));
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
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::*;

// XBSV Libraries
import MemTypes::*;
import PortalMemory::*;
import SGList::*;
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  MemWriteClient#(addrWidth, 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#(addrWidth, busWidth) null_mem_read_client();
   return (interface MemReadClient;
              interface Get readReq = null_get;
              interface Put readData = null_put;
           endinterface);
endfunction

`ifdef BSIM
`ifndef PCIE
import "BDPI" function ActionValue#(Bit#(32)) pareff(Bit#(32) handle, Bit#(32) size);
`endif
`endif

typedef 4 NUM_OO_TAGS;

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

module mkMemServer#(DmaIndication dmaIndication,
		    Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
		    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients),
	    Add#(i__, TLog#(nrc), 6),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients),
	    Add#(j__, TLog#(nwc), 6));

   Vector#(nMasters,TagGen#(nwc,nwc)) writeTagGens <- replicateM(mkTagGenIO);
   Vector#(nMasters,TagGen#(nrc,nrc)) readTagGens  <- replicateM(mkTagGenIO);
   let rv <- mkConfigMemServerRW(dmaIndication, readTagGens, writeTagGens, readClients, writeClients);
   return rv;

endmodule

module mkMemServerR#(DmaIndication dmaIndication,
		     Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients),
	    Add#(i__, TLog#(nrc), 6));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nrc,nrc)) readTagGens <- replicateM(mkTagGenIO);
   let rv <- mkConfigMemServerR(dmaIndication,readTagGens,readClients,sgl);
   return rv;

endmodule

module mkMemServerW#(DmaIndication dmaIndication,
		    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients),
	    Add#(i__, TLog#(nwc), 6));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nwc,nwc)) writeTagGens <- replicateM(mkTagGenIO);
   let rv <- mkConfigMemServerW(dmaIndication, writeTagGens, writeClients,sgl);
   return rv;

endmodule

module mkMemServerOO#(DmaIndication dmaIndication,
		      Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
		      Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients),
	    Add#(i__, TLog#(nrc), 6),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients),
	    Add#(j__, TLog#(nwc), 6));

   Vector#(nMasters,TagGen#(nwc,NUM_OO_TAGS)) writeTagGens <- replicateM(mkTagGenOO);
   Vector#(nMasters,TagGen#(nrc,NUM_OO_TAGS)) readTagGens <- replicateM(mkTagGenOO);
   let rv <- mkConfigMemServerRW(dmaIndication, readTagGens, writeTagGens, readClients, writeClients);
   return rv;

endmodule

module mkMemServerOOR#(DmaIndication dmaIndication,
		       Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numReadClients, nMasters, nrc),
	    Mul#(nrc, nMasters, numReadClients));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nrc,NUM_OO_TAGS)) readTagGens <- replicateM(mkTagGenOO);
   let rv <- mkConfigMemServerR(dmaIndication,readTagGens,readClients,sgl);
   return rv;

endmodule

module mkMemServerOOW#(DmaIndication dmaIndication,
		    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))
   provisos(Add#(1,a__,dataWidth),
	    Add#(b__, TSub#(addrWidth, 12), 32),
	    Add#(c__, 12, addrWidth),
	    Add#(d__, addrWidth, 64),
	    Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	    Add#(f__, c__, ObjectOffsetSize),
	    Add#(g__, addrWidth, 40),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Div#(numWriteClients, nMasters, nwc),
	    Mul#(nwc, nMasters, numWriteClients));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   Vector#(nMasters,TagGen#(nwc,NUM_OO_TAGS)) writeTagGens <- replicateM(mkTagGenOO);
   let rv <- mkConfigMemServerW(dmaIndication, writeTagGens,writeClients,sgl);
   return rv;

endmodule

module mkConfigMemServerRW#(DmaIndication dmaIndication,
			    Vector#(nMasters,TagGen#(nrc, numReadTags)) readTagGens,
			    Vector#(nMasters,TagGen#(nwc, numWriteTags)) writeTagGens,
			    Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
			    Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Add#(b__, TSub#(addrWidth, 12), 32),
	     Add#(c__, 12, addrWidth),
	     Add#(d__, addrWidth, 64),
	     Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	     Add#(f__, c__, ObjectOffsetSize),
	     Add#(g__, addrWidth, 40),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(h__, TLog#(numReadTags), 6),
	     Add#(j__, TLog#(numWriteTags), 6),
	     Mul#(nwc, nMasters, numWriteClients),
	     Mul#(nrc, nMasters, numReadClients));

   SGListMMU#(addrWidth) sgl <- mkSGListMMU(dmaIndication);
   MemServer#(addrWidth,dataWidth,nMasters) reader <- mkConfigMemServerR(dmaIndication, readTagGens,  readClients,  sgl);
   MemServer#(addrWidth,dataWidth,nMasters) writer <- mkConfigMemServerW(dmaIndication, writeTagGens, writeClients, sgl);

   function MemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface MemMaster#(addrWidth,dataWidth);
								 interface MemReadClient read_client = reader.masters[i].read_client;
								 interface MemWriteClient write_client = writer.masters[i].write_client;
							      endinterface);

   interface DmaConfig request;
      method Action getStateDbg(ChannelType rc);
	 if (rc == Read)
	    reader.request.getStateDbg(rc);
	 else
	    writer.request.getStateDbg(rc);
      endmethod
      method Action getMemoryTraffic(ChannelType rc);
	 if (rc == Read)
	    reader.request.getMemoryTraffic(rc);
	 else
	    writer.request.getMemoryTraffic(rc);
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(64) addr, Bit#(32) len);
	 if (bad_pointer(pref))
	    dmaIndication.dmaError(extend(pack(DmaErrorBadPointer1)), pref, 0, 0);
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pref, len);
`endif
`endif
	 sgl.sglist(pref, truncate(addr), len);
      endmethod
      method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(64) barr4, Bit#(64) barr0);
	 sgl.region(pointer,truncate(barr8),truncate(barr4),truncate(barr0));
      endmethod
      method Action addrRequest(Bit#(32) pointer, Bit#(32) offset);
	 writer.request.addrRequest(pointer,offset);
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkConfigMemServerR#(DmaIndication dmaIndication,
			   Vector#(nMasters,TagGen#(nrc, numReadTags)) readTagGens,
			   Vector#(numReadClients, ObjectReadClient#(dataWidth)) readClients,
			   SGListMMU#(addrWidth) sgl)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Add#(b__, TSub#(addrWidth, 12), 32),
	     Add#(c__, 12, addrWidth),
	     Add#(d__, addrWidth, 64),
	     Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	     Add#(f__, c__, ObjectOffsetSize),
	     Add#(g__, addrWidth, 40),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(h__, TLog#(numReadTags), 6),
	     Mul#(nrc, nMasters, numReadClients));

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

   Vector#(nMasters,List#(ObjectReadClient#(dataWidth))) client_bins = replicate(Nil);
   for(Integer i = 0; i < valueOf(numReadClients); i=i+1)
      client_bins[i%valueOf(nMasters)] = List::cons(readClients[i], client_bins[i%valueOf(nMasters)]);

   SglAddrServer#(addrWidth,nMasters) sgl_server <- mkSglAddrServer(sgl.addr[0]);
   Vector#(nMasters,MemReadInternal#(addrWidth,dataWidth)) readers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1)
      readers[i] <- mkMemReadInternal(i, toVector(client_bins[i]), dmaIndication, sgl_server.servers[i], readTagGens[i]);

   rule sglistEntry;
      addrReqFifo.deq;
      let physAddr <- sgl.addr[0].response.get;
      dmaIndication.addrResponse(zeroExtend(physAddr));
   endrule

   function MemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface MemMaster#(addrWidth,dataWidth);
								 interface MemReadClient read_client = readers[i].read_client;
								 interface MemWriteClient write_client = null_mem_write_client;
							      endinterface);

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

   interface DmaConfig request;
      method Action getStateDbg(ChannelType rc);
	 if (rc == Read)
	    dbgFSM.start;
      endmethod
      method Action getMemoryTraffic(ChannelType rc);
	 if (rc == Read)
	    trafficFSM.start;
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(64) addr, Bit#(32) len);
	 if (bad_pointer(pref))
	    dmaIndication.dmaError(extend(pack(DmaErrorBadPointer2)), pref, 0, 0);
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pref, len);
`endif
`endif
	 sgl.sglist(pref, truncate(addr), len);
      endmethod
      method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(64) barr4, Bit#(64) barr0);
	 sgl.region(pointer,truncate(barr8),truncate(barr4),truncate(barr0));
      endmethod
      method Action addrRequest(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(?);
	 sgl.addr[0].request.put(tuple2(truncate(pointer), extend(offset)));
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule

module mkConfigMemServerW#(DmaIndication dmaIndication,
			   Vector#(nMasters,TagGen#(nwc,numWriteTags)) writeTagGens,
			   Vector#(numWriteClients, ObjectWriteClient#(dataWidth)) writeClients,
			   SGListMMU#(addrWidth) sgl)
   (MemServer#(addrWidth, dataWidth, nMasters))

   provisos (Add#(1,a__,dataWidth),
	     Add#(b__, TSub#(addrWidth, 12), 32),
	     Add#(c__, 12, addrWidth),
	     Add#(d__, addrWidth, 64),
	     Add#(e__, TSub#(addrWidth, 12), ObjectOffsetSize),
	     Add#(f__, c__, ObjectOffsetSize),
	     Add#(g__, addrWidth, 40),
	     Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Add#(j__, TLog#(numWriteTags), 6),
	     Mul#(nwc, nMasters, numWriteClients));

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

   Vector#(nMasters,List#(ObjectWriteClient#(dataWidth))) client_bins = replicate(Nil);
   for(Integer i = 0; i < valueOf(numWriteClients); i=i+1)
      client_bins[i%valueOf(nMasters)] = List::cons(writeClients[i], client_bins[i%valueOf(nMasters)]);

   SglAddrServer#(addrWidth,nMasters) sgl_server <- mkSglAddrServer(sgl.addr[1]);
   Vector#(nMasters,MemWriteInternal#(addrWidth,dataWidth)) writers;
   for(Integer i = 0; i < valueOf(nMasters); i = i+1)
      writers[i] <- mkMemWriteInternal(i, toVector(client_bins[i]), dmaIndication, sgl_server.servers[i], writeTagGens[i]);

   rule sglistEntry;
      addrReqFifo.deq;
      let physAddr <- sgl.addr[1].response.get;
      dmaIndication.addrResponse(zeroExtend(physAddr));
   endrule

   function MemMaster#(addrWidth,dataWidth) mkm(Integer i) = (interface MemMaster#(addrWidth,dataWidth);
								 interface MemReadClient read_client = null_mem_read_client;
								 interface MemWriteClient 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;
			    dmaIndication.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);
			 dmaIndication.reportMemoryTraffic(trafficAccum);
		      endseq;
   FSM trafficFSM <- mkFSM(trafficStmt);

   interface DmaConfig request;
      method Action getStateDbg(ChannelType rc);
	 if (rc == Write)
	    dbgFSM.start;
      endmethod
      method Action getMemoryTraffic(ChannelType rc);
	 if (rc == Write)
	    trafficFSM.start;
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(64) addr, Bit#(32) len);
	 if (bad_pointer(pref))
	    dmaIndication.dmaError(extend(pack(DmaErrorBadPointer3)), pref, 0, 0);
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pref, len);
`endif
`endif
	 sgl.sglist(pref, truncate(addr), len);
      endmethod
      method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(64) barr4, Bit#(64) barr0);
	 sgl.region(pointer,truncate(barr8),truncate(barr4),truncate(barr0));
      endmethod
      method Action addrRequest(Bit#(32) pointer, Bit#(32) offset);
	 addrReqFifo.enq(?);
	 sgl.addr[1].request.put(tuple2(truncate(pointer), extend(offset)));
      endmethod
   endinterface
   interface masters = map(mkm,genVector);
endmodule