clear finishedReg on start

clear finishedReg on start

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

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

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

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

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

import Arith::*;
import Pipe::*;
import MemTypes::*;
import MemreadEngine::*;
import Pipe::*;
import HostInterface::*; // for DataBusWidth

`ifdef NumEngineServers
typedef `NumEngineServers NumEngineServers;
`else
typedef 1 NumEngineServers;
`endif
`ifdef NumOutstandingRequests
typedef `NumOutstandingRequests NumOutstandingRequests;
`else
typedef 2 NumOutstandingRequests;
`endif
`ifdef MemreadEngineBufferSize
Integer memreadEngineBufferSize=`MemreadEngineBufferSize;
`else
Integer memreadEngineBufferSize=256;
`endif

interface MemreadRequest;
   method Action startRead(Bit#(32) pointer, Bit#(32) offset, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
   method Action getStateDbg();
endinterface

interface Memread;
   interface MemreadRequest request;
   interface MemReadClient#(DataBusWidth) dmaClient;
endinterface

interface MemreadIndication;
   method Action started(Bit#(32) numWords);
   method Action reportStateDbg(Bit#(32) streamRdCnt, Bit#(32) mismatchCount, Bit#(32) finished, Bit#(32) dataPipeNotEmpty);
   method Action readDone(Bit#(32) mismatchCount);
endinterface

typedef TDiv#(DataBusWidth,32) DataBusWords;

module mkMemread#(MemreadIndication indication) (Memread);

   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))       numWords <- mkReg(0);
   Reg#(Bit#(32))       burstLen <- mkReg(0);
   Reg#(Bit#(32))    mismatchCnt <- mkReg(0);
   FIFO#(void)                cf <- mkSizedFIFO(1);

   Reg#(Bit#(32))                                   iterCnt <- mkReg(0);
   Reg#(Bit#(32))                                readOffset <- mkReg(0);
   Vector#(NumEngineServers, Reg#(Bit#(32)))       iterCnts <- replicateM(mkReg(0));
   Vector#(NumEngineServers, Reg#(Bit#(32)))   valuesToRead <- replicateM(mkReg(0));
   Vector#(NumEngineServers, Reg#(Bit#(32))) mismatchCounts <- replicateM(mkReg(0));
   MemreadEngineV#(DataBusWidth,NumOutstandingRequests,NumEngineServers) re <- mkMemreadEngineBuff(memreadEngineBufferSize);
   Vector#(NumEngineServers, FIFOF#(Bit#(32))) mismatchFifos <- replicateM(mkFIFOF);
   Bit#(MemOffsetSize) chunk = (extend(numWords)/fromInteger(valueOf(NumEngineServers)))*4;

   Vector#(NumEngineServers, RangePipeIfc#(Bit#(32)))     rangePipeIfcs <- replicateM(mkRangePipeOut);
   function PipeOut#(a) getRangePipePipe(RangePipeIfc#(a) rpi); return rpi.pipe; endfunction
   Vector#(NumEngineServers, PipeOut#(Vector#(1,Bit#(32)))) rangePipes = map(mapPipe(replicate), map(getRangePipePipe, rangePipeIfcs));
   Vector#(NumEngineServers, PipeOut#(Vector#(DataBusWords,Bit#(32)))) srcGenPipes <- mapM(mkUnfunnel, rangePipes);
   function Vector#(DataBusWords,Bit#(32)) split(Bit#(DataBusWidth) v); return unpack(v); endfunction
   Vector#(NumEngineServers, PipeOut#(Vector#(DataBusWords,Bit#(32)))) readPipes <- mapM(mkMapPipe(split), re.dataPipes);

   function Vector#(n, Bool) vcompare(Vector#(n, a) x, Vector#(n, a) y) provisos (Eq#(a));
      return map(uncurry(eq), zip(x,y));
   endfunction
   Vector#(NumEngineServers, PipeOut#(Vector#(DataBusWords, Bool)))  mismatchPipes <- mapM(uncurry(mkJoinBuffered(vcompare)), zip(readPipes, srcGenPipes));

   Vector#(NumEngineServers, Reg#(Bool)) finishedReg <- replicateM(mkReg(False));

   for(Integer i = 0; i < valueOf(NumEngineServers); i=i+1) begin
      rule start (iterCnts[i] > 0);
	 re.readServers[i].request.put(MemengineCmd{sglId:pointer, base:extend(readOffset)+(fromInteger(i)*chunk), len:truncate(chunk), burstLen:truncate(burstLen*4)});
	 iterCnts[i] <= iterCnts[i]-1;
	 Bit#(32) base = (readOffset/4)+(fromInteger(i)*(truncate(chunk)/4));
	 Bit#(32) limit = base + truncate(chunk)/4;
	 let rangeConfig = RangeConfig { xbase: base, xlimit: limit, xstep: 1 };
	 rangePipeIfcs[i].start(rangeConfig);
	 $display("start %d, %d, %h", i, iterCnts[i], readOffset);
      endrule
      rule finish;
	 $display("finish %d", i);
	 let rv <- re.readServers[i].response.get;
	 finishedReg[i] <= True;
      endrule
      rule check;
	 let bv <- toGet(mismatchPipes[i]).get();
	 let mismatch = !bv[0] || !bv[1];
	 if (mismatch) $display("mismatch bv[0] %d bv[1] %d\n", bv[0], bv[1]);
	 let mc = mismatchCounts[i] + (mismatch ? 1 : 0);

	 let newValuesToRead = valuesToRead[i] - 2;

	 if (valuesToRead[i] <= 2) begin
	    $display("mismatch count %d", mc);
	    mismatchFifos[i].enq(mc);
	    mc = 0; // restart count
	    newValuesToRead = truncate(chunk/4);
	 end
	 mismatchCounts[i] <= mc;
	 valuesToRead[i] <= newValuesToRead;

      endrule
   end

   PipeOut#(Vector#(NumEngineServers, Bit#(32))) mismatchCountsPipe <- mkJoinVector(id, map(toPipeOut, mismatchFifos));
   PipeOut#(Bit#(32)) mismatchCountPipe <- mkReducePipe(uncurry(add), mismatchCountsPipe);

   rule indicate_finish;
      let mc <- toGet(mismatchCountPipe).get();
      mc = mc + mismatchCnt;
      if (iterCnt == 1) begin
	 cf.deq;
	 indication.readDone(mc);
	 mc = 0;
      end
      mismatchCnt <= mc;
      iterCnt <= iterCnt - 1;
   endrule

   interface dmaClient = re.dmaClient;
   interface MemreadRequest request;
      method Action startRead(Bit#(32) rp, Bit#(32) off, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
	 indication.started(nw);
	 pointer <= rp;
	 cf.enq(?);
	 numWords  <= nw;
	 burstLen  <= bl;
	 iterCnt <= ic;
	 readOffset <= off*4;
	 for(Integer i = 0; i < valueOf(NumEngineServers); i=i+1) begin
	    iterCnts[i] <= ic;
	    mismatchCounts[i] <= 0;
	    valuesToRead[i] <= truncate(chunk/4);
	    finishedReg[i] <= False;
	 end
      endmethod
      method Action getStateDbg();
	 Vector#(NumEngineServers, Bool) notEmpty = map(pipeOutNotEmpty, re.dataPipes);
	 indication.reportStateDbg(0, 0,
				   extend(pack(readVReg(finishedReg))),
				   extend(pack(notEmpty)));
      endmethod
   endinterface
endmodule

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

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

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

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

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

import Arith::*;
import Pipe::*;
import MemTypes::*;
import MemreadEngine::*;
import Pipe::*;
import HostInterface::*; // for DataBusWidth

`ifdef NumEngineServers
typedef `NumEngineServers NumEngineServers;
`else
typedef 1 NumEngineServers;
`endif
`ifdef NumOutstandingRequests
typedef `NumOutstandingRequests NumOutstandingRequests;
`else
typedef 2 NumOutstandingRequests;
`endif
`ifdef MemreadEngineBufferSize
Integer memreadEngineBufferSize=`MemreadEngineBufferSize;
`else
Integer memreadEngineBufferSize=256;
`endif

interface MemreadRequest;
   method Action startRead(Bit#(32) pointer, Bit#(32) offset, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
   method Action getStateDbg();
endinterface

interface Memread;
   interface MemreadRequest request;
   interface MemReadClient#(DataBusWidth) dmaClient;
endinterface

interface MemreadIndication;
   method Action started(Bit#(32) numWords);
   method Action reportStateDbg(Bit#(32) streamRdCnt, Bit#(32) mismatchCount, Bit#(32) finished, Bit#(32) dataPipeNotEmpty);
   method Action readDone(Bit#(32) mismatchCount);
endinterface

typedef TDiv#(DataBusWidth,32) DataBusWords;

module mkMemread#(MemreadIndication indication) (Memread);

   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))       numWords <- mkReg(0);
   Reg#(Bit#(32))       burstLen <- mkReg(0);
   Reg#(Bit#(32))    mismatchCnt <- mkReg(0);
   FIFO#(void)                cf <- mkSizedFIFO(1);

   Reg#(Bit#(32))                                   iterCnt <- mkReg(0);
   Reg#(Bit#(32))                                readOffset <- mkReg(0);
   Vector#(NumEngineServers, Reg#(Bit#(32)))       iterCnts <- replicateM(mkReg(0));
   Vector#(NumEngineServers, Reg#(Bit#(32)))   valuesToRead <- replicateM(mkReg(0));
   Vector#(NumEngineServers, Reg#(Bit#(32))) mismatchCounts <- replicateM(mkReg(0));
   MemreadEngineV#(DataBusWidth,NumOutstandingRequests,NumEngineServers) re <- mkMemreadEngineBuff(memreadEngineBufferSize);
   Vector#(NumEngineServers, FIFOF#(Bit#(32))) mismatchFifos <- replicateM(mkFIFOF);
   Bit#(MemOffsetSize) chunk = (extend(numWords)/fromInteger(valueOf(NumEngineServers)))*4;

   Vector#(NumEngineServers, RangePipeIfc#(Bit#(32)))     rangePipeIfcs <- replicateM(mkRangePipeOut);
   function PipeOut#(a) getRangePipePipe(RangePipeIfc#(a) rpi); return rpi.pipe; endfunction
   Vector#(NumEngineServers, PipeOut#(Vector#(1,Bit#(32)))) rangePipes = map(mapPipe(replicate), map(getRangePipePipe, rangePipeIfcs));
   Vector#(NumEngineServers, PipeOut#(Vector#(DataBusWords,Bit#(32)))) srcGenPipes <- mapM(mkUnfunnel, rangePipes);
   function Vector#(DataBusWords,Bit#(32)) split(Bit#(DataBusWidth) v); return unpack(v); endfunction
   Vector#(NumEngineServers, PipeOut#(Vector#(DataBusWords,Bit#(32)))) readPipes <- mapM(mkMapPipe(split), re.dataPipes);

   function Vector#(n, Bool) vcompare(Vector#(n, a) x, Vector#(n, a) y) provisos (Eq#(a));
      return map(uncurry(eq), zip(x,y));
   endfunction
   Vector#(NumEngineServers, PipeOut#(Vector#(DataBusWords, Bool)))  mismatchPipes <- mapM(uncurry(mkJoinBuffered(vcompare)), zip(readPipes, srcGenPipes));

   Vector#(NumEngineServers, Reg#(Bool)) finishedReg <- replicateM(mkReg(False));

   for(Integer i = 0; i < valueOf(NumEngineServers); i=i+1) begin
      rule start (iterCnts[i] > 0);
	 re.readServers[i].request.put(MemengineCmd{sglId:pointer, base:extend(readOffset)+(fromInteger(i)*chunk), len:truncate(chunk), burstLen:truncate(burstLen*4)});
	 iterCnts[i] <= iterCnts[i]-1;
	 Bit#(32) base = (readOffset/4)+(fromInteger(i)*(truncate(chunk)/4));
	 Bit#(32) limit = base + truncate(chunk)/4;
	 let rangeConfig = RangeConfig { xbase: base, xlimit: limit, xstep: 1 };
	 rangePipeIfcs[i].start(rangeConfig);
	 $display("start %d, %d, %h", i, iterCnts[i], readOffset);
      endrule
      rule finish;
	 $display("finish %d", i);
	 let rv <- re.readServers[i].response.get;
	 finishedReg[i] <= True;
      endrule
      rule check;
	 let bv <- toGet(mismatchPipes[i]).get();
	 let mismatch = !bv[0] || !bv[1];
	 if (mismatch) $display("mismatch bv[0] %d bv[1] %d\n", bv[0], bv[1]);
	 let mc = mismatchCounts[i] + (mismatch ? 1 : 0);

	 let newValuesToRead = valuesToRead[i] - 2;

	 if (valuesToRead[i] <= 2) begin
	    $display("mismatch count %d", mc);
	    mismatchFifos[i].enq(mc);
	    mc = 0; // restart count
	    newValuesToRead = truncate(chunk/4);
	 end
	 mismatchCounts[i] <= mc;
	 valuesToRead[i] <= newValuesToRead;

      endrule
   end

   PipeOut#(Vector#(NumEngineServers, Bit#(32))) mismatchCountsPipe <- mkJoinVector(id, map(toPipeOut, mismatchFifos));
   PipeOut#(Bit#(32)) mismatchCountPipe <- mkReducePipe(uncurry(add), mismatchCountsPipe);

   rule indicate_finish;
      let mc <- toGet(mismatchCountPipe).get();
      mc = mc + mismatchCnt;
      if (iterCnt == 1) begin
	 cf.deq;
	 indication.readDone(mc);
	 mc = 0;
      end
      mismatchCnt <= mc;
      iterCnt <= iterCnt - 1;
   endrule

   interface dmaClient = re.dmaClient;
   interface MemreadRequest request;
      method Action startRead(Bit#(32) rp, Bit#(32) off, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
	 indication.started(nw);
	 pointer <= rp;
	 cf.enq(?);
	 numWords  <= nw;
	 burstLen  <= bl;
	 iterCnt <= ic;
	 readOffset <= off*4;
	 for(Integer i = 0; i < valueOf(NumEngineServers); i=i+1) begin
	    iterCnts[i] <= ic;
	    mismatchCounts[i] <= 0;
	    valuesToRead[i] <= truncate(chunk/4);
	 end
      endmethod
      method Action getStateDbg();
	 Vector#(NumEngineServers, Bool) notEmpty = map(pipeOutNotEmpty, re.dataPipes);
	 indication.reportStateDbg(0, 0,
				   extend(pack(readVReg(finishedReg))),
				   extend(pack(notEmpty)));
      endmethod
   endinterface
endmodule


fixed clock domain problem in BlueScope

fixed clock domain problem in BlueScope

Change-Id: I4fe7d1028714e4c31ecfe78f3821e2eafe2eae7e

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

import MemTypes::*;
import MemUtils::*;
import ClientServer::*;

interface BlueScopeIndication;
   method Action triggerFired();
endinterface

interface BlueScopeRequest;
   method Action start(Bit#(32) pointer);
   method Action reset();
   method Action setTriggerMask(Bit#(64) mask);
   method Action setTriggerValue(Bit#(64) value);
endinterface

interface BlueScope#(numeric type dataWidth);
   method Action dataIn(Bit#(dataWidth) d, Bit#(dataWidth) t);
   interface BlueScopeRequest requestIfc;
   interface ObjectWriteClient#(dataWidth) writeClient;
endinterface

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

module mkBlueScope#(Integer samples, BlueScopeIndication indication)(BlueScope#(dataWidth))
   provisos(Add#(a__,dataWidth,64),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Add#(1,b__,dataWidth));

   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;
   let rv  <- mkSyncBlueScope(samples, indication, clk, rst, clk,rst);
   return rv;
endmodule

module mkSyncBlueScope#(Integer samples, BlueScopeIndication indication, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScope#(dataWidth))
   provisos(Add#(a__,dataWidth,64),
	    Add#(1,b__,dataWidth),
	    Mul#(dataBytes, 8, dataWidth),
	    Div#(dataWidth,8,dataBytes));

   SyncFIFOIfc#(Bit#(dataWidth)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sRst, dClk, dRst);
   Reg#(ObjectPointer) pointerReg <- mkReg(0);
   Reg#(Bit#(dataWidth))       maskReg <- mkSyncReg(0, dClk, dRst, sClk);
   Reg#(Bit#(dataWidth))      valueReg <- mkSyncReg(0, dClk, dRst, sClk);
   Reg#(Bit#(1))          triggeredReg <- mkReg(0,    clocked_by sClk, reset_by sRst);
   Reg#(State)                stateReg <- mkReg(Idle, clocked_by sClk, reset_by sRst);
   Reg#(Bit#(32))             countReg <- mkReg(0,    clocked_by sClk, reset_by sRst);
   Reg#(Bit#(ObjectOffsetSize)) writeOffsetReg <- mkReg(0,    clocked_by dClk, reset_by dRst);

   SyncPulseIfc             startPulse <- mkSyncPulse(dClk, dRst, sClk);
   SyncPulseIfc             resetPulse <- mkSyncPulse(dClk, dRst, sClk);
   SyncPulseIfc         triggeredPulse <- mkSyncPulse(sClk, sRst, dClk);

   MemWriter#(dataWidth) mwriter <- mkMemWriter;

   (* descending_urgency = "resetState, startState" *)
   rule resetState if (resetPulse.pulse);
      stateReg <= Idle;
      countReg <= 0;
   endrule

   rule startState if (startPulse.pulse && !resetPulse.pulse);
      stateReg <= Enabled;
   endrule

   rule writeReq if (dfifo.notEmpty);
      let bl = fromInteger(valueOf(dataBytes)) * 2;
      mwriter.writeServer.writeReq.put(ObjectRequest { pointer: pointerReg, offset: zeroExtend(writeOffsetReg), burstLen: bl, tag: 0});
      writeOffsetReg <= writeOffsetReg + bl;
   endrule

   rule  writeData;
      //$display("mkSyncBlueScope::writeData");
      dfifo.deq();
      mwriter.writeServer.writeData.put(ObjectData { data: dfifo.first, tag: 0});
   endrule

   rule writeDone;
      let tag <- mwriter.writeServer.writeDone.get();
   endrule

   rule triggerRule if (triggeredPulse.pulse);
      indication.triggerFired;
   endrule

   method Action dataIn(Bit#(dataWidth) data, Bit#(dataWidth) trigger) if (stateReg != Idle);
      let e = False;
      let s = stateReg;
      let c = countReg;
      let t = False;

      // if 'Enabled', we can transition to 'Triggered'
      if (s == Enabled && ((trigger & maskReg) == (valueReg & maskReg)))
      	 begin
      	    s = Triggered;
      	    e = True;
      	    c = c+1;
      	    t = True;
         end
      // if 'Triggered', we can transition to 'Enabled'
      else if (s == Triggered && c == fromInteger(samples))
      	 begin
      	    s = Enabled;
      	    e = False;
      	    c = 0;
      	    t = False;
      	 end
      // if 'Triggered', we can remain in 'Triggered'
      else if (s == Triggered && c <= fromInteger(samples))
      	 begin
      	    s = Triggered;
      	    e = True;
      	    c = c+1;
      	    t = False;
      	 end
      // else we must be enabled waiting for a Trigger
      else
      	 begin
      	    s = s;
      	    e = e;
      	    c = c;
      	    t = t;
      	 end

      if(e && dfifo.notFull)
      	 dfifo.enq(data);
      if(t)
      	 triggeredPulse.send();
      countReg <= c;
      stateReg <= s;
   endmethod

   interface BlueScopeRequest requestIfc;
      method Action start(Bit#(32) pointer);
         pointerReg <= pointer;
	 startPulse.send();
      endmethod

      method Action reset();
          resetPulse.send();
      endmethod

      method Action setTriggerMask(Bit#(64) mask);
	 maskReg <= truncate(mask);
      endmethod

      method Action setTriggerValue(Bit#(64) value);
	 valueReg <= truncate(value);
      endmethod
   endinterface
   interface writeClient = mwriter.writeClient;
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 Clocks::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;

import MemTypes::*;
import MemUtils::*;
import ClientServer::*;

interface BlueScopeIndication;
   method Action triggerFired();
endinterface

interface BlueScopeRequest;
   method Action start(Bit#(32) pointer);
   method Action reset();
   method Action setTriggerMask(Bit#(64) mask);
   method Action setTriggerValue(Bit#(64) value);
endinterface

interface BlueScope#(numeric type dataWidth);
   method Action dataIn(Bit#(dataWidth) d, Bit#(dataWidth) t);
   interface BlueScopeRequest requestIfc;
   interface ObjectWriteClient#(dataWidth) writeClient;
endinterface

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

module mkBlueScope#(Integer samples, BlueScopeIndication indication)(BlueScope#(dataWidth))
   provisos(Add#(a__,dataWidth,64),
	    Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	    Add#(1,b__,dataWidth));

   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;
   let rv  <- mkSyncBlueScope(samples, indication, clk, rst, clk,rst);
   return rv;
endmodule

module mkSyncBlueScope#(Integer samples, BlueScopeIndication indication, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScope#(dataWidth))
   provisos(Add#(a__,dataWidth,64),
	    Add#(1,b__,dataWidth),
	    Mul#(dataBytes, 8, dataWidth),
	    Div#(dataWidth,8,dataBytes));

   SyncFIFOIfc#(Bit#(dataWidth)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sRst, dClk, dRst);
   Reg#(ObjectPointer) pointerReg <- mkSyncReg(0, dClk, dRst, sClk);
   Reg#(Bit#(dataWidth))       maskReg <- mkSyncReg(0, dClk, dRst, sClk);
   Reg#(Bit#(dataWidth))      valueReg <- mkSyncReg(0, dClk, dRst, sClk);
   Reg#(Bit#(1))          triggeredReg <- mkReg(0,    clocked_by sClk, reset_by sRst);
   Reg#(State)                stateReg <- mkReg(Idle, clocked_by sClk, reset_by sRst);
   Reg#(Bit#(32))             countReg <- mkReg(0,    clocked_by sClk, reset_by sRst);
   Reg#(Bit#(ObjectOffsetSize)) writeOffsetReg <- mkReg(0,    clocked_by dClk, reset_by dRst);

   SyncPulseIfc             startPulse <- mkSyncPulse(dClk, dRst, sClk);
   SyncPulseIfc             resetPulse <- mkSyncPulse(dClk, dRst, sClk);
   SyncPulseIfc         triggeredPulse <- mkSyncPulse(sClk, sRst, dClk);

   MemWriter#(dataWidth) mwriter <- mkMemWriter;

   (* descending_urgency = "resetState, startState" *)
   rule resetState if (resetPulse.pulse);
      stateReg <= Idle;
      countReg <= 0;
   endrule

   rule startState if (startPulse.pulse && !resetPulse.pulse);
      stateReg <= Enabled;
   endrule

   rule writeReq if (dfifo.notEmpty);
      let bl = fromInteger(valueOf(dataBytes)) * 2;
      mwriter.writeServer.writeReq.put(ObjectRequest { pointer: pointerReg, offset: zeroExtend(writeOffsetReg), burstLen: bl, tag: 0});
      writeOffsetReg <= writeOffsetReg + bl;
   endrule

   rule  writeData;
      //$display("mkSyncBlueScope::writeData");
      dfifo.deq();
      mwriter.writeServer.writeData.put(ObjectData { data: dfifo.first, tag: 0});
   endrule

   rule writeDone;
      let tag <- mwriter.writeServer.writeDone.get();
   endrule

   rule triggerRule if (triggeredPulse.pulse);
      indication.triggerFired;
   endrule

   method Action dataIn(Bit#(dataWidth) data, Bit#(dataWidth) trigger) if (stateReg != Idle);
      let e = False;
      let s = stateReg;
      let c = countReg;
      let t = False;

      // if 'Enabled', we can transition to 'Triggered'
      if (s == Enabled && ((trigger & maskReg) == (valueReg & maskReg)))
      	 begin
      	    s = Triggered;
      	    e = True;
      	    c = c+1;
      	    t = True;
         end
      // if 'Triggered', we can transition to 'Enabled'
      else if (s == Triggered && c == fromInteger(samples))
      	 begin
      	    s = Enabled;
      	    e = False;
      	    c = 0;
      	    t = False;
      	 end
      // if 'Triggered', we can remain in 'Triggered'
      else if (s == Triggered && c <= fromInteger(samples))
      	 begin
      	    s = Triggered;
      	    e = True;
      	    c = c+1;
      	    t = False;
      	 end
      // else we must be enabled waiting for a Trigger
      else
      	 begin
      	    s = s;
      	    e = e;
      	    c = c;
      	    t = t;
      	 end

      if(e && dfifo.notFull)
      	 dfifo.enq(data);
      if(t)
      	 triggeredPulse.send();
      countReg <= c;
      stateReg <= s;
   endmethod

   interface BlueScopeRequest requestIfc;
      method Action start(Bit#(32) pointer);
         pointerReg <= pointer;
	 startPulse.send();
      endmethod

      method Action reset();
          resetPulse.send();
      endmethod

      method Action setTriggerMask(Bit#(64) mask);
	 maskReg <= truncate(mask);
      endmethod

      method Action setTriggerValue(Bit#(64) value);
	 valueReg <= truncate(value);
      endmethod
   endinterface
   interface writeClient = mwriter.writeClient;
endmodule


added mkConnection for DMA clients and servers

Change-Id: Ib8d79a8d2de723f90ebd20496c71e8d1476a5fdb

// 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 FIFOF::*;
import Adapter::*;
import GetPutF::*;
import Vector::*;
import Connectable::*;
import BRAMFIFO::*;

// XBSV Libraries
import PortalMemory::*;
import BRAMFIFOFLevel::*;

typedef Bit#(32) DmaPointer;

typedef 24 DmaAddrSize;
// SGListMaxPages is derived from this

typedef struct {
   DmaPointer handle;
   Bit#(DmaAddrSize)  address;
   Bit#(8) burstLen;
   Bit#(6)  tag;
   } DmaRequest deriving (Bits);
typedef struct {
   Bit#(dsz) data;
   Bit#(6) tag;
   } DmaData#(numeric type dsz) deriving (Bits);

interface DmaReadClient#(numeric type dsz);
   interface GetF#(DmaRequest)    readReq;
   interface PutF#(DmaData#(dsz)) readData;
endinterface

interface DmaWriteClient#(numeric type dsz);
   interface GetF#(DmaRequest)    writeReq;
   interface GetF#(DmaData#(dsz)) writeData;
   interface PutF#(Bit#(6))       writeDone;
endinterface

interface DmaReadServer#(numeric type dsz);
   interface PutF#(DmaRequest) readReq;
   interface GetF#(DmaData#(dsz))     readData;
endinterface

interface DmaWriteServer#(numeric type dsz);
   interface PutF#(DmaRequest) writeReq;
   interface PutF#(DmaData#(dsz))     writeData;
   interface GetF#(Bit#(6))           writeDone;
endinterface

interface DmaRead;
   method ActionValue#(DmaDbgRec) dbg();
endinterface

interface DmaWrite;
   method ActionValue#(DmaDbgRec) dbg();
endinterface

instance Connectable#(DmaReadClient#(dsz), DmaReadServer#(dsz));
   module mkConnection#(DmaReadClient#(dsz) source, DmaReadServer#(dsz) sink)(Empty);
      rule request;
	 let req <- source.readReq.get();
	 sink.readReq.put(req);
      endrule
      rule response;
	 let resp <- sink.readData.get();
	 source.readData.put(resp);
      endrule
   endmodule
endinstance

instance Connectable#(DmaWriteClient#(dsz), DmaWriteServer#(dsz));
   module mkConnection#(DmaWriteClient#(dsz) source, DmaWriteServer#(dsz) sink)(Empty);
      rule request;
	 let req <- source.writeReq.get();
	 sink.writeReq.put(req);
      endrule
      rule response;
	 let resp <- source.writeData.get();
	 sink.writeData.put(resp);
      endrule
      rule done;
	 let resp <- sink.writeDone.get();
	 source.writeDone.put(resp);
      endrule
   endmodule
endinstance

// 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 FIFOF::*;
import Adapter::*;
import GetPutF::*;
import Vector::*;
import ClientServer::*;
import BRAMFIFO::*;

// XBSV Libraries
import PortalMemory::*;
import BRAMFIFOFLevel::*;

typedef Bit#(32) DmaPointer;

typedef 24 DmaAddrSize;
// SGListMaxPages is derived from this

typedef struct {
   DmaPointer handle;
   Bit#(DmaAddrSize)  address;
   Bit#(8) burstLen;
   Bit#(6)  tag;
   } DmaRequest deriving (Bits);
typedef struct {
   Bit#(dsz) data;
   Bit#(6) tag;
   } DmaData#(numeric type dsz) deriving (Bits);

interface DmaReadClient#(numeric type dsz);
   interface GetF#(DmaRequest)    readReq;
   interface PutF#(DmaData#(dsz)) readData;
endinterface

interface DmaWriteClient#(numeric type dsz);
   interface GetF#(DmaRequest)    writeReq;
   interface GetF#(DmaData#(dsz)) writeData;
   interface PutF#(Bit#(6))       writeDone;
endinterface

interface DmaReadServer#(numeric type dsz);
   interface PutF#(DmaRequest) readReq;
   interface GetF#(DmaData#(dsz))     readData;
endinterface

interface DmaWriteServer#(numeric type dsz);
   interface PutF#(DmaRequest) writeReq;
   interface PutF#(DmaData#(dsz))     writeData;
   interface GetF#(Bit#(6))           writeDone;
endinterface

interface DmaRead;
   method ActionValue#(DmaDbgRec) dbg();
endinterface

interface DmaWrite;
   method ActionValue#(DmaDbgRec) dbg();
endinterface


refactor

refactor

// 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 DefaultValue :: *;
import XilinxCells  :: *;
import Vector       :: *;

(* always_ready, always_enabled *)
interface AxiREQ#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    Bit#(32)             ADDR;
    Bit#(2)              BURST;
    Bit#(4)              CACHE;
    Bit#(C_ID_WIDTH)     ID;
    Bit#(4)              LEN;
    Bit#(2)              LOCK;
    Bit#(3)              PROT;
    Bit#(4)              QOS;
    Bit#(3)              SIZE;
    Bit#(1)              VALID;
endinterface
interface AxiMOSI#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    AxiREQ               AR;
    AxiREQ               AW;
    Bit#(1)              BREADY;
    Bit#(1)              RREADY;
    Bit#(C_DATA_WIDTH)   WDATA;
    Bit#(C_ID_WIDTH)     WID;
    Bit#(1)              WLAST;
    Bit#(C_DATA_WIDTH/8) WSTRB;
    Bit#(1)              WVALID;
endinterface
interface AxiVALID#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    Bit#(C_ID_WIDTH)     ID;
    Bit#(2)              RESP;
    Bit#(1)              VALID;
endinterface
interface AxiMISO(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    Bit#(1)              ARREADY;
    Bit#(1)              AWREADY;
    AxiVALID#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH) B;
    AxiVALID#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH) R;
    Bit#(C_DATA_WIDTH)   RDATA;
    Bit#(1)              RLAST;
    Bit#(1)              WREADY;
endinterface
interface AxiMasterCommon#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    method Action ACLK(Bit#(1) v); // common
    method Bit#(1) ARESETN();      // common
    AxiMOSI#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    AxiMISO#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    method Action ARADDR(Bit#(32) v);
    method Bit#(1) ARREADY();
endinterface

interface AxiMasterHighSpeed#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    interface AxiCommon#(C_DATA_WIDTH, C_ID_WIDTH) axi;
    method Bit#(3) RACOUNT();
    method Bit#(8) RCOUNT();
    method Action RDISSUECAP1_EN(Bit#(1) v);
    method Bit#(6) WACOUNT();
    method Bit#(8) WCOUNT();
    method Action WRISSUECAP1_EN(Bit#(1) v);
endinterface
interface Ddr;
    method Bit#(15) DDR_Addr();
    method Bit#(3) DDR_BankAddr();
    method Bit#(1) DDR_CAS_n();
    method Bit#(1) DDR_CKE();
    method Bit#(1) DDR_CS_n();
    method Bit#(1) DDR_Clk();
    method Bit#(1) DDR_Clk_n();
    method Bit#(C_DM_WIDTH) DDR_DM();
    method Bit#(C_DQ_WIDTH) DDR_DQ();
    method Bit#(C_DQS_WIDTH) DDR_DQS();
    method Bit#(C_DQS_WIDTH) DDR_DQS_n();
    method Bit#(1) DDR_DRSTB();
    method Bit#(1) DDR_ODT();
    method Bit#(1) DDR_RAS_n();
    method Bit#(1) DDR_VRN();
    method Bit#(1) DDR_VRP();
    method Bit#(1) DDR_WEB();
endinterface
interface Dma;
    method Action DMA0_ACLK(Bit#(1) v);
    method Action DMA0_DAREADY(Bit#(1) v);
    method Bit#(2) DMA0_DATYPE();
    method Bit#(1) DMA0_DAVALID();
    method Action DMA0_DRLAST(Bit#(1) v);
    method Bit#(1) DMA0_DRREADY();
    method Action DMA0_DRTYPE(Bit#(2) v);
    method Action DMA0_DRVALID(Bit#(1) v);
    method Bit#(1) DMA0_RSTN();
endinterface
interface Enet;
    method Action ENET0_EXT_INTIN(Bit#(1) v);
    method Action ENET0_GMII_COL(Bit#(1) v);
    method Action ENET0_GMII_CRS(Bit#(1) v);
    method Action ENET0_GMII_RXD(Bit#(8) v);
    method Action ENET0_GMII_RX_CLK(Bit#(1) v);
    method Action ENET0_GMII_RX_DV(Bit#(1) v);
    method Action ENET0_GMII_RX_ER(Bit#(1) v);
    method Bit#(8) ENET0_GMII_TXD();
    method Action ENET0_GMII_TX_CLK(Bit#(1) v);
    method Bit#(1) ENET0_GMII_TX_EN();
    method Bit#(1) ENET0_GMII_TX_ER();
    method Action ENET0_MDIO_I(Bit#(1) v);
    method Bit#(1) ENET0_MDIO_MDC();
    method Bit#(1) ENET0_MDIO_O();
    method Bit#(1) ENET0_MDIO_T();
    method Bit#(1) ENET0_PTP_DELAY_REQ_RX();
    method Bit#(1) ENET0_PTP_DELAY_REQ_TX();
    method Bit#(1) ENET0_PTP_PDELAY_REQ_RX();
    method Bit#(1) ENET0_PTP_PDELAY_REQ_TX();
    method Bit#(1) ENET0_PTP_PDELAY_RESP_RX();
    method Bit#(1) ENET0_PTP_PDELAY_RESP_TX();
    method Bit#(1) ENET0_PTP_SYNC_FRAME_RX();
    method Bit#(1) ENET0_PTP_SYNC_FRAME_TX();
    method Bit#(1) ENET0_SOF_RX();
    method Bit#(1) ENET0_SOF_TX();
endinterface
interface Sdio;
    method Bit#(1) SDIO0_BUSPOW();
    method Bit#(3) SDIO0_BUSVOLT();
    method Action SDIO0_CDN(Bit#(1) v);
    method Bit#(1) SDIO0_CLK();
    method Action SDIO0_CLK_FB(Bit#(1) v);
    method Action SDIO0_CMD_I(Bit#(1) v);
    method Bit#(1) SDIO0_CMD_O();
    method Bit#(1) SDIO0_CMD_T();
    method Action SDIO0_DATA_I(Bit#(4) v);
    method Bit#(4) SDIO0_DATA_O();
    method Bit#(4) SDIO0_DATA_T();
    method Bit#(1) SDIO0_LED();
    method Action SDIO0_WP(Bit#(1) v);
endinterface
interface Spi;
    method Action SPI0_MISO_I(Bit#(1) v);
    method Bit#(1) SPI0_MISO_O();
    method Bit#(1) SPI0_MISO_T();
    method Action SPI0_MOSI_I(Bit#(1) v);
    method Bit#(1) SPI0_MOSI_O();
    method Bit#(1) SPI0_MOSI_T();
    method Action SPI0_SCLK_I(Bit#(1) v);
    method Bit#(1) SPI0_SCLK_O();
    method Bit#(1) SPI0_SCLK_T();
    method Bit#(1) SPI0_SS1_O();
    method Bit#(1) SPI0_SS2_O();
    method Action SPI0_SS_I(Bit#(1) v);
    method Bit#(1) SPI0_SS_O();
    method Bit#(1) SPI0_SS_T();
endinterface
interface Ttc;
    method Action TTC0_CLK0_IN(Bit#(1) v);
    method Action TTC0_CLK1_IN(Bit#(1) v);
    method Action TTC0_CLK2_IN(Bit#(1) v);
    method Bit#(1) TTC0_WAVE0_OUT();
    method Bit#(1) TTC0_WAVE1_OUT();
    method Bit#(1) TTC0_WAVE2_OUT();
endinterface
interface Uart;
    method Action UART0_CTSN(Bit#(1) v);
    method Action UART0_DCDN(Bit#(1) v);
    method Action UART0_DSRN(Bit#(1) v);
    method Bit#(1) UART0_DTRN();
    method Action UART0_RIN(Bit#(1) v);
    method Bit#(1) UART0_RTSN();
    method Action UART0_RX(Bit#(1) v);
    method Bit#(1) UART0_TX();
endinterface
interface Usb;
    method Bit#(2) USB0_PORT_INDCTL();
    method Action USB0_VBUS_PWRFAULT(Bit#(1) v);
    method Bit#(1) USB0_VBUS_PWRSELECT();
endinterface
interface I2c;
    method Action I2C0_SCL_I(Bit#(1) v);
    method Bit#(1) I2C0_SCL_O();
    method Bit#(1) I2C0_SCL_T();
    method Action I2C0_SDA_I(Bit#(1) v);
    method Bit#(1) I2C0_SDA_O();
    method Bit#(1) I2C0_SDA_T();
endinterface

interface Ps7#(numeric type C_EMIO_GPIO_WIDTH);
    method Action CAN0_PHY_RX(Bit#(1) v);
    method Bit#(1) CAN0_PHY_TX();
    method Action CAN1_PHY_RX(Bit#(1) v);
    method Bit#(1) CAN1_PHY_TX();
    method Action Core0_nFIQ(Bit#(1) v);
    method Action Core0_nIRQ(Bit#(1) v);
    method Action Core1_nFIQ(Bit#(1) v);
    method Action Core1_nIRQ(Bit#(1) v);
    method Action DDR_ARB(Bit#(4) v);
    interface Ddr DDR;
    interface Dma DMA0;
    interface Dma DMA1;
    interface Dma DMA2;
    interface Dma DMA3;
    interface Enet ENET0;
    interface Enet ENET1;
    method Action EVENT_EVENTI(Bit#(1) v);
    method Bit#(1) EVENT_EVENTO();
    method Bit#(2) EVENT_STANDBYWFE();
    method Bit#(2) EVENT_STANDBYWFI();
    method Bit#(1) FCLK_CLK0();
    method Bit#(1) FCLK_CLK1();
    method Bit#(1) FCLK_CLK2();
    method Bit#(1) FCLK_CLK3();
    method Action FCLK_CLKTRIG0_N(Bit#(1) v);
    method Action FCLK_CLKTRIG1_N(Bit#(1) v);
    method Action FCLK_CLKTRIG2_N(Bit#(1) v);
    method Action FCLK_CLKTRIG3_N(Bit#(1) v);
    method Bit#(1) FCLK_RESET0_N();
    method Bit#(1) FCLK_RESET1_N();
    method Bit#(1) FCLK_RESET2_N();
    method Bit#(1) FCLK_RESET3_N();
    method Action FPGA_IDLE_N(Bit#(1) v);
    method Action FTMD_TRACEIN_ATID(Bit#(4) v);
    method Action FTMD_TRACEIN_CLK(Bit#(1) v);
    method Action FTMD_TRACEIN_DATA(Bit#(32) v);
    method Action FTMD_TRACEIN_VALID(Bit#(1) v);
    method Action FTMT_F2P_DEBUG(Bit#(32) v);
    method Action FTMT_F2P_TRIG(Bit#(4) v);
    method Bit#(4) FTMT_F2P_TRIGACK();
    method Bit#(32) FTMT_P2F_DEBUG();
    method Bit#(4) FTMT_P2F_TRIG();
    method Action FTMT_P2F_TRIGACK(Bit#(4) v);
    method Action GPIO_I(Bit#(C_EMIO_GPIO_WIDTH) v);
    method Bit#(C_EMIO_GPIO_WIDTH) GPIO_O();
    method Bit#(C_EMIO_GPIO_WIDTH) GPIO_T();
    interface I2c I2C0;
    interface I2c I2C1;
    method Action IRQ_F2P(Bit#(16) v);
    method Bit#(1) IRQ_P2F_CAN0();
    method Bit#(1) IRQ_P2F_CAN1();
    method Bit#(1) IRQ_P2F_CTI();
    method Bit#(1) IRQ_P2F_DMAC0();
    method Bit#(1) IRQ_P2F_DMAC1();
    method Bit#(1) IRQ_P2F_DMAC2();
    method Bit#(1) IRQ_P2F_DMAC3();
    method Bit#(1) IRQ_P2F_DMAC4();
    method Bit#(1) IRQ_P2F_DMAC5();
    method Bit#(1) IRQ_P2F_DMAC6();
    method Bit#(1) IRQ_P2F_DMAC7();
    method Bit#(1) IRQ_P2F_DMAC_ABORT();
    method Bit#(1) IRQ_P2F_ENET0();
    method Bit#(1) IRQ_P2F_ENET1();
    method Bit#(1) IRQ_P2F_ENET_WAKE0();
    method Bit#(1) IRQ_P2F_ENET_WAKE1();
    method Bit#(1) IRQ_P2F_GPIO();
    method Bit#(1) IRQ_P2F_I2C0();
    method Bit#(1) IRQ_P2F_I2C1();
    method Bit#(1) IRQ_P2F_QSPI();
    method Bit#(1) IRQ_P2F_SDIO0();
    method Bit#(1) IRQ_P2F_SDIO1();
    method Bit#(1) IRQ_P2F_SMC();
    method Bit#(1) IRQ_P2F_SPI0();
    method Bit#(1) IRQ_P2F_SPI1();
    method Bit#(1) IRQ_P2F_UART0();
    method Bit#(1) IRQ_P2F_UART1();
    method Bit#(1) IRQ_P2F_USB0();
    method Bit#(1) IRQ_P2F_USB1();
    method Bit#(C_MIO_PRIMITIVE) MIO();
    interface AxiSlaveCommon#(1) s_axi_acp;
>     method Action ARUSER(Bit#(5) v);
>     method Action AWUSER(Bit#(5) v);
    interface AxiSlaveCommon#(1) s_axi_gp0;
    interface AxiSlaveCommon#(1) s_axi_gp1;
    interface AxiSlaveHighSpeed#(1) s_axi_hp0;
    interface AxiSlaveHighSpeed#(1) s_axi_hp1;
    interface AxiSlaveHighSpeed#(1) s_axi_hp2;
    interface AxiSlaveHighSpeed#(1) s_axi_hp3;
    interface AxiMasterCommon#(1) m_axi_gp0;
    interface AxiMasterCommon#(1) m_axi_gp1;
    method Action PJTAG_TCK(Bit#(1) v);
    method Action PJTAG_TD_I(Bit#(1) v);
    method Bit#(1) PJTAG_TD_O();
    method Bit#(1) PJTAG_TD_T();
    method Action PJTAG_TMS(Bit#(1) v);
    method Action PS_CLK(Bit#(1) v);
    method Action PS_PORB(Bit#(1) v);
    method Action PS_SRSTB(Bit#(1) v);
    interface Sdio SDIO0;
    interface Sdio SDIO1;
    interface Spi SPI0;
    interface Spi SPI1;
    method Action SRAM_INTIN(Bit#(1) v);
    method Action TRACE_CLK(Bit#(1) v);
    method Bit#(1) TRACE_CTL();
    method Bit#(32) TRACE_DATA();
    interface Ttc TTC0;
    interface Ttc TTC1;
    interface Uart UART0;
    interface Uart UART1;
    interface Usb USB0;
    interface Usb USB1;
    method Action WDT_CLK_IN(Bit#(1) v);
    method Bit#(1) WDT_RST_OUT();

   schedule (datain, idatain, inc, ce) CF (datain, idatain, inc, ce);
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 Clocks       :: *;
import DefaultValue :: *;
import XilinxCells  :: *;
import Vector       :: *;

(* always_ready, always_enabled *)
interface AxiREQ#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    Bit#(32)             ADDR;
    Bit#(2)              BURST;
    Bit#(4)              CACHE;
    Bit#(C_ID_WIDTH)     ID;
    Bit#(4)              LEN;
    Bit#(2)              LOCK;
    Bit#(3)              PROT;
    Bit#(4)              QOS;
    Bit#(3)              SIZE;
    Bit#(1)              VALID;
endinterface
interface AxiMOSI#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    AxiREQ               AR;
    AxiREQ               AW;
    Bit#(1)              BREADY;
    Bit#(1)              RREADY;
    Bit#(C_DATA_WIDTH)   WDATA;
    Bit#(C_ID_WIDTH)     WID;
    Bit#(1)              WLAST;
    Bit#(C_DATA_WIDTH/8) WSTRB;
    Bit#(1)              WVALID;
endinterface
interface AxiVALID#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    Bit#(C_ID_WIDTH)     ID;
    Bit#(2)              RESP;
    Bit#(1)              VALID;
endinterface
interface AxiMISO(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    Bit#(1)              ARREADY;
    Bit#(1)              AWREADY;
    AxiVALID#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH) B;
    AxiVALID#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH) R;
    Bit#(C_DATA_WIDTH)   RDATA;
    Bit#(1)              RLAST;
    Bit#(1)              WREADY;
endinterface
interface AxiMasterCommon#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    method Action ACLK(Bit#(1) v); // common
    method Bit#(1) ARESETN();      // common
    AxiMOSI#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    AxiMISO#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    method Action ARADDR(Bit#(32) v);
    method Action ARBURST(Bit#(2) v);
    method Action ARCACHE(Bit#(4) v);
    method Action ARID(Bit#(C_ID_WIDTH) v);
    method Action ARLEN(Bit#(4) v);
    method Action ARLOCK(Bit#(2) v);
    method Action ARPROT(Bit#(3) v);
    method Action ARQOS(Bit#(4) v);
    method Bit#(1) ARREADY();
    method Action ARSIZE(Bit#(3) v);
    method Action ARVALID(Bit#(1) v);
    method Action AWADDR(Bit#(32) v);
    method Action AWBURST(Bit#(2) v);
    method Action AWCACHE(Bit#(4) v);
    method Action AWID(Bit#(C_ID_WIDTH) v);
    method Action AWLEN(Bit#(4) v);
    method Action AWLOCK(Bit#(2) v);
    method Action AWPROT(Bit#(3) v);
    method Action AWQOS(Bit#(4) v);
    method Bit#(1) AWREADY();
    method Action AWSIZE(Bit#(3) v);
    method Action AWVALID(Bit#(1) v);
    method Bit#(C_ID_WIDTH) BID();
    method Action BREADY(Bit#(1) v);
    method Bit#(2) BRESP();
    method Bit#(1) BVALID();
    method Bit#(C_DATA_WIDTH) RDATA();
    method Bit#(C_ID_WIDTH) RID();
    method Bit#(1) RLAST();
    method Action RREADY(Bit#(1) v);
    method Bit#(2) RRESP();
    method Bit#(1) RVALID();
    method Action WDATA(Bit#(C_DATA_WIDTH) v);
    method Action WID(Bit#(C_ID_WIDTH) v);
    method Action WLAST(Bit#(1) v);
    method Bit#(1) WREADY();
    method Action WSTRB(Bit#(C_DATA_WIDTH/8) v);
    method Action WVALID(Bit#(1) v);
endinterface

interface AxiMasterHighSpeed#(numeric type C_DATA_WIDTH, numeric type C_ID_WIDTH);
    interface AxiCommon#(C_DATA_WIDTH, C_ID_WIDTH) axi;
    method Bit#(3) RACOUNT();
    method Bit#(8) RCOUNT();
    method Action RDISSUECAP1_EN(Bit#(1) v);
    method Bit#(6) WACOUNT();
    method Bit#(8) WCOUNT();
    method Action WRISSUECAP1_EN(Bit#(1) v);
endinterface

interface Ps7#(numeric type C_EMIO_GPIO_WIDTH);
    method Action CAN0_PHY_RX(Bit#(1) v);
    method Bit#(1) CAN0_PHY_TX();
    method Action CAN1_PHY_RX(Bit#(1) v);
    method Bit#(1) CAN1_PHY_TX();
    method Action Core0_nFIQ(Bit#(1) v);
    method Action Core0_nIRQ(Bit#(1) v);
    method Action Core1_nFIQ(Bit#(1) v);
    method Action Core1_nIRQ(Bit#(1) v);
    method Action DDR_ARB(Bit#(4) v);
    method Bit#(15) DDR_Addr();
    method Bit#(3) DDR_BankAddr();
    method Bit#(1) DDR_CAS_n();
    method Bit#(1) DDR_CKE();
    method Bit#(1) DDR_CS_n();
    method Bit#(1) DDR_Clk();
    method Bit#(1) DDR_Clk_n();
    method Bit#(C_DM_WIDTH) DDR_DM();
    method Bit#(C_DQ_WIDTH) DDR_DQ();
    method Bit#(C_DQS_WIDTH) DDR_DQS();
    method Bit#(C_DQS_WIDTH) DDR_DQS_n();
    method Bit#(1) DDR_DRSTB();
    method Bit#(1) DDR_ODT();
    method Bit#(1) DDR_RAS_n();
    method Bit#(1) DDR_VRN();
    method Bit#(1) DDR_VRP();
    method Bit#(1) DDR_WEB();
    method Action DMA0_ACLK(Bit#(1) v);
    method Action DMA0_DAREADY(Bit#(1) v);
    method Bit#(2) DMA0_DATYPE();
    method Bit#(1) DMA0_DAVALID();
    method Action DMA0_DRLAST(Bit#(1) v);
    method Bit#(1) DMA0_DRREADY();
    method Action DMA0_DRTYPE(Bit#(2) v);
    method Action DMA0_DRVALID(Bit#(1) v);
    method Bit#(1) DMA0_RSTN();
    method Action DMA1_ACLK(Bit#(1) v);
    method Action DMA1_DAREADY(Bit#(1) v);
    method Bit#(2) DMA1_DATYPE();
    method Bit#(1) DMA1_DAVALID();
    method Action DMA1_DRLAST(Bit#(1) v);
    method Bit#(1) DMA1_DRREADY();
    method Action DMA1_DRTYPE(Bit#(2) v);
    method Action DMA1_DRVALID(Bit#(1) v);
    method Bit#(1) DMA1_RSTN();
    method Action DMA2_ACLK(Bit#(1) v);
    method Action DMA2_DAREADY(Bit#(1) v);
    method Bit#(2) DMA2_DATYPE();
    method Bit#(1) DMA2_DAVALID();
    method Action DMA2_DRLAST(Bit#(1) v);
    method Bit#(1) DMA2_DRREADY();
    method Action DMA2_DRTYPE(Bit#(2) v);
    method Action DMA2_DRVALID(Bit#(1) v);
    method Bit#(1) DMA2_RSTN();
    method Action DMA3_ACLK(Bit#(1) v);
    method Action DMA3_DAREADY(Bit#(1) v);
    method Bit#(2) DMA3_DATYPE();
    method Bit#(1) DMA3_DAVALID();
    method Action DMA3_DRLAST(Bit#(1) v);
    method Bit#(1) DMA3_DRREADY();
    method Action DMA3_DRTYPE(Bit#(2) v);
    method Action DMA3_DRVALID(Bit#(1) v);
    method Bit#(1) DMA3_RSTN();
    method Action ENET0_EXT_INTIN(Bit#(1) v);
    method Action ENET0_GMII_COL(Bit#(1) v);
    method Action ENET0_GMII_CRS(Bit#(1) v);
    method Action ENET0_GMII_RXD(Bit#(8) v);
    method Action ENET0_GMII_RX_CLK(Bit#(1) v);
    method Action ENET0_GMII_RX_DV(Bit#(1) v);
    method Action ENET0_GMII_RX_ER(Bit#(1) v);
    method Bit#(8) ENET0_GMII_TXD();
    method Action ENET0_GMII_TX_CLK(Bit#(1) v);
    method Bit#(1) ENET0_GMII_TX_EN();
    method Bit#(1) ENET0_GMII_TX_ER();
    method Action ENET0_MDIO_I(Bit#(1) v);
    method Bit#(1) ENET0_MDIO_MDC();
    method Bit#(1) ENET0_MDIO_O();
    method Bit#(1) ENET0_MDIO_T();
    method Bit#(1) ENET0_PTP_DELAY_REQ_RX();
    method Bit#(1) ENET0_PTP_DELAY_REQ_TX();
    method Bit#(1) ENET0_PTP_PDELAY_REQ_RX();
    method Bit#(1) ENET0_PTP_PDELAY_REQ_TX();
    method Bit#(1) ENET0_PTP_PDELAY_RESP_RX();
    method Bit#(1) ENET0_PTP_PDELAY_RESP_TX();
    method Bit#(1) ENET0_PTP_SYNC_FRAME_RX();
    method Bit#(1) ENET0_PTP_SYNC_FRAME_TX();
    method Bit#(1) ENET0_SOF_RX();
    method Bit#(1) ENET0_SOF_TX();
    method Action ENET1_EXT_INTIN(Bit#(1) v);
    method Action ENET1_GMII_COL(Bit#(1) v);
    method Action ENET1_GMII_CRS(Bit#(1) v);
    method Action ENET1_GMII_RXD(Bit#(8) v);
    method Action ENET1_GMII_RX_CLK(Bit#(1) v);
    method Action ENET1_GMII_RX_DV(Bit#(1) v);
    method Action ENET1_GMII_RX_ER(Bit#(1) v);
    method Bit#(8) ENET1_GMII_TXD();
    method Action ENET1_GMII_TX_CLK(Bit#(1) v);
    method Bit#(1) ENET1_GMII_TX_EN();
    method Bit#(1) ENET1_GMII_TX_ER();
    method Action ENET1_MDIO_I(Bit#(1) v);
    method Bit#(1) ENET1_MDIO_MDC();
    method Bit#(1) ENET1_MDIO_O();
    method Bit#(1) ENET1_MDIO_T();
    method Bit#(1) ENET1_PTP_DELAY_REQ_RX();
    method Bit#(1) ENET1_PTP_DELAY_REQ_TX();
    method Bit#(1) ENET1_PTP_PDELAY_REQ_RX();
    method Bit#(1) ENET1_PTP_PDELAY_REQ_TX();
    method Bit#(1) ENET1_PTP_PDELAY_RESP_RX();
    method Bit#(1) ENET1_PTP_PDELAY_RESP_TX();
    method Bit#(1) ENET1_PTP_SYNC_FRAME_RX();
    method Bit#(1) ENET1_PTP_SYNC_FRAME_TX();
    method Bit#(1) ENET1_SOF_RX();
    method Bit#(1) ENET1_SOF_TX();
    method Action EVENT_EVENTI(Bit#(1) v);
    method Bit#(1) EVENT_EVENTO();
    method Bit#(2) EVENT_STANDBYWFE();
    method Bit#(2) EVENT_STANDBYWFI();
    method Bit#(1) FCLK_CLK0();
    method Bit#(1) FCLK_CLK1();
    method Bit#(1) FCLK_CLK2();
    method Bit#(1) FCLK_CLK3();
    method Action FCLK_CLKTRIG0_N(Bit#(1) v);
    method Action FCLK_CLKTRIG1_N(Bit#(1) v);
    method Action FCLK_CLKTRIG2_N(Bit#(1) v);
    method Action FCLK_CLKTRIG3_N(Bit#(1) v);
    method Bit#(1) FCLK_RESET0_N();
    method Bit#(1) FCLK_RESET1_N();
    method Bit#(1) FCLK_RESET2_N();
    method Bit#(1) FCLK_RESET3_N();
    method Action FPGA_IDLE_N(Bit#(1) v);
    method Action FTMD_TRACEIN_ATID(Bit#(4) v);
    method Action FTMD_TRACEIN_CLK(Bit#(1) v);
    method Action FTMD_TRACEIN_DATA(Bit#(32) v);
    method Action FTMD_TRACEIN_VALID(Bit#(1) v);
    method Action FTMT_F2P_DEBUG(Bit#(32) v);
    method Action FTMT_F2P_TRIG(Bit#(4) v);
    method Bit#(4) FTMT_F2P_TRIGACK();
    method Bit#(32) FTMT_P2F_DEBUG();
    method Bit#(4) FTMT_P2F_TRIG();
    method Action FTMT_P2F_TRIGACK(Bit#(4) v);
    method Action GPIO_I(Bit#(C_EMIO_GPIO_WIDTH) v);
    method Bit#(C_EMIO_GPIO_WIDTH) GPIO_O();
    method Bit#(C_EMIO_GPIO_WIDTH) GPIO_T();
    method Action I2C0_SCL_I(Bit#(1) v);
    method Bit#(1) I2C0_SCL_O();
    method Bit#(1) I2C0_SCL_T();
    method Action I2C0_SDA_I(Bit#(1) v);
    method Bit#(1) I2C0_SDA_O();
    method Bit#(1) I2C0_SDA_T();
    method Action I2C1_SCL_I(Bit#(1) v);
    method Bit#(1) I2C1_SCL_O();
    method Bit#(1) I2C1_SCL_T();
    method Action I2C1_SDA_I(Bit#(1) v);
    method Bit#(1) I2C1_SDA_O();
    method Bit#(1) I2C1_SDA_T();
    method Action IRQ_F2P(Bit#(16) v);
    method Bit#(1) IRQ_P2F_CAN0();
    method Bit#(1) IRQ_P2F_CAN1();
    method Bit#(1) IRQ_P2F_CTI();
    method Bit#(1) IRQ_P2F_DMAC0();
    method Bit#(1) IRQ_P2F_DMAC1();
    method Bit#(1) IRQ_P2F_DMAC2();
    method Bit#(1) IRQ_P2F_DMAC3();
    method Bit#(1) IRQ_P2F_DMAC4();
    method Bit#(1) IRQ_P2F_DMAC5();
    method Bit#(1) IRQ_P2F_DMAC6();
    method Bit#(1) IRQ_P2F_DMAC7();
    method Bit#(1) IRQ_P2F_DMAC_ABORT();
    method Bit#(1) IRQ_P2F_ENET0();
    method Bit#(1) IRQ_P2F_ENET1();
    method Bit#(1) IRQ_P2F_ENET_WAKE0();
    method Bit#(1) IRQ_P2F_ENET_WAKE1();
    method Bit#(1) IRQ_P2F_GPIO();
    method Bit#(1) IRQ_P2F_I2C0();
    method Bit#(1) IRQ_P2F_I2C1();
    method Bit#(1) IRQ_P2F_QSPI();
    method Bit#(1) IRQ_P2F_SDIO0();
    method Bit#(1) IRQ_P2F_SDIO1();
    method Bit#(1) IRQ_P2F_SMC();
    method Bit#(1) IRQ_P2F_SPI0();
    method Bit#(1) IRQ_P2F_SPI1();
    method Bit#(1) IRQ_P2F_UART0();
    method Bit#(1) IRQ_P2F_UART1();
    method Bit#(1) IRQ_P2F_USB0();
    method Bit#(1) IRQ_P2F_USB1();
    method Bit#(C_MIO_PRIMITIVE) MIO();
    interface AxiSlaveCommon#(1) s_axi_acp;
>     method Action ARUSER(Bit#(5) v);
>     method Action AWUSER(Bit#(5) v);
    interface AxiSlaveCommon#(1) s_axi_gp0;
    interface AxiSlaveCommon#(1) s_axi_gp1;
    interface AxiSlaveHighSpeed#(1) s_axi_hp0;
    interface AxiSlaveHighSpeed#(1) s_axi_hp1;
    interface AxiSlaveHighSpeed#(1) s_axi_hp2;
    interface AxiSlaveHighSpeed#(1) s_axi_hp3;
    interface AxiMasterCommon#(1) m_axi_gp0;
    interface AxiMasterCommon#(1) m_axi_gp1;
    interface AxiMasterHighSpeed#(1) m_axi_hp0;
    interface AxiMasterHighSpeed#(1) m_axi_hp1;
    interface AxiMasterHighSpeed#(1) m_axi_hp2;
    interface AxiMasterHighSpeed#(1) m_axi_hp3;
    method Action PJTAG_TCK(Bit#(1) v);
    method Action PJTAG_TD_I(Bit#(1) v);
    method Bit#(1) PJTAG_TD_O();
    method Bit#(1) PJTAG_TD_T();
    method Action PJTAG_TMS(Bit#(1) v);
    method Action PS_CLK(Bit#(1) v);
    method Action PS_PORB(Bit#(1) v);
    method Action PS_SRSTB(Bit#(1) v);
    method Bit#(1) SDIO0_BUSPOW();
    method Bit#(3) SDIO0_BUSVOLT();
    method Action SDIO0_CDN(Bit#(1) v);
    method Bit#(1) SDIO0_CLK();
    method Action SDIO0_CLK_FB(Bit#(1) v);
    method Action SDIO0_CMD_I(Bit#(1) v);
    method Bit#(1) SDIO0_CMD_O();
    method Bit#(1) SDIO0_CMD_T();
    method Action SDIO0_DATA_I(Bit#(4) v);
    method Bit#(4) SDIO0_DATA_O();
    method Bit#(4) SDIO0_DATA_T();
    method Bit#(1) SDIO0_LED();
    method Action SDIO0_WP(Bit#(1) v);
    method Bit#(1) SDIO1_BUSPOW();
    method Bit#(3) SDIO1_BUSVOLT();
    method Action SDIO1_CDN(Bit#(1) v);
    method Bit#(1) SDIO1_CLK();
    method Action SDIO1_CLK_FB(Bit#(1) v);
    method Action SDIO1_CMD_I(Bit#(1) v);
    method Bit#(1) SDIO1_CMD_O();
    method Bit#(1) SDIO1_CMD_T();
    method Action SDIO1_DATA_I(Bit#(4) v);
    method Bit#(4) SDIO1_DATA_O();
    method Bit#(4) SDIO1_DATA_T();
    method Bit#(1) SDIO1_LED();
    method Action SDIO1_WP(Bit#(1) v);
    method Action SPI0_MISO_I(Bit#(1) v);
    method Bit#(1) SPI0_MISO_O();
    method Bit#(1) SPI0_MISO_T();
    method Action SPI0_MOSI_I(Bit#(1) v);
    method Bit#(1) SPI0_MOSI_O();
    method Bit#(1) SPI0_MOSI_T();
    method Action SPI0_SCLK_I(Bit#(1) v);
    method Bit#(1) SPI0_SCLK_O();
    method Bit#(1) SPI0_SCLK_T();
    method Bit#(1) SPI0_SS1_O();
    method Bit#(1) SPI0_SS2_O();
    method Action SPI0_SS_I(Bit#(1) v);
    method Bit#(1) SPI0_SS_O();
    method Bit#(1) SPI0_SS_T();
    method Action SPI1_MISO_I(Bit#(1) v);
    method Bit#(1) SPI1_MISO_O();
    method Bit#(1) SPI1_MISO_T();
    method Action SPI1_MOSI_I(Bit#(1) v);
    method Bit#(1) SPI1_MOSI_O();
    method Bit#(1) SPI1_MOSI_T();
    method Action SPI1_SCLK_I(Bit#(1) v);
    method Bit#(1) SPI1_SCLK_O();
    method Bit#(1) SPI1_SCLK_T();
    method Bit#(1) SPI1_SS1_O();
    method Bit#(1) SPI1_SS2_O();
    method Action SPI1_SS_I(Bit#(1) v);
    method Bit#(1) SPI1_SS_O();
    method Bit#(1) SPI1_SS_T();
    method Action SRAM_INTIN(Bit#(1) v);
    method Action TRACE_CLK(Bit#(1) v);
    method Bit#(1) TRACE_CTL();
    method Bit#(32) TRACE_DATA();
    method Action TTC0_CLK0_IN(Bit#(1) v);
    method Action TTC0_CLK1_IN(Bit#(1) v);
    method Action TTC0_CLK2_IN(Bit#(1) v);
    method Bit#(1) TTC0_WAVE0_OUT();
    method Bit#(1) TTC0_WAVE1_OUT();
    method Bit#(1) TTC0_WAVE2_OUT();
    method Action TTC1_CLK0_IN(Bit#(1) v);
    method Action TTC1_CLK1_IN(Bit#(1) v);
    method Action TTC1_CLK2_IN(Bit#(1) v);
    method Bit#(1) TTC1_WAVE0_OUT();
    method Bit#(1) TTC1_WAVE1_OUT();
    method Bit#(1) TTC1_WAVE2_OUT();
    method Action UART0_CTSN(Bit#(1) v);
    method Action UART0_DCDN(Bit#(1) v);
    method Action UART0_DSRN(Bit#(1) v);
    method Bit#(1) UART0_DTRN();
    method Action UART0_RIN(Bit#(1) v);
    method Bit#(1) UART0_RTSN();
    method Action UART0_RX(Bit#(1) v);
    method Bit#(1) UART0_TX();
    method Action UART1_CTSN(Bit#(1) v);
    method Action UART1_DCDN(Bit#(1) v);
    method Action UART1_DSRN(Bit#(1) v);
    method Bit#(1) UART1_DTRN();
    method Action UART1_RIN(Bit#(1) v);
    method Bit#(1) UART1_RTSN();
    method Action UART1_RX(Bit#(1) v);
    method Bit#(1) UART1_TX();
    method Bit#(2) USB0_PORT_INDCTL();
    method Action USB0_VBUS_PWRFAULT(Bit#(1) v);
    method Bit#(1) USB0_VBUS_PWRSELECT();
    method Bit#(2) USB1_PORT_INDCTL();
    method Action USB1_VBUS_PWRFAULT(Bit#(1) v);
    method Bit#(1) USB1_VBUS_PWRSELECT();
    method Action WDT_CLK_IN(Bit#(1) v);
    method Bit#(1) WDT_RST_OUT();
    method Action S_AXI_HP3_ACLK(Bit#(1) v);
    method Action TRACE_CLK(Bit#(1) v);
    method Bit#(1) TRACE_CTL();
    method Bit#(32) TRACE_DATA();
    method Action TTC0_CLK0_IN(Bit#(1) v);
    method Action TTC0_CLK1_IN(Bit#(1) v);
    method Action TTC0_CLK2_IN(Bit#(1) v);
    method Bit#(1) TTC0_WAVE0_OUT();
    method Bit#(1) TTC0_WAVE1_OUT();
    method Bit#(1) TTC0_WAVE2_OUT();
    method Action TTC1_CLK0_IN(Bit#(1) v);
    method Action TTC1_CLK1_IN(Bit#(1) v);
    method Action TTC1_CLK2_IN(Bit#(1) v);
    method Bit#(1) TTC1_WAVE0_OUT();
    method Bit#(1) TTC1_WAVE1_OUT();
    method Bit#(1) TTC1_WAVE2_OUT();
    method Action UART0_CTSN(Bit#(1) v);
    method Action UART0_DCDN(Bit#(1) v);
    method Action UART0_DSRN(Bit#(1) v);
    method Bit#(1) UART0_DTRN();
    method Action UART0_RIN(Bit#(1) v);
    method Bit#(1) UART0_RTSN();
    method Action UART0_RX(Bit#(1) v);
    method Bit#(1) UART0_TX();
    method Action UART1_CTSN(Bit#(1) v);
    method Action UART1_DCDN(Bit#(1) v);
    method Action UART1_DSRN(Bit#(1) v);
    method Bit#(1) UART1_DTRN();
    method Action UART1_RIN(Bit#(1) v);
    method Bit#(1) UART1_RTSN();
    method Action UART1_RX(Bit#(1) v);
    method Bit#(1) UART1_TX();
    method Bit#(2) USB0_PORT_INDCTL();
    method Action USB0_VBUS_PWRFAULT(Bit#(1) v);
    method Bit#(1) USB0_VBUS_PWRSELECT();
    method Bit#(2) USB1_PORT_INDCTL();
    method Action USB1_VBUS_PWRFAULT(Bit#(1) v);
    method Bit#(1) USB1_VBUS_PWRSELECT();
    method Action WDT_CLK_IN(Bit#(1) v);
    method Bit#(1) WDT_RST_OUT();

   schedule (datain, idatain, inc, ce) CF (datain, idatain, inc, ce);
endmodule


need more buffering to enable 32-word write requests back to back

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

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

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

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

import FIFO         :: *;
import FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import MIFO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;
import Probe        :: *;
import ConfigCounter ::*;

typedef struct {
   TLPData#(16) tlp;
   TLPLength    dwCount;
   Bool         is3dw;
   Bool         isHeaderOnly;
   } TlpWriteHeaderInfo deriving (Bits);

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

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

typedef 64 WriteDataMimoSize;
typedef TAdd#(1,TLog#(WriteDataMimoSize)) WriteDataBurstLenSize;
module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8),
	     Add#(1, a__, busWidthWords),
	     Add#(busWidthWords, b__, 4),
	     Add#(c__, busWidthWords, WriteDataMimoSize)
      );

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFOF#(TlpWriteHeaderInfo) tlpWriteHeaderFifo <- mkFIFOF;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
   MIFO#(4,busWidthWords,16,Bit#(32)) completionMimo <- mkMIFO();
   MIFO#(4,busWidthWords,16,TLPTag) completionTagMimo <- mkMIFO();

   mimoCfg.bram_based = True;
   mimoCfg.unguarded = True;
    MIMO#(busWidthWords,4,WriteDataMimoSize,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    ConfigCounter#(8) writeDataCnt <- mkConfigCounter(0);
    Reg#(Bit#(WriteDataBurstLenSize)) writeBurstCount <- mkReg(0);
    FIFO#(Bit#(WriteDataBurstLenSize)) writeBurstCountFifo <- mkFIFO();
    Reg#(TLPLength)  writeDwCount <- mkReg(0); // how many 4 byte (double) words to send
    Reg#(LUInt#(4))    tlpDwCount <- mkReg(0); // how many to send in the next tlp (at most 4)
    Reg#(Bool)            lastTlp <- mkReg(False); // if the next tlp sent is the last one
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    Reg#(Bool) quadAlignedTlpHandled <- mkReg(True);

   Wire#(Bool) writeHeaderTlpWire <- mkDWire(False);
   Probe#(Bool) writeHeaderAvailableProbe <- mkProbe;
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);
   Probe#(Bool) writeDataMimoEnqProbe <- mkProbe;
   let    writeDataMimoCountProbe <- mkProbe;
   let writeDataMimoEnqReadyProbe <- mkProbe;
   Probe#(Bool) writeInProgressProbe <- mkProbe;
   Probe#(Bit#(10)) writeBurstCountProbe <- mkProbe;
   rule updateProbe0;
      writeDataMimoCountProbe    <= writeDataMimo.count();
      writeDataMimoEnqReadyProbe <= writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords)));
   endrule
   rule updateProbe2;
      writeHeaderAvailableProbe <= writeHeaderTlpWire;
      writeDataMimoEnqProbe <= writeDataMimoEnqWire;
   endrule

   Reg#(Bool) writeDataCntAboveThreshold <- mkReg(False);
   Reg#(Bool) writeDataMimoHasRoom <- mkReg(False);
   rule updateWriteDataMimoHasRoom;
      writeDataMimoHasRoom <= (writeDataCnt.read <= fromInteger(valueOf(WriteDataMimoSize) - valueOf(busWidthWords)));
   endrule
   rule noheader if (!tlpWriteHeaderFifo.notEmpty());
      writeDataCntAboveThreshold <= False;
   endrule
   rule updateWriteDataCntAboveThreshold if (writeInProgress || !writeDataCntAboveThreshold);
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));
   endrule
   (* descending_urgency = "writeHeaderTlp,updateWriteDataCntAboveThreshold" *)
   rule writeHeaderTlp if (!writeInProgress && writeDataCntAboveThreshold);
      // update for next cycle
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));

      writeHeaderTlpWire <= True;
      let info <- toGet(tlpWriteHeaderFifo).get();
      let tlp     = info.tlp;
      let dwCount = info.dwCount;
      let is3dw   = info.is3dw;
      let isHeaderOnly = info.isHeaderOnly;

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      if (is3dw) begin
	 if (hdr_3dw.format != MEM_WRITE_3DW_DATA)
	    $display("MemSlaveEngine: expecting MEM_WRITE_3DW_DATA, got %d", hdr_3dw.format);
	 Vector#(4, Bit#(32)) v = unpack(0);
         tlp.sof = True;
`ifdef AXI
         v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
         tlp.eof = (dwCount == 1) ? True : False;
         dwCount = dwCount - 1;
         writeDataCnt.decrement(1);
`elsif AVALON
         let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
         // if quad-word aligned, insert bubble.
         if (!quadWordAligned) begin
            v = writeDataMimo.first();
            writeDataMimo.deq(1);
            hdr_3dw.data = v[0];
         end
         else begin
            hdr_3dw.data = unpack(0);
         end
         tlp.eof = (dwCount == 1 && !quadWordAligned) ? True : False;
         if (!quadWordAligned) begin
            dwCount = dwCount - 1;
            writeDataCnt.decrement(1);
         end
`endif
	 tlp.be = 16'hffff;
	 tlp.data = pack(hdr_3dw);
      end
      else begin
         quadAlignedTlpHandled <= isQuadWordAligned(getLowerAddr(truncate(unpack(hdr_4dw.addr)), hdr_4dw.firstbe));
	 tlp.be = 16'hffff;
      end

      tlpOutFifo.enq(tlp);
      $display("writeHeaderTlp dwCount=%d", dwCount);
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      writeInProgress <= (dwCount != 0);
      writeInProgressProbe <= (dwCount != 0);
      if (isHeaderOnly) begin
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
      end

   endrule

   rule writeTlps if (writeInProgress); // already verified  writeDataMimo.deqReadyN(tlpDwCount)) for this transaction
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);
      Integer currDwCount = 4;

`ifdef AVALON
      if (!quadAlignedTlpHandled) begin
         currDwCount = 3; // 3 Data Dwords in this cycle.
         quadAlignedTlpHandled <= True;
      end
`endif

      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      writeDataMimo.deq(tlpDwCount);
      v = writeDataMimo.first();
      let dwCount = writeDwCount - extend(pack(tlpDwCount));
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(fromInteger(currDwCount),unpack(dwCount)));
      writeDataCnt.decrement(unpack(extend(pack(tlpDwCount))));
      lastTlp <= (dwCount <= 4);
      if (tlpDwCount == 4)
	 tlp.be = 16'hffff;
      else if (tlpDwCount == 3)
	 tlp.be = 16'hfff0;
      else if (tlpDwCount == 2)
	 tlp.be = 16'hff00;
      else if (tlpDwCount == 1)
	 tlp.be = 16'hf000;
      tlp.eof = lastTlp;
      if (lastTlp) begin
	 writeInProgress <= False;
	 writeInProgressProbe <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 $display("writeDwCount=%d will be zero", writeDwCount);
      end

      for (Integer i = 0; i < currDwCount; i = i + 1) begin
`ifdef AXI
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(v[(currDwCount-1)-i]);
`elsif AVALON
	 tlp.data[(i+1)*32-1:i*32] = v[(currDwCount-1)-i];
`endif
      end

      tlpOutFifo.enq(tlp);
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   FIFOF#(TLPData#(16)) tlpDecodeFifo <- mkFIFOF();
   Reg#(TLPLength) wordCountReg <- mkReg(0);
   rule tlpInRule;
      let tlp <- toGet(tlpInFifo).get();
      tlpDecodeFifo.enq(tlp);
   endrule

   rule handleTlpRule;
      let tlp = tlpDecodeFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);
      let wordCount = wordCountReg;
`ifdef AXI
      let dataInSecondTlp = False;
`elsif AVALON
      let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
      let dataInSecondTlp = quadWordAligned;
`endif
      if (!tlp.sof) begin
	 vec = reverse(tlpvec);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReady()
	    && completionTagMimo.enqReady())
	    begin
	       UInt#(3) count = 4;
	       if (tlp.eof) begin
		  count = truncate(unpack(wordCountReg));
	       end
	       wordCount = wordCountReg - extend(pack(count));
	       completionMimo.enq(count, vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(count, tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReady()
	       && completionTagMimo.enqReady()) begin
            TLPTag tag = hdr_completion.tag;
            lastTag <= tag;
            if (!dataInSecondTlp) begin
               vec[0] = hdr_3dw.data;
               wordCount = hdr_3dw.length - 1;
               completionMimo.enq(1, vec);
               completionTagMimo.enq(1, replicate(tag));
            end
	    handled = True;
      end
      wordCountReg <= wordCount;
      $display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled) begin
	 tlpDecodeFifo.deq();
      end
   endrule

   FIFO#(PhysMemRequest#(40)) readReqFifo <- mkFIFO();
   rule readReqRule if (!writeInProgress && !writeDataMimo.deqReady());
      let req <- toGet(readReqFifo).get();
      let burstLen = req.burstLen >> beat_shift;
      let addr = req.addr;
      let arid = req.tag;

      TLPData#(16) tlp = defaultValue;
      tlp.sof = True;
      tlp.eof = True;
      tlp.hit = 7'h00;
      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
      if (addr[39:32] != 0) begin
	 TLPMemory4DWHeader hdr_4dw = defaultValue;
	 hdr_4dw.format = MEM_READ_4DW_NO_DATA;
	 hdr_4dw.tag = extend(arid);
	 hdr_4dw.reqid = my_id;
	 hdr_4dw.nosnoop = SNOOPING_REQD;
	 hdr_4dw.addr = addr[40-1:2];
	 hdr_4dw.length = tlplen;
	 hdr_4dw.firstbe = 4'hf;
	 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_4dw);
	 tlp.be = 16'hffff;
      end
      else begin
	 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	 hdr_3dw.format = MEM_READ_3DW_NO_DATA;
	 hdr_3dw.tag = extend(arid);
	 hdr_3dw.reqid = my_id;
	 hdr_3dw.nosnoop = SNOOPING_REQD;
	 hdr_3dw.addr = addr[32-1:2];
	 hdr_3dw.length = tlplen;
	 hdr_3dw.firstbe = 4'hf;
	 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_3dw);
	 tlp.be = 16'hfff0;
      end
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface PhysMemSlave slave;
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(40) req); // if (writeBurstCount == 0);
	    Bit#(WriteDataBurstLenSize) burstLen = truncate(req.burstLen >> beat_shift);
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;

	    TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
	    TLPData#(16) tlp = defaultValue;
	    tlp.sof = True;
	    tlp.eof = False;
	    tlp.hit = 7'h00;
	    tlp.be = 16'hffff;

	    $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	    if ((addr >> 32) != 0) begin
	       TLPMemory4DWHeader hdr_4dw = defaultValue;
	       hdr_4dw.format = MEM_WRITE_4DW_DATA;
	       hdr_4dw.tag = extend(awid);
	       hdr_4dw.reqid = my_id;
	       hdr_4dw.nosnoop = SNOOPING_REQD;
	       hdr_4dw.addr = addr[40-1:2];
	       hdr_4dw.length = tlplen;
	       hdr_4dw.firstbe = 4'hf;
	       hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	       tlp.data = pack(hdr_4dw);
	    end
	    else begin
	       writeIs3dw = True;
	       TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	       hdr_3dw.format = MEM_WRITE_3DW_DATA;
	       hdr_3dw.tag = extend(awid);
	       hdr_3dw.reqid = my_id;
	       hdr_3dw.nosnoop = SNOOPING_REQD;
	       hdr_3dw.addr = addr[32-1:2];
	       hdr_3dw.length = tlplen;
	       hdr_3dw.firstbe = 4'hf;
	       hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

	       tlp.be = 16'hfff0; // no data word in this TLP

	       tlp.data = pack(hdr_3dw);
	    end
	    tlpWriteHeaderFifo.enq(TlpWriteHeaderInfo {tlp: tlp, dwCount: tlplen, is3dw: writeIs3dw, isHeaderOnly: (writeIs3dw && tlplen == 1) });
	    writeBurstCountFifo.enq(burstLen);
	    writeTag.enq(extend(awid));
         endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	    provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeDataMimoHasRoom); //.enqReadyN(fromInteger(valueOf(busWidthWords))));

	    let burstLen = writeBurstCount;
	    if (burstLen == 0) begin
	       burstLen <- toGet(writeBurstCountFifo).get();
	    end
	    writeBurstCount <= extend(burstLen-1);
	    writeBurstCountProbe <= extend(burstLen-1);

	    Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	    writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
            writeDataCnt.increment(fromInteger(valueOf(busWidthWords)));
	    writeDataMimoEnqWire <= True;
         endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(40) req);
	    readReqFifo.enq(req);
         endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReady()
							   && completionTagMimo.deqReady());
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
              for (Integer i = 0; i < valueOf(busWidthWords); i = i+1) begin
`ifdef AXI
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
`elsif AVALON
		 v[(i+1)*32-1:i*32] = data_v[i];
`endif
              end
	      return MemData { data: v, tag: truncate(tag_v[0]), last: True};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine

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

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

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

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

import FIFO         :: *;
import FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import MIFO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;
import Probe        :: *;
import ConfigCounter ::*;

typedef struct {
   TLPData#(16) tlp;
   TLPLength    dwCount;
   Bool         is3dw;
   Bool         isHeaderOnly;
   } TlpWriteHeaderInfo deriving (Bits);

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

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

typedef 32 WriteDataMimoSize;
module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8),
	     Add#(1, a__, busWidthWords),
	     Add#(busWidthWords, b__, 4),
	     Add#(c__, busWidthWords, WriteDataMimoSize)
      );

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFOF#(TlpWriteHeaderInfo) tlpWriteHeaderFifo <- mkFIFOF;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
   MIFO#(4,busWidthWords,16,Bit#(32)) completionMimo <- mkMIFO();
   MIFO#(4,busWidthWords,16,TLPTag) completionTagMimo <- mkMIFO();

   mimoCfg.bram_based = True;
   mimoCfg.unguarded = True;
    MIMO#(busWidthWords,4,WriteDataMimoSize,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    ConfigCounter#(8) writeDataCnt <- mkConfigCounter(0);
    Reg#(Bit#(10)) writeBurstCount <- mkReg(0);
   FIFO#(Bit#(10)) writeBurstCountFifo <- mkFIFO();
    Reg#(TLPLength)  writeDwCount <- mkReg(0); // how many 4 byte (double) words to send
    Reg#(LUInt#(4))    tlpDwCount <- mkReg(0); // how many to send in the next tlp (at most 4)
    Reg#(Bool)            lastTlp <- mkReg(False); // if the next tlp sent is the last one
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    Reg#(Bool) quadAlignedTlpHandled <- mkReg(True);

   Wire#(Bool) writeHeaderTlpWire <- mkDWire(False);
   Probe#(Bool) writeHeaderAvailableProbe <- mkProbe;
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);
   Probe#(Bool) writeDataMimoEnqProbe <- mkProbe;
   let    writeDataMimoCountProbe <- mkProbe;
   let writeDataMimoEnqReadyProbe <- mkProbe;
   Probe#(Bool) writeInProgressProbe <- mkProbe;
   Probe#(Bit#(10)) writeBurstCountProbe <- mkProbe;
   rule updateProbe0;
      writeDataMimoCountProbe    <= writeDataMimo.count();
      writeDataMimoEnqReadyProbe <= writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords)));
   endrule
   rule updateProbe2;
      writeHeaderAvailableProbe <= writeHeaderTlpWire;
      writeDataMimoEnqProbe <= writeDataMimoEnqWire;
   endrule

   Reg#(Bool) writeDataCntAboveThreshold <- mkReg(False);
   rule noheader if (!tlpWriteHeaderFifo.notEmpty());
      writeDataCntAboveThreshold <= False;
   endrule
   rule updateWriteDataCntAboveThreshold if (writeInProgress || !writeDataCntAboveThreshold);
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));
   endrule
   (* descending_urgency = "writeHeaderTlp,updateWriteDataCntAboveThreshold" *)
   rule writeHeaderTlp if (!writeInProgress && writeDataCntAboveThreshold);
      // update for next cycle
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));

      writeHeaderTlpWire <= True;
      let info <- toGet(tlpWriteHeaderFifo).get();
      let tlp     = info.tlp;
      let dwCount = info.dwCount;
      let is3dw   = info.is3dw;
      let isHeaderOnly = info.isHeaderOnly;

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      if (is3dw) begin
	 if (hdr_3dw.format != MEM_WRITE_3DW_DATA)
	    $display("MemSlaveEngine: expecting MEM_WRITE_3DW_DATA, got %d", hdr_3dw.format);
	 Vector#(4, Bit#(32)) v = unpack(0);
         tlp.sof = True;
`ifdef AXI
         v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
         tlp.eof = (dwCount == 1) ? True : False;
         dwCount = dwCount - 1;
         writeDataCnt.decrement(1);
`elsif AVALON
         let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
         // if quad-word aligned, insert bubble.
         if (!quadWordAligned) begin
            v = writeDataMimo.first();
            writeDataMimo.deq(1);
            hdr_3dw.data = v[0];
         end
         else begin
            hdr_3dw.data = unpack(0);
         end
         tlp.eof = (dwCount == 1 && !quadWordAligned) ? True : False;
         if (!quadWordAligned) begin
            dwCount = dwCount - 1;
            writeDataCnt.decrement(1);
         end
`endif
	 tlp.be = 16'hffff;
	 tlp.data = pack(hdr_3dw);
      end
      else begin
         quadAlignedTlpHandled <= isQuadWordAligned(getLowerAddr(truncate(unpack(hdr_4dw.addr)), hdr_4dw.firstbe));
	 tlp.be = 16'hffff;
      end

      tlpOutFifo.enq(tlp);
      $display("writeHeaderTlp dwCount=%d", dwCount);
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      writeInProgress <= (dwCount != 0);
      writeInProgressProbe <= (dwCount != 0);
      if (isHeaderOnly) begin
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
      end

   endrule

   rule writeTlps if (writeInProgress); // already verified  writeDataMimo.deqReadyN(tlpDwCount)) for this transaction
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);
      Integer currDwCount = 4;

`ifdef AVALON
      if (!quadAlignedTlpHandled) begin
         currDwCount = 3; // 3 Data Dwords in this cycle.
         quadAlignedTlpHandled <= True;
      end
`endif

      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      writeDataMimo.deq(tlpDwCount);
      v = writeDataMimo.first();
      let dwCount = writeDwCount - extend(pack(tlpDwCount));
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(fromInteger(currDwCount),unpack(dwCount)));
      writeDataCnt.decrement(unpack(extend(pack(tlpDwCount))));
      lastTlp <= (dwCount <= 4);
      if (tlpDwCount == 4)
	 tlp.be = 16'hffff;
      else if (tlpDwCount == 3)
	 tlp.be = 16'hfff0;
      else if (tlpDwCount == 2)
	 tlp.be = 16'hff00;
      else if (tlpDwCount == 1)
	 tlp.be = 16'hf000;
      tlp.eof = lastTlp;
      if (lastTlp) begin
	 writeInProgress <= False;
	 writeInProgressProbe <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 $display("writeDwCount=%d will be zero", writeDwCount);
      end

      for (Integer i = 0; i < currDwCount; i = i + 1) begin
`ifdef AXI
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(v[(currDwCount-1)-i]);
`elsif AVALON
	 tlp.data[(i+1)*32-1:i*32] = v[(currDwCount-1)-i];
`endif
      end

      tlpOutFifo.enq(tlp);
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   FIFOF#(TLPData#(16)) tlpDecodeFifo <- mkFIFOF();
   Reg#(TLPLength) wordCountReg <- mkReg(0);
   rule tlpInRule;
      let tlp <- toGet(tlpInFifo).get();
      tlpDecodeFifo.enq(tlp);
   endrule

   rule handleTlpRule;
      let tlp = tlpDecodeFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);
      let wordCount = wordCountReg;
`ifdef AXI
      let dataInSecondTlp = False;
`elsif AVALON
      let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
      let dataInSecondTlp = quadWordAligned;
`endif
      if (!tlp.sof) begin
	 vec = reverse(tlpvec);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReady()
	    && completionTagMimo.enqReady())
	    begin
	       UInt#(3) count = 4;
	       if (tlp.eof) begin
		  count = truncate(unpack(wordCountReg));
	       end
	       wordCount = wordCountReg - extend(pack(count));
	       completionMimo.enq(count, vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(count, tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReady()
	       && completionTagMimo.enqReady()) begin
            TLPTag tag = hdr_completion.tag;
            lastTag <= tag;
            if (!dataInSecondTlp) begin
               vec[0] = hdr_3dw.data;
               wordCount = hdr_3dw.length - 1;
               completionMimo.enq(1, vec);
               completionTagMimo.enq(1, replicate(tag));
            end
	    handled = True;
      end
      wordCountReg <= wordCount;
      $display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled) begin
	 tlpDecodeFifo.deq();
      end
   endrule

   FIFO#(PhysMemRequest#(40)) readReqFifo <- mkFIFO();
   rule readReqRule if (!writeInProgress && !writeDataMimo.deqReady());
      let req <- toGet(readReqFifo).get();
      let burstLen = req.burstLen >> beat_shift;
      let addr = req.addr;
      let arid = req.tag;

      TLPData#(16) tlp = defaultValue;
      tlp.sof = True;
      tlp.eof = True;
      tlp.hit = 7'h00;
      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
      if (addr[39:32] != 0) begin
	 TLPMemory4DWHeader hdr_4dw = defaultValue;
	 hdr_4dw.format = MEM_READ_4DW_NO_DATA;
	 hdr_4dw.tag = extend(arid);
	 hdr_4dw.reqid = my_id;
	 hdr_4dw.nosnoop = SNOOPING_REQD;
	 hdr_4dw.addr = addr[40-1:2];
	 hdr_4dw.length = tlplen;
	 hdr_4dw.firstbe = 4'hf;
	 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_4dw);
	 tlp.be = 16'hffff;
      end
      else begin
	 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	 hdr_3dw.format = MEM_READ_3DW_NO_DATA;
	 hdr_3dw.tag = extend(arid);
	 hdr_3dw.reqid = my_id;
	 hdr_3dw.nosnoop = SNOOPING_REQD;
	 hdr_3dw.addr = addr[32-1:2];
	 hdr_3dw.length = tlplen;
	 hdr_3dw.firstbe = 4'hf;
	 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_3dw);
	 tlp.be = 16'hfff0;
      end
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface PhysMemSlave slave;
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(40) req); // if (writeBurstCount == 0);
	    let burstLen = req.burstLen >> beat_shift;
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;

	    TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
	    TLPData#(16) tlp = defaultValue;
	    tlp.sof = True;
	    tlp.eof = False;
	    tlp.hit = 7'h00;
	    tlp.be = 16'hffff;

	    $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	    if ((addr >> 32) != 0) begin
	       TLPMemory4DWHeader hdr_4dw = defaultValue;
	       hdr_4dw.format = MEM_WRITE_4DW_DATA;
	       hdr_4dw.tag = extend(awid);
	       hdr_4dw.reqid = my_id;
	       hdr_4dw.nosnoop = SNOOPING_REQD;
	       hdr_4dw.addr = addr[40-1:2];
	       hdr_4dw.length = tlplen;
	       hdr_4dw.firstbe = 4'hf;
	       hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	       tlp.data = pack(hdr_4dw);
	    end
	    else begin
	       writeIs3dw = True;
	       TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	       hdr_3dw.format = MEM_WRITE_3DW_DATA;
	       hdr_3dw.tag = extend(awid);
	       hdr_3dw.reqid = my_id;
	       hdr_3dw.nosnoop = SNOOPING_REQD;
	       hdr_3dw.addr = addr[32-1:2];
	       hdr_3dw.length = tlplen;
	       hdr_3dw.firstbe = 4'hf;
	       hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

	       tlp.be = 16'hfff0; // no data word in this TLP

	       tlp.data = pack(hdr_3dw);
	    end
	    tlpWriteHeaderFifo.enq(TlpWriteHeaderInfo {tlp: tlp, dwCount: tlplen, is3dw: writeIs3dw, isHeaderOnly: (writeIs3dw && tlplen == 1) });
	    writeBurstCountFifo.enq(extend(burstLen));
	    writeTag.enq(extend(awid));
         endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	    let burstLen = writeBurstCount;
	    if (burstLen == 0) begin
	       burstLen <- toGet(writeBurstCountFifo).get();
	    end
	    writeBurstCount <= extend(burstLen-1);
	    writeBurstCountProbe <= extend(burstLen-1);

	    Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	    writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
            writeDataCnt.increment(fromInteger(valueOf(busWidthWords)));
	    writeDataMimoEnqWire <= True;
         endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(40) req);
	    readReqFifo.enq(req);
         endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReady()
							   && completionTagMimo.deqReady());
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
              for (Integer i = 0; i < valueOf(busWidthWords); i = i+1) begin
`ifdef AXI
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
`elsif AVALON
		 v[(i+1)*32-1:i*32] = data_v[i];
`endif
              end
	      return MemData { data: v, tag: truncate(tag_v[0]), last: True};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine