MemWriteEngine no longer requires request length to be a multiple of burstLen

// 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 Vector::*;
import BuildVector::*;
import Cntrs::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import MemTypes::*;
import Pipe::*;
import ConnectalConfig::*;

`include "ConnectalProjectConfig.bsv"

module mkMemWriteEngine(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Add#(1, d__, busWidth)
	    ,Add#(1, d__, userWidth)
	    ,Add#(e__, TLog#(numServers), MemTagSize)
	    ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
	    ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
	    ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	    );
   let rv <- mkMemWriteEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

interface MemWriteChannel#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth);
   interface PipeIn#(Bit#(MemTagSize))        writeGnt; // grants request
   interface PipeOut#(MemRequest)             writeReq;
   interface PipeOut#(MemData#(userWidth))    writeData;
   interface PipeIn#(Bit#(MemTagSize))        writeDone;
   interface MemWriteEngineServer#(userWidth) writeServer;
endinterface

module mkMemWriteChannel#(Integer bufferSizeBytes, Integer channelNumber,
			  PipeOut#(Bit#(MemTagSize)) writeGntPipe, PipeOut#(Bit#(MemTagSize)) writeDonePipe)
   (MemWriteChannel#(busWidth, userWidth, cmdQDepth))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, d__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))       serverCond <- mkFIFO1();
   FIFO#(Tuple2#(Bit#(MemTagSize),MemengineCmd)) serverReq <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(MemTagSize),Bool))inProgress <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(MemTagSize),Bit#(MemTagSize),Bool)) serverDone <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFOF#(MemRequest)           writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();

   Reg#(Bool)              clientInFlight <- mkReg(False);
   Reg#(Bool)              clientBursts <- mkReg(False);
   ConfigCounter#(16)      clientAvail <- mkConfigCounter(0);
   Reg#(MemengineCmd)      clientStart <- mkReg(unpack(0));
   FIFO#(Bool)             clientFinished <- mkSizedFIFO(1);
   FIFOF#(MemengineCmd)    clientCommand <- mkSizedFIFOF(1);
   Count#(Bit#(32))        clientCycles     <- mkCount(0);
   FIFOF#(MemRequestCycles) clientCyclesFifo <- mkFIFOF();
   FIFOF#(Bit#(userWidth)) dataBuffer <- mkSizedBRAMFIFOF(bufferSizeBeats);
   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule rl_cycles;
      cycles <= cycles + 1;
   endrule

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   rule store_cmd if (!clientInFlight);
      let cmd <- toGet(clientCommand).get();
      clientInFlight <= True;
      clientBursts <= True;
      clientStart <= cmd;
      $display("cycles %d starting request %d bytes %d", cycles, cmd.tag, cmd.len);
      clientCycles <= 0;
   endrule
   rule rule_request_cycles;
      clientCycles.incr(1);
   endrule

   rule load_ctxt_a if (!load_in_progress);
      if (clientBursts) begin
	 load_in_progress <= True;
	 let cmd = clientStart;
	 let cond0 <- clientAvail.maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 serverCond.enq(tuple3(cmd,cond0,cond1));
      end
   endrule

   rule load_ctxt_b if (load_in_progress);
      load_in_progress <= False;
      match {.cmd,.cond0,.cond1} <- toGet(serverCond).get;
      if  (cond0) begin
	 //$display("load_ctxt_b cycles %d %h", cycles, cmd.base);
	 serverReq.enq(tuple2(0,cmd));
	 if (cond1) begin
	    clientBursts <= False;
	 end
	 else begin
	    clientStart <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
               burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule rlWriteReq;
      match {.idx, .cmd} <- toGet(serverReq).get;
      Bit#(BurstLenSize) bl = cmd.burstLen;
      Bool last = False;
      if (cmd.len <= extend(bl)) begin
	 last = True;
	 bl = truncate(cmd.len);
      end
      inProgress.enq(tuple3(truncate(bl>>beat_shift), cmd.tag, last));
      //$display("writeReq %d, %h %h %h", channelNumber, cmd.base, bl, last);
      writeReqFifo.enq(MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: fromInteger(channelNumber)});
   endrule

   rule rlWriteData;
      match {.rc, .client_tag, .last} = inProgress.first;
      //let gnt = writeGntPipe.first;
      let new_respCnt = respCnt+1;
      let lastBeat = False;
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 inProgress.deq();
	 //writeGntPipe.deq();
	 serverDone.enq(tuple3(0,client_tag,last));
	 lastBeat = True;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      let wd <- toGet(dataBuffer).get();
      writeDataFifo.enq(MemData{data:wd, tag:fromInteger(channelNumber), last:lastBeat});
   endrule

   rule rlWriteDone;
      let tag <- toGet(writeDonePipe).get();
      match {.idx, .req_tag, .last} <- toGet(serverDone).get;
      if (last) begin
	 clientInFlight <= False;
	 clientFinished.enq(True);
`ifdef MEMENGINE_REQUEST_CYCLES
	 $display("cycles %d req_tag %d clientCycles = %d", cycles, req_tag, clientCycles);
	 clientCyclesFifo.enq(MemRequestCycles { tag: req_tag, cycles: clientCycles });
