added scheduling annotation and changed interface of mkXsimSink to Empty

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import ConnectalConfig::*;
import Vector            :: *;
import GetPut::*;
import Connectable::*;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes:: *;
import MMU:: *;
import MemServer:: *;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import SimDma::*;
import IfcNames::*;
import BuildVector::*;

`include "ConnectalProjectConfig.bsv"

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimSource;
    method Action beat(Bit#(32) v);
endinterface
import "BVI" XsimSource =
module mkXsimSourceBVI#(Bit#(32) portal)(XsimSource);
    port portal = portal;
    method beat(beat) enable(en_beat);
    schedule (beat) C (beat);
endmodule
module mkXsimSource#(PortalMsgIndication indication)(Empty);
   let tmp <- mkXsimSourceBVI(indication.id);
   rule ind_dst_rdy;
      indication.message.deq();
      tmp.beat(indication.message.first());
   endrule
endmodule

interface MsgSinkR#(numeric type bytes_per_beat);
   method ActionValue#(Bit#(32)) beat();
endinterface

import "BVI" XsimSink =
module mkXsimSinkBVI#(Bit#(32) portal)(MsgSinkR#(4));
   port portal = portal;
   method beat beat() enable (EN_beat) ready (RDY_beat);
   schedule (beat) C (beat);
endmodule
module mkXsimSink#(PortalMsgRequest request)(Empty);
   let sink <- mkXsimSinkBVI(request.id);

   rule req_src_rdy;
      let beat <- sink.beat();
      request.message.enq(beat);
   endrule
endmodule

module mkXsimMemoryConnection#(PhysMemMaster#(addrWidth, dataWidth) master)(Empty)
   provisos (Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(TDiv#(dataWidth, 32), 32, dataWidth),
	     Add#(a__, TDiv#(DataBusWidth,8), TDiv#(dataWidth, 8)),
	     Mul#(TDiv#(dataWidth, 32), 4, TDiv#(dataWidth, 8)));
   PhysMemSlave#(addrWidth,dataWidth) slave <- mkSimDmaDmaMaster();
   mkConnection(master, slave);
endmodule

module mkXsimTop#(Clock derivedClock, Reset derivedReset)(Empty);

   Reg#(Bool) dumpstarted <- mkReg(False);
   rule startdump if (!dumpstarted);
      //$dumpfile("dump.vcd");
      //$dumpvars;
      $display("XsimTop starting");
      dumpstarted <= True;
   endrule
   XsimHost host <- mkXsimHost(derivedClock, derivedReset);
   let top <- mkCnocTop(
`ifdef IMPORT_HOSTIF
       host
`else
`ifdef IMPORT_HOST_CLOCKS // enables synthesis boundary
       derivedClock, derivedReset
`else
// otherwise no params
`endif
`endif
       );

   MMUIndicationOutput lMMUIndicationOutput <- mkMMUIndicationOutput;
   MMURequestInput lMMURequestInput <- mkMMURequestInput;
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationOutput.ifc);
   mkConnection(lMMURequestInput.pipes, lMMU.request);

   MemServerIndicationOutput lMemServerIndicationOutput <- mkMemServerIndicationOutput;
   MemServerRequestInput lMemServerRequestInput <- mkMemServerRequestInput;
   MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(top.readers, top.writers, cons(lMMU,nil), lMemServerIndicationOutput.ifc);
   mkConnection(lMemServerRequestInput.pipes, lMemServer.request);

   let lMMUIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(IfcNames_MMUIndicationH2S)), lMMUIndicationOutput.portalIfc.indications, lMMUIndicationOutput.portalIfc.messageSize);
   let lMMURequestInputNoc <- mkPortalMsgRequest(extend(pack(IfcNames_MMURequestS2H)), lMMURequestInput.portalIfc.requests);
   let lMemServerIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(IfcNames_MemServerIndicationH2S)), lMemServerIndicationOutput.portalIfc.indications, lMemServerIndicationOutput.portalIfc.messageSize);
   let lMemServerRequestInputNoc <- mkPortalMsgRequest(extend(pack(IfcNames_MemServerRequestS2H)), lMemServerRequestInput.portalIfc.requests);

   mapM_(mkXsimSink, append(top.requests, append(vec(lMMURequestInputNoc), vec(lMemServerRequestInputNoc))));
   mapM_(mkXsimSource, append(top.indications, append(vec(lMMUIndicationOutputNoc), vec(lMemServerIndicationOutputNoc))));
   mapM_(mkXsimMemoryConnection, lMemServer.masters);
endmodule

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import ConnectalConfig::*;
import Vector            :: *;
import GetPut::*;
import Connectable::*;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes:: *;
import MMU:: *;
import MemServer:: *;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import SimDma::*;
import IfcNames::*;
import BuildVector::*;

`include "ConnectalProjectConfig.bsv"

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimSource;
    method Action beat(Bit#(32) v);
endinterface
import "BVI" XsimSource =
module mkXsimSourceBVI#(Bit#(32) portal)(XsimSource);
    port portal = portal;
    method beat(beat) enable(en_beat);
endmodule
module mkXsimSource#(PortalMsgIndication indication)(Empty);
   let tmp <- mkXsimSourceBVI(indication.id);
   rule ind_dst_rdy;
      indication.message.deq();
      tmp.beat(indication.message.first());
   endrule
endmodule

interface MsgSinkR#(numeric type bytes_per_beat);
   method ActionValue#(Bit#(32)) beat();
endinterface

import "BVI" XsimSink =
module mkXsimSinkBVI#(Bit#(32) portal)(MsgSinkR#(4));
   port portal = portal;
   method beat beat() enable (EN_beat) ready (RDY_beat);
endmodule
module mkXsimSink#(PortalMsgRequest request)(MsgSinkR#(4));
   let sink <- mkXsimSinkBVI(request.id);

   rule req_src_rdy;
      let beat <- sink.beat();
      request.message.enq(beat);
   endrule
endmodule

module mkXsimMemoryConnection#(PhysMemMaster#(addrWidth, dataWidth) master)(Empty)
   provisos (Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     Mul#(TDiv#(dataWidth, 32), 32, dataWidth),
	     Add#(a__, TDiv#(DataBusWidth,8), TDiv#(dataWidth, 8)),
	     Mul#(TDiv#(dataWidth, 32), 4, TDiv#(dataWidth, 8)));
   PhysMemSlave#(addrWidth,dataWidth) slave <- mkSimDmaDmaMaster();
   mkConnection(master, slave);
endmodule

module mkXsimTop#(Clock derivedClock, Reset derivedReset)(Empty);

   Reg#(Bool) dumpstarted <- mkReg(False);
   rule startdump if (!dumpstarted);
      //$dumpfile("dump.vcd");
      //$dumpvars;
      $display("XsimTop starting");
      dumpstarted <= True;
   endrule
   XsimHost host <- mkXsimHost(derivedClock, derivedReset);
   let top <- mkCnocTop(
`ifdef IMPORT_HOSTIF
       host
`else
`ifdef IMPORT_HOST_CLOCKS // enables synthesis boundary
       derivedClock, derivedReset
`else
// otherwise no params
`endif
`endif
       );

   MMUIndicationOutput lMMUIndicationOutput <- mkMMUIndicationOutput;
   MMURequestInput lMMURequestInput <- mkMMURequestInput;
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationOutput.ifc);
   mkConnection(lMMURequestInput.pipes, lMMU.request);

   MemServerIndicationOutput lMemServerIndicationOutput <- mkMemServerIndicationOutput;
   MemServerRequestInput lMemServerRequestInput <- mkMemServerRequestInput;
   MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(top.readers, top.writers, cons(lMMU,nil), lMemServerIndicationOutput.ifc);
   mkConnection(lMemServerRequestInput.pipes, lMemServer.request);

   let lMMUIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(IfcNames_MMUIndicationH2S)), lMMUIndicationOutput.portalIfc.indications, lMMUIndicationOutput.portalIfc.messageSize);
   let lMMURequestInputNoc <- mkPortalMsgRequest(extend(pack(IfcNames_MMURequestS2H)), lMMURequestInput.portalIfc.requests);
   let lMemServerIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(IfcNames_MemServerIndicationH2S)), lMemServerIndicationOutput.portalIfc.indications, lMemServerIndicationOutput.portalIfc.messageSize);
   let lMemServerRequestInputNoc <- mkPortalMsgRequest(extend(pack(IfcNames_MemServerRequestS2H)), lMemServerRequestInput.portalIfc.requests);

   mapM_(mkXsimSink, append(top.requests, append(vec(lMMURequestInputNoc), vec(lMemServerRequestInputNoc))));
   mapM_(mkXsimSource, append(top.indications, append(vec(lMMUIndicationOutputNoc), vec(lMemServerIndicationOutputNoc))));
   mapM_(mkXsimMemoryConnection, lMemServer.masters);