`endif
      end
      //$display("writeDone %d %d", channelNumber, last);
   endrule

   MemWriteEngineServer#(userWidth) ws = (interface MemWriteEngineServer#(userWidth);
      interface Put request;
	 method Action put(MemengineCmd cmd);
	    Bit#(32) bsb = fromInteger(bufferSizeBytes);
      `ifdef SIMULATION
	    Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
	    Bit#(32) bl = extend(cmd.burstLen);
	    // this is because bsc lifts the divide operation (below)
	    // and on startup the simulator gets a floating-point exception
	    if (bl ==0)
	       bl = 1;
	    let mdw1 = ((cmd.len)/dw)*dw != cmd.len;
	    let bbl = extend(cmd.burstLen) > bsb;
	    if(bbl || mdw1 || cmd.len == 0) begin
	       if (bbl)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
	       if (mdw1 || cmd.len == 0)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported len %h mdw1=%d", cmd.len, mdw1);
	    end
	    else
      `endif
	       begin
		  clientCommand.enq(cmd);
		  $display("(%d) %h %h %h", channelNumber, cmd.base, cmd.len, cmd.burstLen);
	       end
	 endmethod
      endinterface
      interface Get done;
	 method ActionValue#(Bool) get = toGet(clientFinished).get;
      endinterface
      interface PipeIn data = interface PipeIn;
				 method Bool notFull = dataBuffer.notFull;
   				 method Action enq(Bit#(userWidth) v);
				    dataBuffer.enq(v);
				    clientAvail.increment(1);
				 endmethod
			      endinterface;
	 interface PipeOut requestCycles = toPipeOut(clientCyclesFifo);
	 endinterface);
   interface writeServer = ws;
   interface writeReq = toPipeOut(writeReqFifo);
   interface writeData = toPipeOut(writeDataFifo);
endmodule

module mkMemWriteEngineBuff#(Integer bufferSizeBytes)(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, a__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     ,Add#(b__, TLog#(numServers), MemTagSize)
             ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
             ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
             ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	     );

   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();
   function Tuple2#(Bit#(TLog#(numServers)),Bit#(MemTagSize)) tagDone(Bit#(MemTagSize) tag);
      return tuple2(truncate(tag), tag);
   endfunction
`ifdef ARB_FUNNEL
   FIFOF#(Bit#(MemTagSize))       arbFifo <- mkFIFOF1();
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) arbPipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(arbFifo))));
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) donePipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(writeDoneFifo))));
`else
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   arbFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) arbPipes = map(toPipeOut, arbFifos);
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   doneFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) donePipes = map(toPipeOut, doneFifos);
`endif
   Vector#(numServers, MemWriteChannel#(busWidth,userWidth,cmdQDepth)) writeChannels <- zipWith3M(mkMemWriteChannel(bufferSizeBytes),
												  genVector(),
												  arbPipes,
												  donePipes);
   function PipeOut#(MemRequest) writeChannelDmaWriteReq(Integer i);
      return writeChannels[i].writeReq;
   endfunction
   function PipeOut#(MemData#(userWidth)) writeChannelDmaWriteData(Integer i);
      return writeChannels[i].writeData;
   endfunction
   function MemWriteEngineServer#(userWidth) writeChannelServer(Integer i);
      return writeChannels[i].writeServer;
   endfunction

   Reg#(Bool)         reqInFlight <- mkReg(False);
   Reg#(Bool)         reqNotDone  <- mkReg(False);
   Reg#(Bit#(TLog#(numServers))) currentChannel <- mkReg(0);
   FIFOF#(MemRequest)          writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkSizedFIFOF(16);
   FunnelPipe#(1,numServers,MemRequest,2) reqFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteReq));
//   FunnelPipe#(1,numServers,MemData#(userWidth),2) dataFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteData));

   rule rl_arbitration if (!reqInFlight && !reqNotDone);
      let req <- toGet(reqFunnel[0]).get();
      // tag is channel number
      currentChannel <= truncate(req.tag);
      reqNotDone  <= True;
      writeReqFifo.enq(req);
      reqInFlight <= True;
   endrule
   rule rl_writeData if (reqInFlight);
      MemData#(userWidth) md <- toGet(writeChannels[currentChannel].writeData).get();
      if (md.last)
	 reqInFlight <= False;
      writeDataFifo.enq(md);
   endrule

   rule rl_writeDone;
      let tag <- toGet(writeDoneFifo).get();
      doneFifos[tag].enq(tag);
      reqNotDone  <= False;
   endrule

   interface writeServers = genWith(writeChannelServer);
   interface MemWriteClient dmaClient;
      interface writeReq = toGet(writeReqFifo);
      interface writeData = toGet(writeDataFifo);
      interface writeDone = toPut(writeDoneFifo);
   endinterface: dmaClient

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 Vector::*;
import BuildVector::*;
import Cntrs::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import MemTypes::*;
import Pipe::*;
import ConnectalConfig::*;

`include "ConnectalProjectConfig.bsv"

module mkMemWriteEngine(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Add#(1, d__, busWidth)
	    ,Add#(1, d__, userWidth)
	    ,Add#(e__, TLog#(numServers), MemTagSize)
	    ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
	    ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
	    ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	    );
   let rv <- mkMemWriteEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

interface MemWriteChannel#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth);
   interface PipeIn#(Bit#(MemTagSize))        writeGnt; // grants request
   interface PipeOut#(MemRequest)             writeReq;
   interface PipeOut#(MemData#(userWidth))    writeData;
   interface PipeIn#(Bit#(MemTagSize))        writeDone;
   interface MemWriteEngineServer#(userWidth) writeServer;
endinterface

module mkMemWriteChannel#(Integer bufferSizeBytes, Integer channelNumber,
			  PipeOut#(Bit#(MemTagSize)) writeGntPipe, PipeOut#(Bit#(MemTagSize)) writeDonePipe)
   (MemWriteChannel#(busWidth, userWidth, cmdQDepth))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, d__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))       serverCond <- mkFIFO1();
   FIFO#(Tuple2#(Bit#(MemTagSize),MemengineCmd)) serverReq <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(MemTagSize),Bool))inProgress <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(MemTagSize),Bit#(MemTagSize),Bool)) serverDone <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFOF#(MemRequest)           writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();

   Reg#(Bool)              clientInFlight <- mkReg(False);
   Reg#(Bool)              clientBursts <- mkReg(False);
   ConfigCounter#(16)      clientAvail <- mkConfigCounter(0);
   Reg#(MemengineCmd)      clientStart <- mkReg(unpack(0));
   FIFO#(Bool)             clientFinished <- mkSizedFIFO(1);
   FIFOF#(MemengineCmd)    clientCommand <- mkSizedFIFOF(1);
   Count#(Bit#(32))        clientCycles     <- mkCount(0);
   FIFOF#(MemRequestCycles) clientCyclesFifo <- mkFIFOF();
   FIFOF#(Bit#(userWidth)) dataBuffer <- mkSizedBRAMFIFOF(bufferSizeBeats);
   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule rl_cycles;
      cycles <= cycles + 1;
   endrule

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   rule store_cmd if (!clientInFlight);
      let cmd <- toGet(clientCommand).get();
      clientInFlight <= True;
      clientBursts <= True;
      clientStart <= cmd;
      $display("cycles %d starting request %d bytes %d", cycles, cmd.tag, cmd.len);
      clientCycles <= 0;
   endrule
   rule rule_request_cycles;
      clientCycles.incr(1);
   endrule

   rule load_ctxt_a if (!load_in_progress);
      if (clientBursts) begin
	 load_in_progress <= True;
	 let cmd = clientStart;
	 let cond0 <- clientAvail.maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 serverCond.enq(tuple3(cmd,cond0,cond1));
      end
   endrule

   rule load_ctxt_b if (load_in_progress);
      load_in_progress <= False;
      match {.cmd,.cond0,.cond1} <- toGet(serverCond).get;
      if  (cond0) begin
	 //$display("load_ctxt_b cycles %d %h", cycles, cmd.base);
	 serverReq.enq(tuple2(0,cmd));
	 if (cond1) begin
	    clientBursts <= False;
	 end
	 else begin
	    clientStart <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
               burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule rlWriteReq;
      match {.idx, .cmd} <- toGet(serverReq).get;
      Bit#(BurstLenSize) bl = cmd.burstLen;
      Bool last = False;
      if (cmd.len <= extend(bl)) begin
	 last = True;
	 bl = truncate(cmd.len);
      end
      inProgress.enq(tuple3(truncate(bl>>beat_shift), cmd.tag, last));
      //$display("writeReq %d, %h %h %h", channelNumber, cmd.base, bl, last);
      writeReqFifo.enq(MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: fromInteger(channelNumber)});
   endrule

   rule rlWriteData;
      match {.rc, .client_tag, .last} = inProgress.first;
      //let gnt = writeGntPipe.first;
      let new_respCnt = respCnt+1;
      let lastBeat = False;
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 inProgress.deq();
	 //writeGntPipe.deq();
	 serverDone.enq(tuple3(0,client_tag,last));
	 lastBeat = True;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      let wd <- toGet(dataBuffer).get();
      writeDataFifo.enq(MemData{data:wd, tag:fromInteger(channelNumber), last:lastBeat});
   endrule

   rule rlWriteDone;
      let tag <- toGet(writeDonePipe).get();
      match {.idx, .req_tag, .last} <- toGet(serverDone).get;
      if (last) begin
	 clientInFlight <= False;
	 clientFinished.enq(True);
`ifdef MEMENGINE_REQUEST_CYCLES
	 $display("cycles %d req_tag %d clientCycles = %d", cycles, req_tag, clientCycles);
	 clientCyclesFifo.enq(MemRequestCycles { tag: req_tag, cycles: clientCycles });
`endif
      end
      //$display("writeDone %d %d", channelNumber, last);
   endrule

   MemWriteEngineServer#(userWidth) ws = (interface MemWriteEngineServer#(userWidth);
      interface Put request;
	 method Action put(MemengineCmd cmd);
	    Bit#(32) bsb = fromInteger(bufferSizeBytes);
      `ifdef SIMULATION
	    Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
	    Bit#(32) bl = extend(cmd.burstLen);
	    // this is because bsc lifts the divide operation (below)
	    // and on startup the simulator gets a floating-point exception
	    if (bl ==0)
	       bl = 1;
	    let mdw0 = ((cmd.len)/bl)*bl != cmd.len;
	    let mdw1 = ((cmd.len)/dw)*dw != cmd.len;
	    let bbl = extend(cmd.burstLen) > bsb;
	    if(bbl || mdw0 || mdw1 || cmd.len == 0) begin
	       if (bbl)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
	       if (mdw0 || mdw1 || cmd.len == 0)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported len %h mdw0=%d mdw1=%d", cmd.len, mdw0, mdw1);
	    end
	    else
      `endif
	       begin
		  clientCommand.enq(cmd);
		  $display("(%d) %h %h %h", channelNumber, cmd.base, cmd.len, cmd.burstLen);
	       end
	 endmethod
      endinterface
      interface Get done;
	 method ActionValue#(Bool) get = toGet(clientFinished).get;
      endinterface
      interface PipeIn data = interface PipeIn;
				 method Bool notFull = dataBuffer.notFull;
   				 method Action enq(Bit#(userWidth) v);
				    dataBuffer.enq(v);
				    clientAvail.increment(1);
				 endmethod
			      endinterface;
	 interface PipeOut requestCycles = toPipeOut(clientCyclesFifo);
	 endinterface);
   interface writeServer = ws;
   interface writeReq = toPipeOut(writeReqFifo);
   interface writeData = toPipeOut(writeDataFifo);
endmodule

module mkMemWriteEngineBuff#(Integer bufferSizeBytes)(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, a__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     ,Add#(b__, TLog#(numServers), MemTagSize)
             ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
             ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
             ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	     );

   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();
   function Tuple2#(Bit#(TLog#(numServers)),Bit#(MemTagSize)) tagDone(Bit#(MemTagSize) tag);
      return tuple2(truncate(tag), tag);
   endfunction
`ifdef ARB_FUNNEL
   FIFOF#(Bit#(MemTagSize))       arbFifo <- mkFIFOF1();
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) arbPipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(arbFifo))));
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) donePipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(writeDoneFifo))));
`else
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   arbFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) arbPipes = map(toPipeOut, arbFifos);
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   doneFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) donePipes = map(toPipeOut, doneFifos);
`endif
   Vector#(numServers, MemWriteChannel#(busWidth,userWidth,cmdQDepth)) writeChannels <- zipWith3M(mkMemWriteChannel(bufferSizeBytes),
												  genVector(),
												  arbPipes,
												  donePipes);
   function PipeOut#(MemRequest) writeChannelDmaWriteReq(Integer i);
      return writeChannels[i].writeReq;
   endfunction
   function PipeOut#(MemData#(userWidth)) writeChannelDmaWriteData(Integer i);
      return writeChannels[i].writeData;
   endfunction
   function MemWriteEngineServer#(userWidth) writeChannelServer(Integer i);
      return writeChannels[i].writeServer;
   endfunction

   Reg#(Bool)         reqInFlight <- mkReg(False);
   Reg#(Bool)         reqNotDone  <- mkReg(False);
   Reg#(Bit#(TLog#(numServers))) currentChannel <- mkReg(0);
   FIFOF#(MemRequest)          writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkSizedFIFOF(16);
   FunnelPipe#(1,numServers,MemRequest,2) reqFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteReq));