endmodule


import AxiSlaveEngine

import AxiSlaveEngine

Change-Id: Iea0c06d510bd938cf1e3b14f7c258175948455d4

// 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 Connectable       :: *;
import Xilinx            :: *;
//import XilinxPCIE        :: *;
import PcieToAxiBridge   :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiSlaveEngine    :: *;

typedef (function Module#(PortalTop#(40, dsz, ipins)) mkPortalTop()) MkPortalTop#(numeric type dsz, type ipins);

`ifdef Artix7
typedef 4 PcieLanes;
typedef 4 NumLeds;
`else
typedef 8 PcieLanes;
typedef 8 NumLeds;
`endif

interface PcieTop#(type ipins);
   (* prefix="PCIE" *)
   interface PCIE_EXP#(PcieLanes) pcie;
   (* always_ready *)
   method Bit#(NumLeds) leds();
   interface ipins       pins;
endinterface

(* no_default_clock, no_default_reset *)
module [Module] mkPcieTopFromPortal #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
				      Clock sys_clk_p,     Clock sys_clk_n,
				      Reset pci_sys_reset_n,
				      MkPortalTop#(dsz, ipins) mkPortalTop)
   (PcieTop#(ipins))
   provisos (Mul#(TDiv#(dsz, 32), 32, dsz),
	     Add#(b__, 32, dsz),
	     Add#(c__, dsz, 256),
	     Add#(d__, TMul#(8, TDiv#(dsz, 32)), 64),
	     Add#(e__, TMul#(32, TDiv#(dsz, 32)), 256),
	     Add#(f__, TDiv#(dsz, 32), 8)
      );

   let contentId = 0;

   X7PcieBridgeIfc#(PcieLanes) x7pcie <- mkX7PcieBridge( pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,
							contentId );

   Reg#(Bool) interruptRequested <- mkReg(False, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // instantiate user portals
   let portalTop <- mkPortalTop(clocked_by x7pcie.clock125, reset_by x7pcie.portalReset);
   let m_axi = portalTop.m_axi;
   AxiSlaveEngine#(dsz) axiSlaveEngine <- mkAxiSlaveEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(x7pcie.slave), tpl_2(axiSlaveEngine.tlps), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(axiSlaveEngine.tlps), tpl_2(x7pcie.slave), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(portalTop.m_axi, axiSlaveEngine.slave3, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(x7pcie.portal0, portalTop.ctrl, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   rule requestInterrupt;
      if (portalTop.interrupt && !interruptRequested)
	 x7pcie.interrupt();
      interruptRequested <= portalTop.interrupt;
   endrule

   interface pcie = x7pcie.pcie;
   //interface ddr3 = x7pcie.ddr3;
   method Bit#(NumLeds) leds();
      return extend({pack(x7pcie.isLinkUp()),3'd2});
   endmethod
   interface pins = portalTop.pins;

endmodule: mkPcieTopFromPortal

// 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 Connectable       :: *;
import Xilinx            :: *;
//import XilinxPCIE        :: *;
import PcieToAxiBridge   :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;

typedef (function Module#(PortalTop#(40, dsz, ipins)) mkPortalTop()) MkPortalTop#(numeric type dsz, type ipins);

`ifdef Artix7
typedef 4 PcieLanes;
typedef 4 NumLeds;
`else
typedef 8 PcieLanes;
typedef 8 NumLeds;
`endif

interface PcieTop#(type ipins);
   (* prefix="PCIE" *)
   interface PCIE_EXP#(PcieLanes) pcie;
   (* always_ready *)
   method Bit#(NumLeds) leds();
   interface ipins       pins;
endinterface

(* no_default_clock, no_default_reset *)
module [Module] mkPcieTopFromPortal #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
				      Clock sys_clk_p,     Clock sys_clk_n,
				      Reset pci_sys_reset_n,
				      MkPortalTop#(dsz, ipins) mkPortalTop)
   (PcieTop#(ipins))
   provisos (Mul#(TDiv#(dsz, 32), 32, dsz),
	     Add#(b__, 32, dsz),
	     Add#(c__, dsz, 256),
	     Add#(d__, TMul#(8, TDiv#(dsz, 32)), 64),
	     Add#(e__, TMul#(32, TDiv#(dsz, 32)), 256),
	     Add#(f__, TDiv#(dsz, 32), 8)
      );

   let contentId = 0;

   X7PcieBridgeIfc#(PcieLanes) x7pcie <- mkX7PcieBridge( pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,
							contentId );

   Reg#(Bool) interruptRequested <- mkReg(False, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // instantiate user portals
   let portalTop <- mkPortalTop(clocked_by x7pcie.clock125, reset_by x7pcie.portalReset);
   let m_axi = portalTop.m_axi;
   AxiSlaveEngine#(dsz) axiSlaveEngine <- mkAxiSlaveEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(x7pcie.slave), tpl_2(axiSlaveEngine.tlps), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(axiSlaveEngine.tlps), tpl_2(x7pcie.slave), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(portalTop.m_axi, axiSlaveEngine.slave3, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(x7pcie.portal0, portalTop.ctrl, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   rule requestInterrupt;
      if (portalTop.interrupt && !interruptRequested)
	 x7pcie.interrupt();
      interruptRequested <= portalTop.interrupt;
   endrule

   interface pcie = x7pcie.pcie;
   //interface ddr3 = x7pcie.ddr3;
   method Bit#(NumLeds) leds();
      return extend({pack(x7pcie.isLinkUp()),3'd2});
   endmethod
   interface pins = portalTop.pins;

endmodule: mkPcieTopFromPortal


added mkSyncBlueScope handling separate control and trace clock domains

// 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 Clocks::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import Gray              ::*;
import GrayCounter       ::*;

interface BlueScope#(type dataWidth, type triggerWidth);
    method Action setTriggerMask(Bit#(triggerWidth) mask);
    method Action setTriggerValue(Bit#(triggerWidth) value);
    method Action start();
    method Action clear();
    method Action dataIn(Bit#(dataWidth) d, Bit#(triggerWidth) t);
    method ActionValue#(Bit#(dataWidth)) dataOut;
    method Bit#(32) sampleCount();
    method Bool triggered();
endinterface

typedef enum { Idle, Enabled, Running } State deriving (Bits,Eq);

module mkBlueScope#(Integer samples)(BlueScope#(dataWidth, triggerWidth)) provisos (Add#(1,a,dataWidth));
    FIFO#(Bit#(dataWidth)) dfifo <- mkSizedBRAMFIFO(samples);
    Reg#(Bit#(triggerWidth)) maskReg <- mkReg(0);
    Reg#(Bit#(triggerWidth)) valueReg <- mkReg(0);

    Reg#(State) stateReg <- mkReg(Idle);
    Reg#(Bit#(32)) sampleCountReg <- mkReg(0);

    method Action setTriggerMask(Bit#(triggerWidth) mask);
        maskReg <= mask;
    endmethod
    method Action setTriggerValue(Bit#(triggerWidth) value);
        valueReg <= value;
    endmethod
    method Action start();
        stateReg <= Enabled;
    endmethod
    method Action clear();
        dfifo.clear();
	stateReg <= Idle;
	sampleCountReg <= 0;
    endmethod
    method Action dataIn(Bit#(dataWidth) d, Bit#(triggerWidth) t) if (stateReg != Idle);
        State s = stateReg;
        if (s == Enabled && ((t & maskReg) == (valueReg & maskReg)))
	begin
	    s = Running;
	    stateReg <= s;
        end
	if (s == Running)
	begin
	    dfifo.enq(d);
	    sampleCountReg <= sampleCountReg + 1;
	end
    endmethod
    method ActionValue#(Bit#(dataWidth)) dataOut;
        dfifo.deq;
        return dfifo.first;
    endmethod
    method Bit#(32) sampleCount();
        return sampleCountReg;
    endmethod
endmodule

module mkSyncBlueScope#(Integer samples, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScope#(dataWidth, triggerWidth)) provisos (Add#(1,a,dataWidth));
    SyncFIFOIfc#(Bit#(dataWidth)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sRst, dClk, dRst);
    Reg#(Bit#(triggerWidth)) maskReg <- mkSyncReg(0, dClk, dRst, sClk);
    Reg#(Bit#(triggerWidth)) valueReg <- mkSyncReg(0, dClk, dRst, sClk);
    Reg#(Bit#(1)) triggeredReg <- mkReg(0, clocked_by dClk, reset_by dRst);

    SyncPulseIfc enablePulse <- mkSyncPulse(dClk, dRst, sClk);
    SyncPulseIfc resetPulse <- mkSyncPulse(dClk, dRst, sClk);
    SyncPulseIfc triggeredPulse <- mkSyncPulse(sClk, sRst, dClk);
    Reg#(State) stateReg <- mkReg(Idle, clocked_by sClk, reset_by sRst);
    GrayCounter#(32) sampleCountReg <- mkGrayCounter(unpack(0), dClk, dRst, clocked_by sClk, reset_by sRst);

    rule reset if (resetPulse.pulse == True);
        stateReg <= Idle;
	sampleCountReg.sWriteBin(unpack(0));
    endrule
    rule enable if (enablePulse.pulse == True);
        stateReg <= Enabled;
    endrule
    rule triggeredRule if (triggeredPulse.pulse == True);
        triggeredReg <= 1;
    endrule

    method Action setTriggerMask(Bit#(triggerWidth) mask);
        maskReg <= mask;
    endmethod
    method Action setTriggerValue(Bit#(triggerWidth) value);
        valueReg <= value;
    endmethod
    method Action start();
	enablePulse.send;
    endmethod
    method Action clear();
        // not in SyncFIFOIfc dfifo.clear();
	resetPulse.send;
	triggeredReg <= 0;
    endmethod
    method Action dataIn(Bit#(dataWidth) d, Bit#(triggerWidth) t) if (stateReg != Idle);
        State s = stateReg;
	if (!dfifo.notFull)
	begin
	    s = Idle;
	end

        if (s == Enabled && ((t & maskReg) == (valueReg & maskReg)))
	begin
	    s = Running;
	    triggeredPulse.send;
        end
	if (s == Running)
	begin
	    dfifo.enq(d);
	    sampleCountReg.incr;
	end
	stateReg <= s;
    endmethod
    method ActionValue#(Bit#(dataWidth)) dataOut;
        dfifo.deq;
        return dfifo.first;
    endmethod
    method Bit#(32) sampleCount();
        return sampleCountReg.dReadBin();
    endmethod
    method Bool triggered();
        return triggeredReg() == 1 ? True : False;
    endmethod
endmodule

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

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

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

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

import FIFOF::*;
import BRAMFIFO::*;

interface BlueScope#(type dataWidth, type triggerWidth);
    method Action setTriggerMask(Bit#(triggerWidth) mask);
    method Action setTriggerValue(Bit#(triggerWidth) value);
    method Action start();
    method Action clear();
    method Action dataIn(Bit#(dataWidth) d, Bit#(triggerWidth) t);
    method ActionValue#(Bit#(dataWidth)) dataOut;
    method Bit#(32) sampleCount();
endinterface

typedef enum { Idle, Enabled, Running } State deriving (Bits,Eq);

module mkBlueScope#(Integer samples)(BlueScope#(dataWidth, triggerWidth)) provisos (Add#(1,a,dataWidth));
    FIFOF#(Bit#(dataWidth)) dfifo <- mkSizedBRAMFIFOF(samples);
    Reg#(Bit#(triggerWidth)) maskReg <- mkReg(0);
    Reg#(Bit#(triggerWidth)) valueReg <- mkReg(0);

    Reg#(State) stateReg <- mkReg(Idle);
    Reg#(Bit#(32)) sampleCountReg <- mkReg(0);

    method Action setTriggerMask(Bit#(triggerWidth) mask);
        maskReg <= mask;
    endmethod
    method Action setTriggerValue(Bit#(triggerWidth) value);
        valueReg <= value;
    endmethod
    method Action start();
        stateReg <= Enabled;
    endmethod
    method Action clear();
        dfifo.clear();
	stateReg <= Idle;
	sampleCountReg <= 0;
    endmethod
    method Action dataIn(Bit#(dataWidth) d, Bit#(triggerWidth) t) if (stateReg != Idle);
        State s = stateReg;
        if (s == Enabled && ((t & maskReg) == (valueReg & maskReg)))
	begin
	    s = Running;
	    stateReg <= s;
        end
	if (s == Running)
	begin
	    dfifo.enq(d);
	    sampleCountReg <= sampleCountReg + 1;
	end
    endmethod
    method ActionValue#(Bit#(dataWidth)) dataOut;
        dfifo.deq;
        return dfifo.first;
    endmethod
    method Bit#(32) sampleCount();
        return sampleCountReg;
    endmethod
endmodule


handle wrap around

handle wrap around

Change-Id: I0d9ff505111691d4aac07e7a3651d1b7fc844c9b

// 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 FIFO::*;
import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import CtrlMux::*;

import Pipe::*;
import Portal::*;
import MemTypes::*;
import AddressGenerator::*;
import MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import ConnectalMemory::*;

typedef struct {
    Bit#(1) select;
    Bit#(6) tag;
} ReadReqInfo deriving (Bits);

interface PortalCtrlMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemSlave#(addrWidth, dataWidth) memSlave;
   interface ReadOnly#(Bool) interrupt;
   interface WriteOnly#(Bool) top;
endinterface

module mkPortalCtrlMemSlave#(Bit#(dataWidth) ifcId,
			     Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indicationPipes)(PortalCtrlMemSlave#(addrWidth, dataWidth))
   provisos( Add#(a__, 1, dataWidth)
	    ,Div#(dataWidth, 8, b__)
	    ,Bits#(MemData#(dataWidth), c__)
	    ,Add#(d__, dataWidth, TMul#(dataWidth, 2))
	    );

   AddressGenerator#(addrWidth,dataWidth) ctrlReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) ctrlWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(MemData#(dataWidth))        ctrlWriteDataFifo <- mkFIFO();
   FIFO#(Bit#(MemTagSize))        ctrlWriteDoneFifo <- mkFIFO();
   Reg#(Bool) topR <- mkReg(True);

   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, indicationPipes);

   Reg#(Bool) interruptEnableReg <- mkReg(False);
   Bool      interruptStatus = False;
   Reg#(Bit#(TMul#(dataWidth,2))) cycle_count <- mkReg(0);
   Reg#(Bit#(dataWidth))    snapshot <- mkReg(0);

   Bit#(dataWidth)  readyChannel = -1;
   for (Integer i = 0; i < valueOf(numIndications); i = i + 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   rule writeDataRule;
      let d <- toGet(ctrlWriteDataFifo).get();
      let b <- ctrlWriteAddrGenerator.addrBeat.get();
      //$display("mkCtrl.writeData addr=%h data=%h last=%d", b.addr, d.data, b.last);
      let v = d.data;
      let addr = b.addr;
      if (addr == 'h000)
	 noAction;
      if (addr == 'h004)
	 interruptEnableReg <= v[0] == 1'd1;
      if (b.last)
	 ctrlWriteDoneFifo.enq(b.tag);
   endrule

   interface PhysMemSlave memSlave;
      interface PhysMemReadServer read_server;
	 interface Put readReq = ctrlReadAddrGenerator.request;
	 interface Get readData;
	    method ActionValue#(MemData#(dataWidth)) get();
	       let b <- ctrlReadAddrGenerator.addrBeat.get();
	       let addr = b.addr;
	       let v = 'h05a05a0;
	       if (addr == 'h000)
		  v = interruptStatus ? 1 : 0;
	       if (addr == 'h004)
		  v = interruptEnableReg ? 1 : 0;
	       if (addr == 'h008)
		  v = 7;
               if (addr == 'h00C) begin
		  if (interruptStatus)
		     v = readyChannel+1;
		  else
		     v = 0;
               end
	       if (addr == 'h010)
		  v = ifcId;
	       if (addr == 'h014)
		  v = extend(pack(topR));
	       if (addr == 'h018) begin
		  snapshot <= truncate(cycle_count);
		  v = truncate(cycle_count>>valueOf(dataWidth));
	       end
	       if (addr == 'h01C)
		  v = snapshot;
	       //$display("mkCtrl.readData addr=%h data=%h", b.addr, v);
	       return MemData { data: v, tag: b.tag, last: b.last };
	    endmethod
	 endinterface
      endinterface: read_server
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = ctrlWriteAddrGenerator.request;
	 interface Put writeData;
	    method Action put(MemData#(dataWidth) d);
	       ctrlWriteDataFifo.enq(d);
	    endmethod
	 endinterface
	 interface Get writeDone;
	    method ActionValue#(Bit#(MemTagSize)) get();
	       let tag <- toGet(ctrlWriteDoneFifo).get();
	       return tag;
	    endmethod
	 endinterface
      endinterface: write_server
   endinterface: memSlave
   interface ReadOnly interrupt;
      method Bool _read();
	 return interruptStatus && interruptEnableReg;
      endmethod
   endinterface
   interface WriteOnly top;
      method Action _write(Bool v);
	 topR <= v;
      endmethod
   endinterface
endmodule

module mkPipeInMemSlave#(PipeIn#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));

   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))        fifoWriteDoneFifo <- mkFIFO();

   interface PhysMemReadServer read_server;
      interface Put readReq = fifoReadAddrGenerator.request;
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let b <- fifoReadAddrGenerator.addrBeat.get();
	    let v = 0;
	    if (b.addr[7:0] == 4)
	       v = extend(pack(methodPipe.notFull()));
	    return MemData { data: v, tag: b.tag, last: b.last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeInMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	    methodPipe.enq(d.data);
	    // this used to be where we triggered putFailed
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkPipeOutMemSlave#(PipeOut#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));
   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                  fifoWriteDoneFifo <- mkFIFO();
   FIFO#(MemData#(dataWidth))                   fifoReadDataFifo <- mkFIFO();
   rule readDataRule;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      let v = 0;
      if (b.addr[7:0] == 0)
	 v <- toGet(methodPipe).get();
      else if (b.addr[7:0] == 4)
	 v = extend(pack(methodPipe.notEmpty()));
      //$display("mkPipeOutMemSlave.readData.get addr=%h data=%h", b.addr, data);
      fifoReadDataFifo.enq(MemData { data: v, tag: b.tag, last: b.last });
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(addrWidth) req);
	    fifoReadAddrGenerator.request.put(req);
	    if (!methodPipe.notEmpty())
	       $display("***\n\n mkPipeOutMemSlave.read_server.underflow! \n\n****");
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let d <- toGet(fifoReadDataFifo).get();
	    return d;
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeOutMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkMemPortal#(Bit#(slaveDataWidth) ifcId,
		    PipePortal#(numRequests, numIndications, slaveDataWidth) portal)(MemPortal#(slaveAddrWidth, slaveDataWidth))
   provisos ( Add#(1, i__, slaveDataWidth)
	     ,Add#(c__, 8, slaveAddrWidth)
	     ,Add#(d__, 1, c__)
	     ,Add#(a__, TLog#(TAdd#(1, TAdd#(numRequests, numIndications))), c__)
	     ,Add#(b__, slaveDataWidth, TMul#(slaveDataWidth, 2))
	     );

   Vector#(numRequests,    PipeIn#(Bit#(slaveDataWidth)))     requestPipes = portal.requests;
   Vector#(numIndications, PipeOut#(Bit#(slaveDataWidth))) indicationPipes = portal.indications;
   Vector#(numRequests,    PhysMemSlave#(8, slaveDataWidth))    requestMemSlaves <- mapM(mkPipeInMemSlave, requestPipes);
   Vector#(numIndications, PhysMemSlave#(8, slaveDataWidth)) indicationMemSlaves <- mapM(mkPipeOutMemSlave, indicationPipes);

   PortalCtrlMemSlave#(8,slaveDataWidth) ctrlPort <- mkPortalCtrlMemSlave(ifcId, indicationPipes);
   PhysMemSlave#(slaveAddrWidth,slaveDataWidth) memslave  <- mkMemSlaveMux(cons(ctrlPort.memSlave,append(requestMemSlaves, indicationMemSlaves)));
   interface PhysMemSlave slave = memslave;
   interface ReadOnly interrupt = ctrlPort.interrupt;
   interface WriteOnly top = ctrlPort.top;
endmodule

typedef enum {
   Idle,
   HeadRequested,
   TailRequested,
   RequestMessage,
   MessageHeaderRequested,
   MessageRequested,
   UpdateTail,
   Waiting,
   Stop
   } SharedMemoryPortalState deriving (Bits,Eq);

module mkSharedMemoryPortal#(PipePortal#(numRequests, numIndications, 32) portal)(SharedMemoryPortal#(64));

   MemreadEngineV#(64,2,2) readEngine <- mkMemreadEngine();
   MemwriteEngineV#(64,2,2) writeEngine <- mkMemwriteEngine();

   Bool verbose = False;

   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);

   if (valueOf(numRequests) > 0) begin
      // read the head and tail pointers, if they are different, then read a request
      Reg#(Bit#(32)) reqLimitReg <- mkReg(0);
      Reg#(Bit#(32)) reqHeadReg <- mkReg(0);
      Reg#(Bit#(32)) reqTailReg <- mkReg(0);
      Reg#(Bit#(16)) wordCountReg <- mkReg(0);
      Reg#(Bit#(16)) demuxCountReg <- mkReg(0);
      Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
      Reg#(Bit#(16)) methodIdReg <- mkReg(0);
      Reg#(SharedMemoryPortalState) reqState <- mkReg(Idle);

      rule updateReqHeadTail if (reqState == Idle && readyReg);
	 //$display("updateReqHeadTail");
	 readEngine.readServers[0].request.put(MemengineCmd { sglId: sglIdReg,
							     base: 0,
							     burstLen: 16,
							     len: 16
							     });
	 reqState <= HeadRequested;
      endrule

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

      rule requestMessage if (reqState == RequestMessage);
	 Bit#(32) wordCount = reqHeadReg - reqTailReg;
	 if ((reqTailReg & 1) == 1) begin
	    $display("WARNING requestMessage: reqTail=%d is odd.", reqTailReg);
	 end
	 let tail = reqTailReg + wordCount;
	 if (reqHeadReg < reqTailReg) begin
	    $display("requestMessage wrapped: head=%d tail=%d", reqHeadReg, reqTailReg);
	    wordCount = reqLimitReg - reqTailReg;
	    tail = 4;
	 end
	 //$display("requestMessage id=%d tail=%h wordCount=%d", sglIdReg, reqTailReg, wordCount);

	 reqTailReg <= tail;
	 wordCountReg <= truncate(wordCount);
	 demuxCountReg <= truncate(wordCount);
	 let fetchCount = wordCount;
	 if ((fetchCount & 1) == 1)
	    fetchCount = fetchCount + 1;
	 readEngine.readServers[0].request.put(MemengineCmd {sglId: sglIdReg,
							     base: extend(reqTailReg << 2),
							     burstLen: 16,
							     len: fetchCount << 2
							     });
	 reqState <= MessageHeaderRequested;
      endrule

      FIFOF#(Vector#(2,Maybe#(Bit#(32)))) readFifo <- mkFIFOF();
      rule demuxwords;
	 let data <- toGet(readEngine.dataPipes[0]).get();
	 Vector#(2,Bit#(32)) dvec = unpack(data);
	 function Maybe#(a) toValid(a in); return tagged Valid in; endfunction
	 Vector#(2,Maybe#(Bit#(32))) mvec = map(toValid, dvec);
	 let demuxCount = demuxCountReg - 2;
	 if (demuxCountReg == 1) begin
	    mvec[1] = tagged Invalid;
	    demuxCount = 0;
	 end
	 demuxCountReg <= demuxCount;
	 readFifo.enq(mvec);
      endrule

      PipeOut#(Vector#(2,Maybe#(Bit#(32)))) readPipe2 = toPipeOut(readFifo);
      PipeOut#(Maybe#(Bit#(32))) readPipe <- mkFunnel1(readPipe2);

      rule receiveMessageHeader if (reqState == MessageHeaderRequested);
	 let maybehdr <- toGet(readPipe).get();
	 if (maybehdr matches tagged Valid .hdr) begin
	     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, wordCountReg);
	     wordCountReg <= wordCountReg - 1;
	     messageWordsReg <= messageWords - 1;
	     if (wordCountReg <= 1)
		reqState <= UpdateTail;
	     else if (messageWords <= 1)
		reqState <= MessageHeaderRequested;
	     else
		reqState <= MessageRequested;
	 end
	 else begin
	    //$display("receiveMessageHeader tagged invalid %x wordCountReg", maybehdr, wordCountReg);
	    reqState <= UpdateTail;
	 end
      endrule

      //GearBox(Bit#(64),Bit#(32)) gb <- mkNto1Gearbox(defaultClock,defaultReset,defaultClock,defaultReset);
      rule receiveMessage if (reqState == MessageRequested);
	 let maybedata <- toGet(readPipe).get();
	 if (maybedata matches tagged Valid .data) begin
	    //$display("receiveMessage data=%x messageWords=%d wordCount=%d", data, messageWordsReg, wordCountReg);
	     portal.requests[methodIdReg].enq(data);

	     messageWordsReg <= messageWordsReg - 1;
	     wordCountReg <= wordCountReg - 1;
	     if (messageWordsReg <= 1)
		reqState <= MessageHeaderRequested;
	     else if (wordCountReg <= 1)
		reqState <= UpdateTail;
	 end
	 else begin
	    //$display("receiveMessage tagged Invalid %x", maybedata);
	    reqState <= UpdateTail;
	 end
      endrule

      rule updateTail if (reqState == UpdateTail);
	 //$display("updateTail: tail=%d", reqTailReg);
	 // update the tail pointer
	 writeEngine.writeServers[0].request.put(MemengineCmd {sglId: sglIdReg,
							       base: 8,
							       len: 8,
							       burstLen: 8
							       });
	 writeEngine.dataPipes[0].enq(extend(reqTailReg));
	 reqState <= Waiting;
      endrule
      rule waiting if (reqState == Waiting);
	 let done <- writeEngine.writeServers[0].response.get();
	 //$display("done waiting for write");
	 reqState <= Idle;
      endrule

      rule consumeResponse;
	 let response <- readEngine.readServers[0].response.get();
      endrule

   end
   if (valueOf(numIndications) > 0) begin
   end
   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
	 $display("setSglId id=%d", id);
	 sglIdReg <= id;
	 readyReg <= True;
      endmethod
   endinterface
   interface MemReadClient  readClient = readEngine.dmaClient;
   interface MemWriteClient writeClient = writeEngine.dmaClient;
   interface ReadOnly interrupt;
   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 FIFO::*;
import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import CtrlMux::*;

import Pipe::*;
import Portal::*;
import MemTypes::*;
import AddressGenerator::*;
import MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import ConnectalMemory::*;

typedef struct {
    Bit#(1) select;
    Bit#(6) tag;
} ReadReqInfo deriving (Bits);

interface PortalCtrlMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemSlave#(addrWidth, dataWidth) memSlave;
   interface ReadOnly#(Bool) interrupt;
   interface WriteOnly#(Bool) top;
endinterface

module mkPortalCtrlMemSlave#(Bit#(dataWidth) ifcId,
			     Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indicationPipes)(PortalCtrlMemSlave#(addrWidth, dataWidth))
   provisos( Add#(a__, 1, dataWidth)
	    ,Div#(dataWidth, 8, b__)
	    ,Bits#(MemData#(dataWidth), c__)
	    ,Add#(d__, dataWidth, TMul#(dataWidth, 2))
	    );

   AddressGenerator#(addrWidth,dataWidth) ctrlReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) ctrlWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(MemData#(dataWidth))        ctrlWriteDataFifo <- mkFIFO();
   FIFO#(Bit#(MemTagSize))        ctrlWriteDoneFifo <- mkFIFO();
   Reg#(Bool) topR <- mkReg(True);

   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, indicationPipes);

   Reg#(Bool) interruptEnableReg <- mkReg(False);
   Bool      interruptStatus = False;
   Reg#(Bit#(TMul#(dataWidth,2))) cycle_count <- mkReg(0);
   Reg#(Bit#(dataWidth))    snapshot <- mkReg(0);

   Bit#(dataWidth)  readyChannel = -1;
   for (Integer i = 0; i < valueOf(numIndications); i = i + 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   rule writeDataRule;
      let d <- toGet(ctrlWriteDataFifo).get();
      let b <- ctrlWriteAddrGenerator.addrBeat.get();
      //$display("mkCtrl.writeData addr=%h data=%h last=%d", b.addr, d.data, b.last);
      let v = d.data;
      let addr = b.addr;
      if (addr == 'h000)
	 noAction;
      if (addr == 'h004)
	 interruptEnableReg <= v[0] == 1'd1;
      if (b.last)
	 ctrlWriteDoneFifo.enq(b.tag);
   endrule

   interface PhysMemSlave memSlave;
      interface PhysMemReadServer read_server;
	 interface Put readReq = ctrlReadAddrGenerator.request;
	 interface Get readData;
	    method ActionValue#(MemData#(dataWidth)) get();
	       let b <- ctrlReadAddrGenerator.addrBeat.get();
	       let addr = b.addr;
	       let v = 'h05a05a0;
	       if (addr == 'h000)
		  v = interruptStatus ? 1 : 0;
	       if (addr == 'h004)
		  v = interruptEnableReg ? 1 : 0;
	       if (addr == 'h008)
		  v = 7;
               if (addr == 'h00C) begin
		  if (interruptStatus)
		     v = readyChannel+1;
		  else
		     v = 0;
               end
	       if (addr == 'h010)
		  v = ifcId;
	       if (addr == 'h014)
		  v = extend(pack(topR));
	       if (addr == 'h018) begin
		  snapshot <= truncate(cycle_count);
		  v = truncate(cycle_count>>valueOf(dataWidth));
	       end
	       if (addr == 'h01C)
		  v = snapshot;
	       //$display("mkCtrl.readData addr=%h data=%h", b.addr, v);
	       return MemData { data: v, tag: b.tag, last: b.last };
	    endmethod
	 endinterface
      endinterface: read_server
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = ctrlWriteAddrGenerator.request;
	 interface Put writeData;
	    method Action put(MemData#(dataWidth) d);
	       ctrlWriteDataFifo.enq(d);
	    endmethod
	 endinterface
	 interface Get writeDone;
	    method ActionValue#(Bit#(MemTagSize)) get();
	       let tag <- toGet(ctrlWriteDoneFifo).get();
	       return tag;
	    endmethod
	 endinterface
      endinterface: write_server
   endinterface: memSlave
   interface ReadOnly interrupt;
      method Bool _read();
	 return interruptStatus && interruptEnableReg;
      endmethod
   endinterface
   interface WriteOnly top;
      method Action _write(Bool v);
	 topR <= v;
      endmethod
   endinterface
endmodule

module mkPipeInMemSlave#(PipeIn#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));

   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))        fifoWriteDoneFifo <- mkFIFO();

   interface PhysMemReadServer read_server;
      interface Put readReq = fifoReadAddrGenerator.request;
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let b <- fifoReadAddrGenerator.addrBeat.get();
	    let v = 0;
	    if (b.addr[7:0] == 4)
	       v = extend(pack(methodPipe.notFull()));
	    return MemData { data: v, tag: b.tag, last: b.last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeInMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	    methodPipe.enq(d.data);
	    // this used to be where we triggered putFailed
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkPipeOutMemSlave#(PipeOut#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));
   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                  fifoWriteDoneFifo <- mkFIFO();
   FIFO#(MemData#(dataWidth))                   fifoReadDataFifo <- mkFIFO();
   rule readDataRule;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      let v = 0;
      if (b.addr[7:0] == 0)
	 v <- toGet(methodPipe).get();
      else if (b.addr[7:0] == 4)
	 v = extend(pack(methodPipe.notEmpty()));
      //$display("mkPipeOutMemSlave.readData.get addr=%h data=%h", b.addr, data);
      fifoReadDataFifo.enq(MemData { data: v, tag: b.tag, last: b.last });
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(addrWidth) req);
	    fifoReadAddrGenerator.request.put(req);
	    if (!methodPipe.notEmpty())
	       $display("***\n\n mkPipeOutMemSlave.read_server.underflow! \n\n****");
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let d <- toGet(fifoReadDataFifo).get();
	    return d;
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeOutMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkMemPortal#(Bit#(slaveDataWidth) ifcId,
		    PipePortal#(numRequests, numIndications, slaveDataWidth) portal)(MemPortal#(slaveAddrWidth, slaveDataWidth))
   provisos ( Add#(1, i__, slaveDataWidth)
	     ,Add#(c__, 8, slaveAddrWidth)
	     ,Add#(d__, 1, c__)
	     ,Add#(a__, TLog#(TAdd#(1, TAdd#(numRequests, numIndications))), c__)
	     ,Add#(b__, slaveDataWidth, TMul#(slaveDataWidth, 2))
	     );

   Vector#(numRequests,    PipeIn#(Bit#(slaveDataWidth)))     requestPipes = portal.requests;
   Vector#(numIndications, PipeOut#(Bit#(slaveDataWidth))) indicationPipes = portal.indications;
   Vector#(numRequests,    PhysMemSlave#(8, slaveDataWidth))    requestMemSlaves <- mapM(mkPipeInMemSlave, requestPipes);
   Vector#(numIndications, PhysMemSlave#(8, slaveDataWidth)) indicationMemSlaves <- mapM(mkPipeOutMemSlave, indicationPipes);

   PortalCtrlMemSlave#(8,slaveDataWidth) ctrlPort <- mkPortalCtrlMemSlave(ifcId, indicationPipes);
   PhysMemSlave#(slaveAddrWidth,slaveDataWidth) memslave  <- mkMemSlaveMux(cons(ctrlPort.memSlave,append(requestMemSlaves, indicationMemSlaves)));
   interface PhysMemSlave slave = memslave;
   interface ReadOnly interrupt = ctrlPort.interrupt;
   interface WriteOnly top = ctrlPort.top;
endmodule

typedef enum {
   Idle,
   HeadRequested,
   TailRequested,
   RequestMessage,
   MessageHeaderRequested,
   MessageRequested,
   UpdateTail,
   Waiting,
   Stop
   } SharedMemoryPortalState deriving (Bits,Eq);

module mkSharedMemoryPortal#(PipePortal#(numRequests, numIndications, 32) portal)(SharedMemoryPortal#(64));

   MemreadEngineV#(64,2,2) readEngine <- mkMemreadEngine();
   MemwriteEngineV#(64,2,2) writeEngine <- mkMemwriteEngine();

   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);

   if (valueOf(numRequests) > 0) begin
      // read the head and tail pointers, if they are different, then read a request
      Reg#(Bit#(32)) limitReg <- mkReg(0);
      Reg#(Bit#(32)) reqHeadReg <- mkReg(0);
      Reg#(Bit#(32)) reqTailReg <- mkReg(0);
      Reg#(Bit#(16)) wordCountReg <- mkReg(0);
      Reg#(Bit#(16)) demuxCountReg <- mkReg(0);
      Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
      Reg#(Bit#(16)) methodIdReg <- mkReg(0);
      Reg#(SharedMemoryPortalState) reqState <- mkReg(Idle);

      rule updateReqHeadTail if (reqState == Idle && readyReg);
	 $display("updateReqHeadTail");
	 readEngine.readServers[0].request.put(MemengineCmd { sglId: sglIdReg,
							     base: 0,
							     burstLen: 16,
							     len: 16
							     });
	 reqState <= HeadRequested;
      endrule

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

      rule requestMessage if (reqState == RequestMessage);
	 Bit#(32) wordCount = reqHeadReg - reqTailReg;
	 if (reqTailReg < reqHeadReg)
	    $display("requestMessage wrapped: head=%d tail=%d", reqHeadReg, reqTailReg);
	 //$display("requestMessage id=%d tail=%h wordCount=%d", sglIdReg, reqTailReg, wordCount);
	 reqTailReg <= reqTailReg + wordCount;
	 wordCountReg <= truncate(wordCount);
	 demuxCountReg <= truncate(wordCount);
	 let fetchCount = wordCount;
	 if ((fetchCount & 1) == 1)
	    fetchCount = fetchCount + 1;
	 readEngine.readServers[0].request.put(MemengineCmd {sglId: sglIdReg,
							     base: extend(reqTailReg << 2),
							     burstLen: 16,
							     len: fetchCount << 2
							     });
	 reqState <= MessageHeaderRequested;
      endrule

      FIFOF#(Vector#(2,Maybe#(Bit#(32)))) readFifo <- mkFIFOF();
      rule demuxwords;
	 let data <- toGet(readEngine.dataPipes[0]).get();
	 Vector#(2,Bit#(32)) dvec = unpack(data);
	 function Maybe#(a) toValid(a in); return tagged Valid in; endfunction
	 Vector#(2,Maybe#(Bit#(32))) mvec = map(toValid, dvec);
	 let demuxCount = demuxCountReg - 2;
	 if (demuxCountReg == 1) begin
	    mvec[1] = tagged Invalid;
	    demuxCount = 0;
	 end
	 demuxCountReg <= demuxCount;
	 readFifo.enq(mvec);
      endrule

      PipeOut#(Vector#(2,Maybe#(Bit#(32)))) readPipe2 = toPipeOut(readFifo);
      PipeOut#(Maybe#(Bit#(32))) readPipe <- mkFunnel1(readPipe2);

      rule receiveMessageHeader if (reqState == MessageHeaderRequested);
	 let maybehdr <- toGet(readPipe).get();
	 if (maybehdr matches tagged Valid .hdr) begin
	     let methodId = hdr[31:16];
	     let messageWords = hdr[15:0];
	     methodIdReg <= methodId;
	     $display("receiveMessageHeader hdr=%x methodId=%x messageWords=%d wordCount=%d", hdr, methodId, messageWords, wordCountReg);
	     wordCountReg <= wordCountReg - 1;
	     messageWordsReg <= messageWords - 1;
	     if (wordCountReg <= 1)
		reqState <= UpdateTail;
	     else if (messageWords <= 1)
		reqState <= MessageHeaderRequested;
	     else
		reqState <= MessageRequested;
	 end
	 else begin
	    $display("receiveMessageHeader tagged invalid %x", maybehdr);
	 end
      endrule

      //GearBox(Bit#(64),Bit#(32)) gb <- mkNto1Gearbox(defaultClock,defaultReset,defaultClock,defaultReset);
      rule receiveMessage if (reqState == MessageRequested);
	 let maybedata <- toGet(readPipe).get();
	 if (maybedata matches tagged Valid .data) begin
	    //$display("receiveMessage data=%x messageWords=%d wordCount=%d", data, messageWordsReg, wordCountReg);
	     portal.requests[methodIdReg].enq(data);

	     messageWordsReg <= messageWordsReg - 1;
	     wordCountReg <= wordCountReg - 1;
	     if (messageWordsReg <= 1)
		reqState <= MessageHeaderRequested;
	     else if (wordCountReg <= 1)
		reqState <= UpdateTail;
	 end
	 else begin
	    $display("receiveMessage tagged Invalid %x", maybedata);
	 end
      endrule

      rule updateTail if (reqState == UpdateTail);
	 $display("updateTail: tail=%d", reqTailReg);
	 // update the tail pointer
	 writeEngine.writeServers[0].request.put(MemengineCmd {sglId: sglIdReg,
							       base: 8,
							       len: 8,
							       burstLen: 8
							       });
	 writeEngine.dataPipes[0].enq(extend(reqTailReg));
	 reqState <= Waiting;
      endrule
      rule waiting if (reqState == Waiting);
	 let done <- writeEngine.writeServers[0].response.get();
	 $display("done waiting for write");
	 reqState <= Idle;
      endrule

      rule consumeResponse;
	 let response <- readEngine.readServers[0].response.get();
      endrule

   end
   if (valueOf(numIndications) > 0) begin
   end
   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
	 $display("setSglId id=%d", id);
	 sglIdReg <= id;
	 readyReg <= True;
      endmethod
   endinterface
   interface MemReadClient  readClient = readEngine.dmaClient;
   interface MemWriteClient writeClient = writeEngine.dmaClient;
   interface ReadOnly interrupt;
   endinterface
endmodule


pipelined SGList pageResponse

pipelined SGList pageResponse

Change-Id: I27ce2d1ebe18add0ebef20505132792e50f2b6cb

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

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

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

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

// BSV Libraries
import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import Dma::*;
import StmtFSM::*;
import ClientServer::*;
import PortalMemory::*;

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

interface SGListMMU#(numeric type addrWidth);
   method Action sglist(Bit#(32) pointer, Bit#(40) paddr, Bit#(32) len);
   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef union tagged{
   Bit#(SGListPageShift0) OOrd0;
   Bit#(SGListPageShift4) OOrd4;
   Bit#(SGListPageShift8) OOrd8;
} Offset deriving (Eq,Bits,FShow);

typedef union tagged{
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift0)) POrd0;
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) POrd4;
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) POrd8;
} Page deriving (Eq,Bits,FShow);

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

module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))

   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

   BRAM2Port#(Bit#(entryIdxSize),Page) pages <- mkBRAM2Server(defaultValue);
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(defaultValue);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(defaultValue);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- mkBRAM2Server(defaultValue);

   Vector#(2,FIFOF#(Bit#(entryIdxSize)))  rp <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Offset))            offs <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(ReqTup))            reqs <- replicateM(mkFIFOF);
   Vector#(2,FIFO#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFO);
   Reg#(Bit#(8))                      idxReg <- mkReg(0);

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

   let ord0 = 40'd1 << page_shift0;
   let ord4 = 40'd1 << page_shift4;
   let ord8 = 40'd1 << page_shift8;

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

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule req0;
	 reqs[i].deq;
	 let ptr = tpl_1(reqs[i].first);
	 let off = tpl_2(reqs[i].first);
	 Offset o = tagged OOrd0 0;
	 Bit#(8) p = 0;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;
	 Bit#(40) barrier8 = region8.barrier;
	 Bit#(40) barrier4 = region4.barrier;
	 Bit#(40) barrier0 = region0.barrier;

	 if (off < barrier8) begin
	    //$display("request: ptr=%h off=%h barrier8=%h", ptr, off, barrier8);
	    o = tagged OOrd8 truncate(off);
	    p = truncate(off>>page_shift8) + region8.idxOffset;
	 end
	 else if (off < barrier4) begin
	    //$display("request: ptr=%h off=%h barrier4=%h", ptr, off, barrier4);
	    o = tagged OOrd4 truncate(off);
	    p = truncate(off>>page_shift4) + region4.idxOffset;
	 end
	 else if (off < barrier0) begin
	    //$display("request: ptr=%h off=%h barrier0=%h", ptr, off, barrier0);
	    o = tagged OOrd0 truncate(off);
	    p = truncate(off>>page_shift0) + region0.idxOffset;
	 end
	 else begin
	    $display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaIndication.badAddrTrans(extend(ptr), extend(off), barrier0);
	 end
	 offs[i].enq(o);
	 rp[i].enq({ptr-1,p});
      endrule
      rule req1;
	 rp[i].deq;
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:rp[i].first, datain:?});
      endrule
      rule pageResponse;
	 let page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs[i]).get();
	 Bit#(ObjectOffsetSize) rv = 0;
	 case (offset) matches
	    tagged OOrd0 .o:
	       begin
		  case (page) matches
		     tagged POrd4 .p:
			$display("OOrd0 vs POrd4");
		     tagged POrd8 .p:
			$display("OOrd0 vs POrd8");
		  endcase
		  rv = {page.POrd0,o};
	       end
	    tagged OOrd4 .o:
	       begin
		  case (page) matches
		     tagged POrd0 .p:
			$display("OOrd4 vs POrd0");
		     tagged POrd8 .p:
			$display("OOrd4 vs POrd8");
		  endcase
		  rv = {page.POrd4,o};
	       end
	    tagged OOrd8 .o:
	       begin
		  case (page) matches
		     tagged POrd0 .p:
			$display("OOrd8 vs POrd0");
		     tagged POrd4 .p:
			$display("OOrd8 vs POrd4");
		  endcase
		  rv = {page.POrd8,o};
	       end
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		let ptr = tpl_1(req);
		let off = tpl_2(req);
		portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:truncate(ptr-1), datain:?});
		portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:truncate(ptr-1), datain:?});
		portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:truncate(ptr-1), datain:?});
		reqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
      Region region8 = Region { barrier: barr8, idxOffset: off8 };
      Region region4 = Region { barrier: barr4, idxOffset: off4 };
      Region region0 = Region { barrier: barr0, idxOffset: off0 };
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(ptr-1), datain: region8});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(ptr-1), datain: region4});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(ptr-1), datain: region0});
      //$display("region ptr=%d off8=%h off4=%h off0=%h", ptr, off8, off4, off0);
      dmaIndication.configResp(ptr, barr0);
   endmethod

   method Action sglist(Bit#(32) ptr, Bit#(40) paddr, Bit#(32) len);
      // $display("sglist(ptr=%d, paddr=%h, len=%h", ptr, paddr,len);
      if (idxReg+1 == 0) begin
	 $display("sglist: exceeded maximun length of sglist");
	 dmaIndication.badPageSize(ptr,len);
      end
      else begin
	 Page page = tagged POrd0 0;
	 if(len == 0) begin
	    idxReg <= 0;
	 end
	 else begin
	    idxReg <= idxReg+1;
	    if (extend(len) == ord0) begin
	       page = tagged POrd0 truncate(paddr>>page_shift0);
	    end
	    else if (extend(len) == ord4) begin
	       page = tagged POrd4 truncate(paddr>>page_shift4);
	    end
	    else if (extend(len) == ord8) begin
	       page = tagged POrd8 truncate(paddr>>page_shift8);
	    end
	    else begin
	       $display("mkSGListMMU::sglist unsupported length %h", len);
	       dmaIndication.badPageSize(ptr, len);
	    end
	 end
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:{truncate(ptr-1),idxReg}, datain:page});
	 dmaIndication.configResp(ptr, 40'haaaaaaaa);
      end
   endmethod

   interface addr = addrServers;

endmodule

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

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(addrWidth,numServers));

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

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

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

   interface servers = addrServers;

endmodule

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

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

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

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

// BSV Libraries
import RegFile::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import Dma::*;
import StmtFSM::*;
import ClientServer::*;
import PortalMemory::*;

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

interface SGListMMU#(numeric type addrWidth);
   method Action sglist(Bit#(32) pointer, Bit#(40) paddr, Bit#(32) len);
   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef union tagged{
   Bit#(SGListPageShift0) OOrd0;
   Bit#(SGListPageShift4) OOrd4;
   Bit#(SGListPageShift8) OOrd8;
} Offset deriving (Eq,Bits,FShow);

typedef union tagged{
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift0)) POrd0;
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) POrd4;
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) POrd8;
} Page deriving (Eq,Bits,FShow);

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

module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))

   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

   BRAM2Port#(Bit#(entryIdxSize),Page) pages <- mkBRAM2Server(defaultValue);
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(defaultValue);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(defaultValue);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- mkBRAM2Server(defaultValue);

   Vector#(2,FIFOF#(Bit#(entryIdxSize)))  rp <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Offset))            offs <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(ReqTup))            reqs <- replicateM(mkFIFOF);
   Reg#(Bit#(8))                      idxReg <- mkReg(0);

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

   let ord0 = 40'd1 << page_shift0;
   let ord4 = 40'd1 << page_shift4;
   let ord8 = 40'd1 << page_shift8;

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

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule req0;
	 reqs[i].deq;
	 let ptr = tpl_1(reqs[i].first);
	 let off = tpl_2(reqs[i].first);
	 Offset o = tagged OOrd0 0;
	 Bit#(8) p = 0;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;
	 Bit#(40) barrier8 = region8.barrier;
	 Bit#(40) barrier4 = region4.barrier;
	 Bit#(40) barrier0 = region0.barrier;

	 if (off < barrier8) begin
	    //$display("request: ptr=%h off=%h barrier8=%h", ptr, off, barrier8);
	    o = tagged OOrd8 truncate(off);
	    p = truncate(off>>page_shift8) + region8.idxOffset;
	 end
	 else if (off < barrier4) begin
	    //$display("request: ptr=%h off=%h barrier4=%h", ptr, off, barrier4);
	    o = tagged OOrd4 truncate(off);
	    p = truncate(off>>page_shift4) + region4.idxOffset;
	 end
	 else if (off < barrier0) begin
	    //$display("request: ptr=%h off=%h barrier0=%h", ptr, off, barrier0);
	    o = tagged OOrd0 truncate(off);
	    p = truncate(off>>page_shift0) + region0.idxOffset;
	 end
	 else begin
	    $display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaIndication.badAddrTrans(extend(ptr), extend(off), barrier0);
	 end
	 offs[i].enq(o);
	 rp[i].enq({ptr-1,p});
      endrule
      rule req1;
	 rp[i].deq;
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:rp[i].first, datain:?});
      endrule
   end

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		let ptr = tpl_1(req);
		let off = tpl_2(req);
		portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:truncate(ptr-1), datain:?});
		portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:truncate(ptr-1), datain:?});
		portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False, address:truncate(ptr-1), datain:?});
		reqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		Bit#(ObjectOffsetSize) rv = 0;
		let page <- portsel(pages, i).response.get;
		let offset = offs[i].first;
		case (offset) matches
		   tagged OOrd0 .o:
		      begin
			 case (page) matches
			    tagged POrd4 .p:
			       $display("OOrd0 vs POrd4");
			    tagged POrd8 .p:
			       $display("OOrd0 vs POrd8");
			 endcase
			 rv = {page.POrd0,o};
		      end
		   tagged OOrd4 .o:
		      begin
			  case (page) matches
			     tagged POrd0 .p:
				$display("OOrd4 vs POrd0");
			     tagged POrd8 .p:
				$display("OOrd4 vs POrd8");
			  endcase
			  rv = {page.POrd4,o};
		      end
		   tagged OOrd8 .o:
		      begin
			 case (page) matches
			    tagged POrd0 .p:
			       $display("OOrd8 vs POrd0");
			    tagged POrd4 .p:
			       $display("OOrd8 vs POrd4");
			 endcase
			 rv = {page.POrd8,o};
		      end
		endcase
		if (False && rv[31:24] != 0)
		   $display($format("SGList response: funny r",fshow(rv),fshow(offset),fshow(page)));
		offs[i].deq;
		return truncate(rv);
	     endmethod
	  endinterface
       endinterface);

   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
      Region region8 = Region { barrier: barr8, idxOffset: off8 };
      Region region4 = Region { barrier: barr4, idxOffset: off4 };
      Region region0 = Region { barrier: barr0, idxOffset: off0 };
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(ptr-1), datain: region8});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(ptr-1), datain: region4});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(ptr-1), datain: region0});
      //$display("region ptr=%d off8=%h off4=%h off0=%h", ptr, off8, off4, off0);
      dmaIndication.configResp(ptr, barr0);
   endmethod

   method Action sglist(Bit#(32) ptr, Bit#(40) paddr, Bit#(32) len);
      // $display("sglist(ptr=%d, paddr=%h, len=%h", ptr, paddr,len);
      if (idxReg+1 == 0) begin
	 $display("sglist: exceeded maximun length of sglist");
	 dmaIndication.badPageSize(ptr,len);
      end
      else begin
	 Page page = tagged POrd0 0;
	 if(len == 0) begin
	    idxReg <= 0;
	 end
	 else begin
	    idxReg <= idxReg+1;
	    if (extend(len) == ord0) begin
	       page = tagged POrd0 truncate(paddr>>page_shift0);
	    end
	    else if (extend(len) == ord4) begin
	       page = tagged POrd4 truncate(paddr>>page_shift4);
	    end
	    else if (extend(len) == ord8) begin
	       page = tagged POrd8 truncate(paddr>>page_shift8);
	    end
	    else begin
	       $display("mkSGListMMU::sglist unsupported length %h", len);
	       dmaIndication.badPageSize(ptr, len);
	    end
	 end
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False, address:{truncate(ptr-1),idxReg}, datain:page});
	 dmaIndication.configResp(ptr, 40'haaaaaaaa);
      end
   endmethod

   interface addr = addrServers;

endmodule

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

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(addrWidth,numServers));

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

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

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

   interface servers = addrServers;

endmodule