//   FunnelPipe#(1,numServers,MemData#(userWidth),2) dataFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteData));

   rule rl_arbitration if (!reqInFlight && !reqNotDone);
      let req <- toGet(reqFunnel[0]).get();
      // tag is channel number
      currentChannel <= truncate(req.tag);
      reqNotDone  <= True;
      writeReqFifo.enq(req);
      reqInFlight <= True;
   endrule
   rule rl_writeData if (reqInFlight);
      MemData#(userWidth) md <- toGet(writeChannels[currentChannel].writeData).get();
      if (md.last)
	 reqInFlight <= False;
      writeDataFifo.enq(md);
   endrule

   rule rl_writeDone;
      let tag <- toGet(writeDoneFifo).get();
      doneFifos[tag].enq(tag);
      reqNotDone  <= False;
   endrule

   interface writeServers = genWith(writeChannelServer);
   interface MemWriteClient dmaClient;
      interface writeReq = toGet(writeReqFifo);
      interface writeData = toGet(writeDataFifo);
      interface writeDone = toPut(writeDoneFifo);
   endinterface: dmaClient

endmodule


parameterized instance definitions

parameterized instance definitions

Change-Id: I54236ff930c9546275973da33250296c85101a28

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012  Bluespec, Inc.  ALL RIGHTS RESERVED.
////////////////////////////////////////////////////////////////////////////////
//  Filename      : PcieConnection.bsv
//  Description   :
////////////////////////////////////////////////////////////////////////////////
package PcieConnection;

// Notes :

////////////////////////////////////////////////////////////////////////////////
/// Imports
////////////////////////////////////////////////////////////////////////////////
import Clocks            ::*;
import Vector            ::*;
import Connectable       ::*;
import GetPut            ::*;
import Reserved          ::*;
import TieOff            ::*;
import DefaultValue      ::*;
import DReg              ::*;
import Gearbox           ::*;
import FIFO              ::*;
import FIFOF             ::*;
import SpecialFIFOs      ::*;

import XilinxCells       ::*;
import PCIE              ::*;
import XbsvXilinx7Pcie   ::*;

////////////////////////////////////////////////////////////////////////////////
/// Connection Instances
////////////////////////////////////////////////////////////////////////////////

// Basic TLPData#(8) connections to PCIE endpoint
instance Connectable#(Get#(TLPData#(8)), PCIE_TRN_XMIT_X7);
   module mkConnection#(Get#(TLPData#(8)) g, PCIE_TRN_XMIT_X7 p)(Empty);
      rule every;
         p.cut_through_mode(0);
         p.configuration_completion_grant(1);  // Core gets to choose
         p.error_forward(0);
	 p.ecrc_generate(0);
	 p.discontinue(0);
      endrule
      rule connect;
         let data <- g.get;
         p.xmit(data);
      endrule
   endmodule
endinstance

instance Connectable#(Put#(TLPData#(8)), PCIE_TRN_RECV_X7);
   module mkConnection#(Put#(TLPData#(8)) p, PCIE_TRN_RECV_X7 r)(Empty);
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         r.non_posted_ok(1);
	 r.non_posted_req(1);
      endrule
      rule connect;
         let data <- r.recv;
         p.put(tpl_3(data));
      endrule
   endmodule
endinstance

// Connections between TLPData#(16) and a PCIE endpoint.
// These are all using the same clock, so the TLPData#(16) accesses
// will not be back-to-back.

instance Connectable#(Get#(TLPData#(16)), PCIE_TRN_XMIT_X7);
   module mkConnection#(Get#(TLPData#(16)) g, PCIE_TRN_XMIT_X7 t)(Empty);
      FIFO#(TLPData#(8)) outFifo <- mkFIFO();

      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         t.cut_through_mode(0);
         t.configuration_completion_grant(1);  // 1 means core gets to choose
         t.error_forward(0);
	 t.ecrc_generate(0);
	 t.discontinue(0);
      endrule
      rule connect;
         let data = outFifo.first; outFifo.deq;
         if (data.be != 0)
            t.xmit(data);
      endrule
      Put#(TLPData#(8)) p = fifoToPut(outFifo);
      mkConnection(g,p);
   endmodule
endinstance

instance Connectable#(Put#(TLPData#(16)), PCIE_TRN_RECV_X7);
   module mkConnection#(Put#(TLPData#(16)) p, PCIE_TRN_RECV_X7 r)(Empty);
      FIFO#(TLPData#(8)) inFifo <- mkFIFO();
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         r.non_posted_ok(1);
	 r.non_posted_req(1);
      endrule
      rule connect;
         let data <- r.recv;
         inFifo.enq(tpl_3(data));
      endrule

      Get#(TLPData#(8)) g = fifoToGet(inFifo);
      mkConnection(g,p);
   endmodule
endinstance

instance Connectable#(PCIE_TRN_XMIT_X7, Get#(TLPData#(numLanes)));
   module mkConnection#(PCIE_TRN_XMIT_X7 p, Get#(TLPData#(numLanes)) g)(Empty);
      mkConnection(g, p);
   endmodule
endinstance

instance Connectable#(PCIE_TRN_RECV_X7, Put#(TLPData#(numLanes)));
   module mkConnection#(PCIE_TRN_RECV_X7 r, Put#(TLPData#(numLanes)) p)(Empty);
      mkConnection(p, r);
   endmodule
endinstance

// Connections between TLPData#(16) and a PCIE endpoint, using a gearbox
// to match data rates between the endpoint and design clocks.

instance ConnectableWithClocks#(PCIE_TRN_XMIT_X7, Get#(TLPData#(16)));
   module mkConnectionWithClocks#(PCIE_TRN_XMIT_X7 p, Get#(TLPData#(16)) g,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);

      ////////////////////////////////////////////////////////////////////////////////
      /// Design Elements
      ////////////////////////////////////////////////////////////////////////////////
      FIFO#(TLPData#(8))                     outFifo             <- mkFIFO(clocked_by fastClock, reset_by fastReset);
      Gearbox#(2, 1, TLPData#(8))            fifoTxData          <- mkNto1Gearbox(slowClock, slowReset, fastClock, fastReset);

      ////////////////////////////////////////////////////////////////////////////////
      /// Rules
      ////////////////////////////////////////////////////////////////////////////////
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         p.cut_through_mode(0);
         p.configuration_completion_grant(1);  // Means the core gets to choose
         p.error_forward(0);
	 p.ecrc_generate(0);
	 p.discontinue(0);
      endrule

      rule get_data;
         function Vector#(2, TLPData#(8)) split(TLPData#(16) in);
            Vector#(2, TLPData#(8)) v = defaultValue;
            v[0].sof  = in.sof;
            v[0].eof  = (in.be[7:0] == 0) ? in.eof : False;
            v[0].hit  = in.hit;
            v[0].be   = in.be[15:8];
            v[0].data = in.data[127:64];
            v[1].sof  = False;
            v[1].eof  = in.eof;
            v[1].hit  = in.hit;
            v[1].be   = in.be[7:0];
            v[1].data = in.data[63:0];
            return v;
         endfunction

         let data <- g.get;
         fifoTxData.enq(split(data));
      endrule

      rule process_outgoing_packets;
         let data = fifoTxData.first; fifoTxData.deq;
         outFifo.enq(head(data));
      endrule

      rule send_data;
         let data = outFifo.first; outFifo.deq;
         // filter out TLPs with 00 byte enable
         if (data.be != 0)
            p.xmit(data);
      endrule

   endmodule
endinstance

instance ConnectableWithClocks#(Get#(TLPData#(16)), PCIE_TRN_XMIT_X7);
   module mkConnectionWithClocks#(Get#(TLPData#(16)) g, PCIE_TRN_XMIT_X7 p,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);

      mkConnectionWithClocks(p, g, fastClock, fastReset, slowClock, slowReset);
   endmodule
endinstance

instance ConnectableWithClocks#(Put#(TLPData#(16)), PCIE_TRN_RECV_X7);
   module mkConnectionWithClocks#(Put#(TLPData#(16)) p, PCIE_TRN_RECV_X7 g,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);

      ////////////////////////////////////////////////////////////////////////////////
      /// Design Elements
      ////////////////////////////////////////////////////////////////////////////////
      FIFO#(TLPData#(8))                        inFifo              <- mkFIFO(clocked_by fastClock, reset_by fastReset);
      Gearbox#(1, 2, TLPData#(8))               fifoRxData          <- mk1toNGearbox(fastClock, fastReset, slowClock, slowReset);

      Reg#(Bool)                                rOddBeat            <- mkRegA(False, clocked_by fastClock, reset_by fastReset);
      Reg#(Bool)                                rSendInvalid        <- mkRegA(False, clocked_by fastClock, reset_by fastReset);

      ////////////////////////////////////////////////////////////////////////////////
      /// Rules
      ////////////////////////////////////////////////////////////////////////////////
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         g.non_posted_ok(1);
	 g.non_posted_req(1);
      endrule
      rule accept_data;
         let data <- g.recv;
         inFifo.enq(tpl_3(data));
      endrule

      rule process_incoming_packets(!rSendInvalid);
         let data = inFifo.first; inFifo.deq;
         rOddBeat     <= !rOddBeat;
         rSendInvalid <= !rOddBeat && data.eof;
         Vector#(1, TLPData#(8)) v = defaultValue;
         v[0] = data;
         fifoRxData.enq(v);
      endrule

      rule send_invalid_packets(rSendInvalid);
         rOddBeat     <= !rOddBeat;
         rSendInvalid <= False;
         Vector#(1, TLPData#(8)) v = defaultValue;
         v[0].eof = True;
         v[0].be  = 0;
         fifoRxData.enq(v);
      endrule

      rule send_data;
         function TLPData#(16) combine(Vector#(2, TLPData#(8)) in);
            return TLPData {sof:   in[0].sof,
                            eof:   in[1].eof,
                            hit:   in[0].hit,
                            be:    { in[0].be,   in[1].be },
                            data:  { in[0].data, in[1].data }
                            };
         endfunction

         fifoRxData.deq;
         p.put(combine(fifoRxData.first));
      endrule

   endmodule
endinstance

instance ConnectableWithClocks#(PCIE_TRN_RECV_X7, Put#(TLPData#(16)));
   module mkConnectionWithClocks#(PCIE_TRN_RECV_X7 g, Put#(TLPData#(16)) p,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);
      mkConnectionWithClocks(p, g, fastClock, fastReset, slowClock, slowReset);
   endmodule
endinstance

endpackage: PcieConnection

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012  Bluespec, Inc.  ALL RIGHTS RESERVED.
////////////////////////////////////////////////////////////////////////////////
//  Filename      : PcieConnection.bsv
//  Description   :
////////////////////////////////////////////////////////////////////////////////
package PcieConnection;

// Notes :

////////////////////////////////////////////////////////////////////////////////
/// Imports
////////////////////////////////////////////////////////////////////////////////
import Clocks            ::*;
import Vector            ::*;
import Connectable       ::*;
import GetPut            ::*;
import Reserved          ::*;
import TieOff            ::*;
import DefaultValue      ::*;
import DReg              ::*;
import Gearbox           ::*;
import FIFO              ::*;
import FIFOF             ::*;
import SpecialFIFOs      ::*;

import XilinxCells       ::*;
import PCIE              ::*;
import XbsvXilinx7Pcie   ::*;

////////////////////////////////////////////////////////////////////////////////
/// Connection Instances
////////////////////////////////////////////////////////////////////////////////

// Basic TLPData#(8) connections to PCIE endpoint
instance Connectable#(Get#(TLPData#(8)), PCIE_TRN_XMIT_X7);
   module mkConnection#(Get#(TLPData#(8)) g, PCIE_TRN_XMIT_X7 p)(Empty);
      rule every;
         p.cut_through_mode(0);
         p.configuration_completion_grant(1);  // Core gets to choose
         p.error_forward(0);
	 p.ecrc_generate(0);
	 p.discontinue(0);
      endrule
      rule connect;
         let data <- g.get;
         p.xmit(data);
      endrule
   endmodule
endinstance

instance Connectable#(Put#(TLPData#(8)), PCIE_TRN_RECV_X7);
   module mkConnection#(Put#(TLPData#(8)) p, PCIE_TRN_RECV_X7 r)(Empty);
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         r.non_posted_ok(1);
	 r.non_posted_req(1);
      endrule
      rule connect;
         let data <- r.recv;
         p.put(tpl_3(data));
      endrule
   endmodule
endinstance

// Connections between TLPData#(16) and a PCIE endpoint.
// These are all using the same clock, so the TLPData#(16) accesses
// will not be back-to-back.

instance Connectable#(Get#(TLPData#(16)), PCIE_TRN_XMIT_X7);
   module mkConnection#(Get#(TLPData#(16)) g, PCIE_TRN_XMIT_X7 t)(Empty);
      FIFO#(TLPData#(8)) outFifo <- mkFIFO();

      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         t.cut_through_mode(0);
         t.configuration_completion_grant(1);  // 1 means core gets to choose
         t.error_forward(0);
	 t.ecrc_generate(0);
	 t.discontinue(0);
      endrule
      rule connect;
         let data = outFifo.first; outFifo.deq;
         if (data.be != 0)
            t.xmit(data);
      endrule
      Put#(TLPData#(8)) p = fifoToPut(outFifo);
      mkConnection(g,p);
   endmodule
endinstance

instance Connectable#(Put#(TLPData#(16)), PCIE_TRN_RECV_X7);
   module mkConnection#(Put#(TLPData#(16)) p, PCIE_TRN_RECV_X7 r)(Empty);
      FIFO#(TLPData#(8)) inFifo <- mkFIFO();
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         r.non_posted_ok(1);
	 r.non_posted_req(1);
      endrule
      rule connect;
         let data <- r.recv;
         inFifo.enq(tpl_3(data));
      endrule

      Get#(TLPData#(8)) g = fifoToGet(inFifo);
      mkConnection(g,p);
   endmodule
endinstance

instance Connectable#(PCIE_TRN_XMIT_X7, Get#(TLPData#(8)));
   module mkConnection#(PCIE_TRN_XMIT_X7 p, Get#(TLPData#(8)) g)(Empty);
      mkConnection(g, p);
   endmodule
endinstance

instance Connectable#(PCIE_TRN_XMIT_X7, Get#(TLPData#(16)));
   module mkConnection#(PCIE_TRN_XMIT_X7 p, Get#(TLPData#(16)) g)(Empty);
      mkConnection(g, p);
   endmodule
endinstance

instance Connectable#(PCIE_TRN_RECV_X7, Put#(TLPData#(8)));
   module mkConnection#(PCIE_TRN_RECV_X7 r, Put#(TLPData#(8)) p)(Empty);
      mkConnection(p, r);
   endmodule
endinstance

instance Connectable#(PCIE_TRN_RECV_X7, Put#(TLPData#(16)));
   module mkConnection#(PCIE_TRN_RECV_X7 r, Put#(TLPData#(16)) p)(Empty);
      mkConnection(p, r);
   endmodule
endinstance

// Connections between TLPData#(16) and a PCIE endpoint, using a gearbox
// to match data rates between the endpoint and design clocks.

instance ConnectableWithClocks#(PCIE_TRN_XMIT_X7, Get#(TLPData#(16)));
   module mkConnectionWithClocks#(PCIE_TRN_XMIT_X7 p, Get#(TLPData#(16)) g,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);

      ////////////////////////////////////////////////////////////////////////////////
      /// Design Elements
      ////////////////////////////////////////////////////////////////////////////////
      FIFO#(TLPData#(8))                     outFifo             <- mkFIFO(clocked_by fastClock, reset_by fastReset);
      Gearbox#(2, 1, TLPData#(8))            fifoTxData          <- mkNto1Gearbox(slowClock, slowReset, fastClock, fastReset);

      ////////////////////////////////////////////////////////////////////////////////
      /// Rules
      ////////////////////////////////////////////////////////////////////////////////
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         p.cut_through_mode(0);
         p.configuration_completion_grant(1);  // Means the core gets to choose
         p.error_forward(0);
	 p.ecrc_generate(0);
	 p.discontinue(0);
      endrule

      rule get_data;
         function Vector#(2, TLPData#(8)) split(TLPData#(16) in);
            Vector#(2, TLPData#(8)) v = defaultValue;
            v[0].sof  = in.sof;
            v[0].eof  = (in.be[7:0] == 0) ? in.eof : False;
            v[0].hit  = in.hit;
            v[0].be   = in.be[15:8];
            v[0].data = in.data[127:64];
            v[1].sof  = False;
            v[1].eof  = in.eof;
            v[1].hit  = in.hit;
            v[1].be   = in.be[7:0];
            v[1].data = in.data[63:0];
            return v;
         endfunction

         let data <- g.get;
         fifoTxData.enq(split(data));
      endrule

      rule process_outgoing_packets;
         let data = fifoTxData.first; fifoTxData.deq;
         outFifo.enq(head(data));
      endrule

      rule send_data;
         let data = outFifo.first; outFifo.deq;
         // filter out TLPs with 00 byte enable
         if (data.be != 0)
            p.xmit(data);
      endrule

   endmodule
endinstance

instance ConnectableWithClocks#(Get#(TLPData#(16)), PCIE_TRN_XMIT_X7);
   module mkConnectionWithClocks#(Get#(TLPData#(16)) g, PCIE_TRN_XMIT_X7 p,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);

      mkConnectionWithClocks(p, g, fastClock, fastReset, slowClock, slowReset);
   endmodule
endinstance

instance ConnectableWithClocks#(Put#(TLPData#(16)), PCIE_TRN_RECV_X7);
   module mkConnectionWithClocks#(Put#(TLPData#(16)) p, PCIE_TRN_RECV_X7 g,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);

      ////////////////////////////////////////////////////////////////////////////////
      /// Design Elements
      ////////////////////////////////////////////////////////////////////////////////
      FIFO#(TLPData#(8))                        inFifo              <- mkFIFO(clocked_by fastClock, reset_by fastReset);
      Gearbox#(1, 2, TLPData#(8))               fifoRxData          <- mk1toNGearbox(fastClock, fastReset, slowClock, slowReset);

      Reg#(Bool)                                rOddBeat            <- mkRegA(False, clocked_by fastClock, reset_by fastReset);
      Reg#(Bool)                                rSendInvalid        <- mkRegA(False, clocked_by fastClock, reset_by fastReset);

      ////////////////////////////////////////////////////////////////////////////////
      /// Rules
      ////////////////////////////////////////////////////////////////////////////////
      (* no_implicit_conditions, fire_when_enabled *)
      rule every;
         g.non_posted_ok(1);
	 g.non_posted_req(1);
      endrule
      rule accept_data;
         let data <- g.recv;
         inFifo.enq(tpl_3(data));
      endrule

      rule process_incoming_packets(!rSendInvalid);
         let data = inFifo.first; inFifo.deq;
         rOddBeat     <= !rOddBeat;
         rSendInvalid <= !rOddBeat && data.eof;
         Vector#(1, TLPData#(8)) v = defaultValue;
         v[0] = data;
         fifoRxData.enq(v);
      endrule

      rule send_invalid_packets(rSendInvalid);
         rOddBeat     <= !rOddBeat;
         rSendInvalid <= False;
         Vector#(1, TLPData#(8)) v = defaultValue;
         v[0].eof = True;
         v[0].be  = 0;
         fifoRxData.enq(v);
      endrule

      rule send_data;
         function TLPData#(16) combine(Vector#(2, TLPData#(8)) in);
            return TLPData {sof:   in[0].sof,
                            eof:   in[1].eof,
                            hit:   in[0].hit,
                            be:    { in[0].be,   in[1].be },
                            data:  { in[0].data, in[1].data }
                            };
         endfunction

         fifoRxData.deq;
         p.put(combine(fifoRxData.first));
      endrule

   endmodule
endinstance

instance ConnectableWithClocks#(PCIE_TRN_RECV_X7, Put#(TLPData#(16)));
   module mkConnectionWithClocks#(PCIE_TRN_RECV_X7 g, Put#(TLPData#(16)) p,
                                  Clock fastClock, Reset fastReset,
                                  Clock slowClock, Reset slowReset)(Empty);
      mkConnectionWithClocks(p, g, fastClock, fastReset, slowClock, slowReset);
   endmodule
endinstance

endpackage: PcieConnection


fixing a bug in application logic

fixing a bug in application logic

// 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 SpecialFIFOs::*;
import FIFOF::*;
import Connectable::*;
import GetPut::*;

import AxiMasterSlave::*;
import Dma::*;
import MemwriteEngine::*;

interface MemwriteRequest;
   method Action startWrite(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
   method Action getStateDbg();
endinterface

interface MemwriteIndication;
   method Action started(Bit#(32) numWords);
   method Action reportStateDbg(Bit#(32) wrCnt, Bit#(32) srcGen);
   method Action writeDone(Bit#(32) v);
endinterface

module  mkMemwriteRequest#(MemwriteIndication indication,
			   ObjectWriteServer#(64) dma_write_server)(MemwriteRequest);

   Reg#(ObjectPointer)     wrPointer <- mkReg(0);
   Reg#(Bit#(8))            burstLen <- mkReg(0);
   Reg#(Bit#(32))             reqLen <- mkReg(0);

   Reg#(Bit#(6))               wrTag <- mkReg(0);
   Reg#(Bit#(32))            respCnt <- mkReg(0);
   Reg#(Bit#(32))           burstCnt <- mkReg(0);
   Reg#(Bit#(32))              wrOff <- mkReg(0);
   Reg#(Bit#(32))             srcGen <- mkReg(0);
   Reg#(Bit#(32))            iterCnt <- mkReg(0);
   FIFO#(Tuple2#(Bool,Bit#(6))) tagFifo <- mkSizedFIFO(6);

   rule wrReq if (wrOff < reqLen);
      let new_wrOff = wrOff + extend(burstLen);
      dma_write_server.writeReq.put(ObjectRequest { pointer: wrPointer, offset: extend(wrOff), burstLen: burstLen, tag: wrTag});
      Bool last = False;
      if (new_wrOff >= reqLen) begin
	 last = True;
	 if (iterCnt > 1)
	    new_wrOff = 0;
	 iterCnt <= iterCnt-1;
      end
      wrOff <= new_wrOff;
      wrTag <= wrTag+1;
      tagFifo.enq(tuple2(last,wrTag));
   endrule

   rule wrData;
      let new_burstCnt = burstCnt+(64/8);
      let new_srcGen = srcGen+2;
      if (new_burstCnt >= extend(burstLen)) begin
	 new_burstCnt = 0;
	 tagFifo.deq;
	 if (tpl_1(tagFifo.first)) begin
	    new_srcGen = 0;
	 end
      end
      burstCnt <= new_burstCnt;
      srcGen <= new_srcGen;
      dma_write_server.writeData.put(ObjectData{data:{srcGen+1,srcGen}, tag: tpl_2(tagFifo.first)});
   endrule

   rule wrDone;
      let new_respCnt = respCnt+extend(burstLen);
      if (new_respCnt >= reqLen) begin
	 new_respCnt = 0;
	 if (iterCnt == 0)
	    indication.writeDone(new_respCnt);
      end
      respCnt <= new_respCnt;
      let rv <- dma_write_server.writeDone.get;
   endrule

   method Action startWrite(Bit#(32) wp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
      $display("startWrite pointer=%d numWords=%h burstLen=%d iterCnt=%d", wp, nw, bl, ic);
      indication.started(nw);
      wrPointer <= wp;
      reqLen    <= nw*4;
      burstLen  <= truncate(bl*4);
      respCnt   <= 0;
      wrOff     <= 0;
      iterCnt   <= ic;
   endmethod

   method Action getStateDbg();
      indication.reportStateDbg(0, srcGen);
   endmethod

endmodule

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

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

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

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

import FIFO::*;
import SpecialFIFOs::*;
import FIFOF::*;
import Connectable::*;
import GetPut::*;

import AxiMasterSlave::*;
import Dma::*;
import MemwriteEngine::*;

interface MemwriteRequest;
   method Action startWrite(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
   method Action getStateDbg();
endinterface

interface MemwriteIndication;
   method Action started(Bit#(32) numWords);
   method Action reportStateDbg(Bit#(32) wrCnt, Bit#(32) srcGen);
   method Action writeDone(Bit#(32) v);
endinterface

module  mkMemwriteRequest#(MemwriteIndication indication,
			   ObjectWriteServer#(64) dma_write_server)(MemwriteRequest);

   Reg#(ObjectPointer)     wrPointer <- mkReg(0);
   Reg#(Bit#(8))            burstLen <- mkReg(0);
   Reg#(Bit#(32))             reqLen <- mkReg(0);

   Reg#(Bit#(6))               wrTag <- mkReg(0);
   Reg#(Bit#(32))            respCnt <- mkReg(0);
   Reg#(Bit#(32))           burstCnt <- mkReg(0);
   Reg#(Bit#(32))              wrOff <- mkReg(0);
   Reg#(Bit#(32))             srcGen <- mkReg(0);
   Reg#(Bit#(32))            iterCnt <- mkReg(0);
   FIFO#(Bit#(6))            tagFifo <- mkSizedFIFO(6);

   rule wrReq if (wrOff < reqLen);
      let new_wrOff = wrOff + extend(burstLen);
      dma_write_server.writeReq.put(ObjectRequest { pointer: wrPointer, offset: extend(wrOff), burstLen: burstLen, tag: wrTag});
      if (new_wrOff >= reqLen) begin
	 if (iterCnt > 1)
	    new_wrOff = 0;
	 iterCnt <= iterCnt-1;
      end
      wrOff <= new_wrOff;
      wrTag <= wrTag+1;
      tagFifo.enq(wrTag);
   endrule

   rule wrData;
      let new_burstCnt = burstCnt+(64/8);
      let new_srcGen = srcGen+2;
      if (new_burstCnt >= extend(burstLen)) begin
	 new_burstCnt = 0;
	 new_srcGen = 0;
	 tagFifo.deq;
      end
      burstCnt <= new_burstCnt;
      srcGen <= new_srcGen;
      dma_write_server.writeData.put(ObjectData{data:{srcGen+1,srcGen}, tag: tagFifo.first});
   endrule

   rule wrDone;
      let new_respCnt = respCnt+extend(burstLen);
      if (new_respCnt >= reqLen) begin
	 new_respCnt = 0;
	 if (iterCnt == 0)
	    indication.writeDone(new_respCnt);
      end
      respCnt <= new_respCnt;
      let rv <- dma_write_server.writeDone.get;
   endrule

   method Action startWrite(Bit#(32) wp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
      $display("startWrite pointer=%d numWords=%h burstLen=%d iterCnt=%d", wp, nw, bl, ic);
      indication.started(nw);
      wrPointer <= wp;
      reqLen    <= nw*4;
      burstLen  <= truncate(bl*4);
      respCnt   <= 0;
      wrOff     <= 0;
      iterCnt   <= ic;
   endmethod

   method Action getStateDbg();
      indication.reportStateDbg(0, srcGen);
   endmethod

endmodule


create 4 taps

create 4 taps

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

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

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

import FIFO::*;
import SpiTap::*;
import SpiRoot::*;
import Connectable::*;

interface SerialconfigIndication;
   method Action ack(Bit#(32) a, Bit#(32) d);
endinterface

interface SerialconfigRequest;
   method Action send(Bit#(32) a, Bit#(32) d);
endinterface

module mkSerialconfigRequest#(SerialconfigIndication indication)(SerialconfigRequest);

   SpiTap tap1 <- mkSpiTap('h11110000);
   SpiTap tap2 <- mkSpiTap('h22220000);
   SpiTap tap3 <- mkSpiTap('h33330000);
   SpiTap tap4 <- mkSpiTap('h44440000);

   mkConnection(tap1.out, tap2.in);
   mkConnection(tap2.out, tap3.in);
   mkConnection(tap3.out, tap4.in);

   FIFO#(SpiItem) spi <- mkSpiRoot(SpiTap{in: tap1.in, out: tap4.out});

   rule getresults;
      indication.ack(spi.first().a, spi.first().d);
      spi.deq();
   endrule

   method Action send(Bit#(32) a, Bit#(32) d);
      spi.enq(SpiItem{a: a, d: d});
   endmethod

endmodule

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

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

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

import FIFO::*;
import SpiTap::*;

interface SerialconfigIndication;
   method Action ack(Bit#(32) a, Bit#(32) d);
endinterface

interface SerialconfigRequest;
   method Action send(Bit#(32) a, Bit#(32) d);
endinterface

module mkSerialconfigRequest#(SerialconfigIndication indication)(SerialconfigRequest);

   SpiTap tap1 <- mkSpiTap('hdeadbeef);
//   SpiTap tap2 <- mkSpiTap('hfeedface);
   FIFO#(SpiItem) spi <- mkSpiRoot(tap1);

   rule getresults;
      indication.ack(spi.first());
      spi.deq();
   endrule

   method Action send(Bit#(32) a, Bit#(32) d);
      spi.enq(Item{a: a, d: d});
   endmethod

endmodule