fixed compilation problems with mkSyncBlueScopeInternal with multiple clock domains

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

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

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

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

import Clocks::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;

import AxiDMA::*;
import ClientServer::*;

interface BlueScopeIndication;
   method Action triggerFired();
   method Action reportStateDbg(Bit#(64) mask, Bit#(64) value);
endinterface

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

interface BlueScopeInternal;
   method Action dataIn(Bit#(64) d, Bit#(64) t);
   interface BlueScopeRequest requestIfc;
endinterface

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

module mkBlueScopeInternal#(Integer samples, WriteChan wchan, BlueScopeIndication indication)(BlueScopeInternal);
   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;
   let rv  <- mkSyncBlueScopeInternal(samples, wchan, indication, clk, rst, clk,rst);
   return rv;
endmodule

module mkSyncBlueScopeInternal#(Integer samples, WriteChan wchan, BlueScopeIndication indication, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScopeInternal);
   SyncFIFOIfc#(Bit#(64)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sRst, dClk, dRst);
   Reg#(Bit#(64))    maskReg <- mkSyncReg(0, dClk, dRst, sClk);
   Reg#(Bit#(64))   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);
   //FIFOF#(void)                  tfifo <- mkFIFOF(    clocked_by sClk, reset_by sRst);
   SyncPulseIfc             resetPulse <- mkSyncPulse(dClk, dRst, sClk);
   SyncPulseIfc         triggeredPulse <- mkSyncPulse(sClk, sRst, dClk);

   rule resetState if (resetPulse.pulse);
      stateReg <= Idle;
      countReg <= 0;
   endrule

   rule writeReq if (dfifo.notEmpty);
      wchan.writeReq.put(?);
   endrule

   rule  writeData;
      dfifo.deq;
      wchan.writeData.put(dfifo.first);
   endrule

   rule writeDone;
      wchan.writeDone.get;
   endrule

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

   method Action dataIn(Bit#(64) data, Bit#(64) 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();
	 stateReg <= Enabled;
      endmethod

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

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

      method Action setTriggerValue(Bit#(64) value);
	 valueReg <= value;
      endmethod

      method Action getStateDbg();
	 indication.reportStateDbg(maskReg,valueReg);
      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 Clocks::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;

import AxiDMA::*;
import ClientServer::*;

interface BlueScopeIndication;
   method Action triggerFired();
   method Action reportStateDbg(Bit#(64) mask, Bit#(64) value);
endinterface

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

interface BlueScopeInternal;
   method Action dataIn(Bit#(64) d, Bit#(64) t);
   interface BlueScopeRequest requestIfc;
endinterface

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

module mkBlueScopeInternal#(Integer samples, WriteChan wchan, BlueScopeIndication indication)(BlueScopeInternal);
   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;
   let rv  <- mkSyncBlueScopeInternal(samples, wchan, indication, clk, rst, clk,rst);
   return rv;
endmodule

module mkSyncBlueScopeInternal#(Integer samples, WriteChan wchan, BlueScopeIndication indication, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScopeInternal);
   SyncFIFOIfc#(Bit#(64)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sRst, dClk, dRst);
   Reg#(Bit#(64))    maskReg <- mkReg(0,    clocked_by sClk, reset_by sRst);
   Reg#(Bit#(64))   valueReg <- mkReg(0,    clocked_by sClk, reset_by sRst);
   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);
   FIFOF#(void)                  tfifo <- mkFIFOF(    clocked_by sClk, reset_by sRst);

   rule writeReq if (stateReg == Enabled && dfifo.notEmpty);
      wchan.writeReq.put(?);
   endrule

   rule  writeData;
      dfifo.deq;
      wchan.writeData.put(dfifo.first);
   endrule

   rule writeDone;
      wchan.writeDone.get;
   endrule

   rule triggerRule;
      indication.triggerFired;
      tfifo.deq;
   endrule

   method Action dataIn(Bit#(64) data, Bit#(64) 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 && tfifo.notFull)
	 tfifo.enq(?);
      countReg <= c;
      stateReg <= s;
   endmethod

   interface BlueScopeRequest requestIfc;
      method Action start();
	 stateReg <= Enabled;
      endmethod

      method Action reset();
	 stateReg <= Idle;
	 countReg <= 0;
      endmethod

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

      method Action setTriggerValue(Bit#(64) value);
	 valueReg <= value;
      endmethod

      method Action getStateDbg();
	 indication.reportStateDbg(maskReg,valueReg);
      endmethod

   endinterface

endmodule


set MemData.last to True for last beat of read burst

// 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 Vector       :: *;
import ClientServer :: *;
import MIMO         :: *;
import Probe        :: *;

import ConnectalMimo :: *;
import MIFO         :: *;
import MemTypes     :: *;
import ConfigCounter ::*;

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

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

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

typedef 64 WriteDataMimoSize;
typedef TAdd#(1,TLog#(WriteDataMimoSize)) WriteDataBurstLenSize;
module mkMemToPcie#(PciId my_id)(MemToPcie#(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,Tuple2#(TLPTag,Bool)) completionTagMimo <- mkMIFO(); // tag, last beat of burst

   mimoCfg.bram_based = True;
   mimoCfg.unguarded = True;
    MIMO#(busWidthWords,4,WriteDataMimoSize,Bit#(32)) writeDataMimo <- ConnectalMimo::mkMIMOBram(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);
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);

   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("MemToPcie: 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);
      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;
	 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
`ifdef PCIE3
	 tlp.data[(i+1)*32-1:i*32] = v[i];
`else
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(v[(currDwCount-1)-i]);
`endif
`elsif AVALON
	 tlp.data[(i+1)*32-1:i*32] = v[(currDwCount-1)-i];
`endif
      end

      tlpOutFifo.enq(tlp);
   endrule: writeTlps

   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
`ifdef PCIE3
	 vec = tlpvec;
`else
	 vec = reverse(tlpvec);
`endif
	 // 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);
	       function Tuple2#(TLPTag,Bool) taglast(Integer i); return tuple2(lastTag, (fromInteger(i) == (count-1)) ? tlp.eof : False); endfunction
	       Vector#(4, Tuple2#(TLPTag,Bool)) tagvec = genWith(taglast);
	       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(tuple2(tag,tlp.eof)));
            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,buswidth)) 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 = reqFirstByteEnable(req)[3:0];
	 hdr_4dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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 = reqFirstByteEnable(req)[3:0];
	 hdr_3dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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,buswidth) req); // if (writeBurstCount == 0);
	    Bit#(WriteDataBurstLenSize) burstLen = truncate(req.burstLen >> beat_shift);
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;
	    let use3dw = True;
`ifdef PCIE3
	    awid = awid | 6'h10;
	    use3dw = False;
`endif
	    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 || !use3dw) 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 = reqFirstByteEnable(req)[3:0];
	       hdr_4dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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 = reqFirstByteEnable(req)[3:0];
	       hdr_3dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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);

	    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,buswidth) 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_last_v = completionTagMimo.first;
	      match { .tag, .last } = tag_last_v[fromInteger(valueOf(busWidthWords))-1];
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
              for (Integer i = 0; i < valueOf(busWidthWords); i = i+1) begin
`ifdef AXI
`ifdef PCIE3
		 v[(i+1)*32-1:i*32] = data_v[i];
`else
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
`endif
`elsif AVALON
		 v[(i+1)*32-1:i*32] = data_v[i];
`endif
              end
	      return MemData { data: v, tag: truncate(tag), last: last}; // last beat of this response burst
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemToPcie

// 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 Vector       :: *;
import ClientServer :: *;
import MIMO         :: *;
import Probe        :: *;

import ConnectalMimo :: *;
import MIFO         :: *;
import MemTypes     :: *;
import ConfigCounter ::*;

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

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

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

typedef 64 WriteDataMimoSize;
typedef TAdd#(1,TLog#(WriteDataMimoSize)) WriteDataBurstLenSize;
module mkMemToPcie#(PciId my_id)(MemToPcie#(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 <- ConnectalMimo::mkMIMOBram(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);
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);

   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("MemToPcie: 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);
      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;
	 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
`ifdef PCIE3
	 tlp.data[(i+1)*32-1:i*32] = v[i];
`else
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(v[(currDwCount-1)-i]);
`endif
`elsif AVALON
	 tlp.data[(i+1)*32-1:i*32] = v[(currDwCount-1)-i];
`endif
      end

      tlpOutFifo.enq(tlp);
   endrule: writeTlps

   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
`ifdef PCIE3
	 vec = tlpvec;
`else
	 vec = reverse(tlpvec);
`endif
	 // 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,buswidth)) 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 = reqFirstByteEnable(req)[3:0];
	 hdr_4dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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 = reqFirstByteEnable(req)[3:0];
	 hdr_3dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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,buswidth) req); // if (writeBurstCount == 0);
	    Bit#(WriteDataBurstLenSize) burstLen = truncate(req.burstLen >> beat_shift);
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;
	    let use3dw = True;
`ifdef PCIE3
	    awid = awid | 6'h10;
	    use3dw = False;
`endif
	    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 || !use3dw) 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 = reqFirstByteEnable(req)[3:0];
	       hdr_4dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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 = reqFirstByteEnable(req)[3:0];
	       hdr_3dw.lastbe = (tlplen > 1) ? reqLastByteEnable(req)[valueOf(busWidthBytes)-1:valueOf(busWidthBytes)-4] : 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);

	    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,buswidth) 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
`ifdef PCIE3
		 v[(i+1)*32-1:i*32] = data_v[i];
`else
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
`endif
`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: mkMemToPcie


fixing count error in decoder

fixing count error in decoder

// Copyright (c) 2014 Cornell University.

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

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

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

package Decoder;

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

import Pipe::*;

import Ethernet::*;

interface Decoder;
   interface PipeIn#(Bit#(66)) decoderIn;
   interface PipeOut#(Bit#(72)) decoderOut;
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   method PcsDbgRec dbg;
endinterface

typedef enum {CONTROL, START, DATA, TERMINATE, ERROR} State
deriving (Bits, Eq);

(* synthesize *)
module mkDecoder(Decoder);

   let verbose = False;
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   Reg#(Bit#(32)) cycle                 <- mkReg(0);
   FIFOF#(Bit#(66))  fifo_in            <- mkBypassFIFOF;
   FIFOF#(Bit#(72))  fifo_out           <- mkBypassFIFOF;
   Vector#(8, FIFOF#(Bit#(8)))  dataFifo      <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(1)))  ctrlFifo      <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(8)))  controlFifo   <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(66))) dataFieldFifo <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(15))) typeRegFifo   <- replicateM(mkFIFOF);
   FIFOF#(Bit#(1)) lane0Seq9cFifo       <- mkFIFOF;
   FIFOF#(Bit#(1)) lane0Seq5cFifo       <- mkFIFOF;
   FIFOF#(Bit#(1)) lane4Seq9cFifo       <- mkFIFOF;
   FIFOF#(Bit#(1)) lane4Seq5cFifo       <- mkFIFOF;

   Wire#(Bool) rx_ready_wire <- mkDWire(False);

   // for debugging
   Reg#(Bit#(64)) debug_bytes <- mkReg(0);
   Reg#(Bit#(64)) debug_starts <- mkReg(0);
   Reg#(Bit#(64)) debug_ends <- mkReg(0);
   Reg#(Bit#(64)) debug_errorframes <- mkReg(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   //-------------------------------------------------------------------------------
   // Extract the control bytes from the data_field bus. This is only
   // routed to the output when the sync_field is \"10\", indicating that
   // a control character has been sent. An idle is 0x00 at the input and this is
   // converted into a 0v07 for the xgmii. The others will be set to error. This
   // is because the other valid control characters except error are decoded
   // by the type field. The positions of each byte are given in figure 49-7 in the spec
   //-------------------------------------------------------------------------------
   rule stage1_decode(rx_ready_wire);
      let v <- toGet(fifo_in).get;
      Bit#(2) sync_field = 0;
      Bit#(8) type_field = 0;
      Bit#(66) data_field = 0;
      Bit#(1) type_1e = 0;
      Bit#(1) type_2d = 0;
      Bit#(1) type_33 = 0;
      Bit#(1) type_66 = 0;
      Bit#(1) type_55 = 0;
      Bit#(1) type_78 = 0;
      Bit#(1) type_4b = 0;
      Bit#(1) type_87 = 0;
      Bit#(1) type_99 = 0;
      Bit#(1) type_aa = 0;
      Bit#(1) type_b4 = 0;
      Bit#(1) type_cc = 0;
      Bit#(1) type_d2 = 0;
      Bit#(1) type_e1 = 0;
      Bit#(1) type_ff = 0;
      Bit#(1) data_word   = 0;
      Bit#(1) control_word = 0;

      Bit#(1) lane0Seq9c = 0;
      Bit#(1) lane0Seq5c = 0;
      Bit#(1) lane4Seq9c = 0;
      Bit#(1) lane4Seq5c = 0;

      Bit#(15) type_reg = 0;

      sync_field = v[1:0];
      type_field = v[9:2];
      data_field = v;

      if(verbose) $display("%d: data in %h", cycle, v);
      Vector#(8, Bit#(8)) ctrl;
      for (Integer i=0; i<8; i=i+1) begin
         Integer idx_hi = (i+1)*7+9;
         Integer idx_lo = (i+1)*7+3;
         if (data_field[idx_hi:idx_lo] == 7'b0000000) begin
            ctrl[i] = 8'b00000111 ; // Idle character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b0101101) begin
            ctrl[i] = 8'b00011100 ; // Reserved 0 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b0110011) begin
            ctrl[i] = 8'b00111100 ; // Reserved 1 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1001011) begin
            ctrl[i] = 8'b01111100 ; // Reserved 2 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1010101) begin
            ctrl[i] = 8'b10111100 ; // Reserved 3 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1100110) begin
            ctrl[i] = 8'b11011100 ; // Reserved 4 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1111000) begin
            ctrl[i] = 8'b11110111 ; // Reserved 5 character.
         end
         else begin
            ctrl[i] = 8'b11111110 ; // Error character.
         end
         controlFifo[i].enq(ctrl[i]);
      end

      //for (Integer i=0; i<8; i=i+1) begin
      //   if(verbose) $display("%d: ctrl[%d]=%h", cycle, i, ctrl[i]);
      //end

      //-------------------------------------------------------------------------------
      // Decode the sync field and the type field to determine what sort of data
      // word was transmitted. The different types are given in figure 49-7 in the spec.
      //-------------------------------------------------------------------------------
      data_word = ~(sync_field[0]) & sync_field[1] ;
      control_word = sync_field[0] & ~(sync_field[1]) ;
      type_1e = ~(type_field[7]) & ~(type_field[6]) & ~(type_field[5]) & type_field[4] & type_field[3] & type_field[2] & type_field[1] & ~(type_field[0]) ;
      type_2d = ~(type_field[7]) & ~(type_field[6]) & type_field[5] & ~(type_field[4]) & type_field[3] & type_field[2] & ~(type_field[1]) & type_field[0] ;
      type_33 = ~(type_field[7]) & ~(type_field[6]) & type_field[5] & type_field[4] & ~(type_field[3]) & ~(type_field[2]) & type_field[1] & type_field[0] ;
      type_66 = ~(type_field[7]) & type_field[6] & type_field[5] & ~(type_field[4]) & ~(type_field[3]) & type_field[2] & type_field[1] & ~(type_field[0]) ;
      type_55 = ~(type_field[7]) & type_field[6] & ~(type_field[5]) & type_field[4] & ~(type_field[3]) & type_field[2] & ~(type_field[1]) & type_field[0] ;
      type_78 = ~(type_field[7]) & type_field[6] & type_field[5] & type_field[4] & type_field[3] & ~(type_field[2]) & ~(type_field[1]) & ~(type_field[0]) ;
      type_4b = ~(type_field[7]) & type_field[6] & ~(type_field[5]) & ~(type_field[4]) & type_field[3] & ~(type_field[2]) & type_field[1] & type_field[0] ;
      type_87 = type_field[7] & ~(type_field[6]) & ~(type_field[5]) & ~(type_field[4]) & ~(type_field[3]) & type_field[2] & type_field[1] & type_field[0] ;
      type_99 = type_field[7] & ~(type_field[6]) & ~(type_field[5]) & type_field[4] & type_field[3] & ~(type_field[2]) & ~(type_field[1]) & type_field[0] ;
      type_aa = type_field[7] & ~(type_field[6]) & type_field[5] & ~(type_field[4]) & type_field[3] & ~(type_field[2]) & type_field[1] & ~(type_field[0]) ;
      type_b4 = type_field[7] & ~(type_field[6]) & type_field[5] & type_field[4] & ~(type_field[3]) & type_field[2] & ~(type_field[1]) & ~(type_field[0]) ;
      type_cc = type_field[7] & type_field[6] & ~(type_field[5]) & ~(type_field[4]) & type_field[3] & type_field[2] & ~(type_field[1]) & ~(type_field[0]) ;
      type_d2 = type_field[7] & type_field[6] & ~(type_field[5]) & type_field[4] & ~(type_field[3]) & ~(type_field[2]) & type_field[1] & ~(type_field[0]) ;
      type_e1 = type_field[7] & type_field[6] & type_field[5] & ~(type_field[4]) & ~(type_field[3]) & ~(type_field[2]) & ~(type_field[1]) & type_field[0] ;
      type_ff = type_field[7] & type_field[6] & type_field[5] & type_field[4] & type_field[3] & type_field[2] & type_field[1] & type_field[0] ;

      // debugging
      if (data_word == 1'b1) begin
         debug_bytes <= debug_bytes + 8;
      end
      else if (type_1e == 1'b1) begin
         debug_errorframes <= debug_errorframes + 1;
      end
      else if (type_33 == 1'b1) begin
         debug_starts <= debug_starts + 1;
         debug_bytes <= debug_bytes + 3;
      end
      else if (type_78 == 1'b1) begin
         debug_starts <= debug_starts + 1;
         debug_bytes <= debug_bytes + 7;
      end
      else if (type_87 == 1'b1) begin
         debug_ends <= debug_ends + 1;
      end
      else if (type_99 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 1;
      end
      else if (type_aa == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 2;
      end
      else if (type_b4 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 3;
      end
      else if (type_cc == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 4;
      end
      else if (type_d2 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 5;
      end
      else if (type_e1 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 6;
      end
      else if (type_ff == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 7;
      end

      //-------------------------------------------------------------------------------
      // Translate these signals to give the type of data in each byte.
      // Prior to this the type signals above are registered as the delay through the
      // above equations could be considerable.
      //-------------------------------------------------------------------------------
      type_reg = ({(control_word & type_ff), (control_word & type_e1), (control_word & type_d2), (control_word & type_cc), (control_word & type_b4), (control_word & type_aa), (control_word & type_99), (control_word & type_87), (control_word & type_4b), (control_word & type_78), (control_word & type_55), (control_word & type_66), (control_word & type_33), (control_word & type_2d), (control_word & type_1e)}) ;

      if(verbose) $display("data_field %h", data_field);
      if(verbose) $display("typereg %h", type_reg);

      lane0Seq9c = (sync_field[0] & ~(sync_field[1])) & ((type_66 | type_55 | type_4b) & ~(data_field[35]) & ~(data_field[34]) & ~(data_field[33]) & ~(data_field[32])) ;
      lane0Seq5c = (sync_field[0] & ~(sync_field[1])) & ((type_66 | type_55 | type_4b) & data_field[35] & data_field[34] & data_field[33] & data_field[32]) ;
      lane4Seq9c = (sync_field[0] & ~(sync_field[1])) & ((type_2d | type_55) & ~(data_field[39]) & ~(data_field[38]) & ~(data_field[37]) & ~(data_field[36])) ;
      lane4Seq5c = (sync_field[0] & ~(sync_field[1])) & ((type_2d | type_55) & data_field[39] & data_field[38] & data_field[37] & data_field[36]) ;

      if(verbose) $display("laneseq %d %d %d %d", lane0Seq9c, lane0Seq5c, lane4Seq9c, lane4Seq5c);

      for (Integer i=0; i<8; i=i+1) begin
         dataFieldFifo[i].enq(data_field);
         typeRegFifo[i].enq(type_reg);
      end
      lane0Seq9cFifo.enq(lane0Seq9c);
      lane0Seq5cFifo.enq(lane0Seq5c);
      lane4Seq9cFifo.enq(lane4Seq9c);
      lane4Seq5cFifo.enq(lane4Seq5c);
   endrule

   //-------------------------------------------------------------------------------
   // Put the input data into the correct byte lane at the output.
   //-------------------------------------------------------------------------------
   rule for_lane0;
      let type_reg <- toGet(typeRegFifo[0]).get();
      let control  <- toGet(controlFifo[0]).get();
      let data_field <- toGet(dataFieldFifo[0]).get();
      let lane0_seq_9c <- toGet(lane0Seq9cFifo).get();
      let lane0_seq_5c <- toGet(lane0Seq5cFifo).get();

      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[3]) == 1'b1 && lane0_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field (9C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[3]) == 1'b1 && lane0_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field (5C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane0_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field (9C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane0_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field (5C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[5]) == 1'b1)
      begin
         data = 8'b11111011 ; // Start field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[6]) == 1'b1 && lane0_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field (9C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[6]) == 1'b1 && lane0_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field (5C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[7]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termimation.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:8] != 7'b0000000)
      begin
         data = data_field[17:10] ; // Data byte 0.
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the first data byte.
         data = data_field[9:2] ;
         ctrl = 1'b0 ;
      end
      dataFifo[0].enq(data);
      ctrlFifo[0].enq(ctrl);
   endrule

   rule for_lane1 ;
      let type_reg <- toGet(typeRegFifo[1]).get();
      let control  <- toGet(controlFifo[1]).get();
      let data_field <- toGet(dataFieldFifo[1]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[6:3] != 4'b0000)
      begin
         data = data_field[17:10] ; // Data byte 1
         ctrl = 1'b0 ;
      end
      else if ((type_reg[7]) == 1'b1)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[8]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:9] != 6'b000000)
      begin
         data = data_field[25:18] ; // Data byte 1
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the second data byte.
         data = data_field[17:10] ;
         ctrl = 1'b0 ;
      end
      dataFifo[1].enq(data);
      ctrlFifo[1].enq(ctrl);
   endrule

   rule for_lane2 ;
      let type_reg <- toGet(typeRegFifo[2]).get();
      let control  <- toGet(controlFifo[2]).get();
      let data_field <- toGet(dataFieldFifo[2]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000 || type_reg[8:7] != 2'b00)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[6:3] != 4'b0000)
      begin
         data = data_field[25:18] ; // Data byte 2
         ctrl = 1'b0 ;
      end
      else if ((type_reg[9]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:10] != 5'b00000)
      begin
         data = data_field[33:26] ; // Data byte 2
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the third data byte.
         data = data_field[25:18] ;
         ctrl = 1'b0 ;
      end
      dataFifo[2].enq(data);
      ctrlFifo[2].enq(ctrl);
   endrule

   rule for_lane3 ;
      let type_reg <- toGet(typeRegFifo[3]).get();
      let control  <- toGet(controlFifo[3]).get();
      let data_field <- toGet(dataFieldFifo[3]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000 || type_reg[9:7] != 3'b000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[6:3] != 4'b0000)
      begin
         data = data_field[33:26] ; // Data byte 3
         ctrl = 1'b0 ;
      end
      else if ((type_reg[10]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:11] != 4'b0000)
      begin
         data = data_field[41:34] ; // Data byte 3
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the fourth data byte.
         data = data_field[33:26] ;
         ctrl = 1'b0 ;
      end
      dataFifo[3].enq(data);
      ctrlFifo[3].enq(ctrl);
   endrule

   rule for_lane4 ;
      let type_reg <- toGet(typeRegFifo[4]).get();
      let control  <- toGet(controlFifo[4]).get();
      let data_field <- toGet(dataFieldFifo[4]).get();
      let lane4_seq_9c <- toGet(lane4Seq9cFifo).get();
      let lane4_seq_5c <- toGet(lane4Seq5cFifo).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[10:6] != 5'b00000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[1]) == 1'b1 && lane4_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[1]) == 1'b1 && lane4_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[2]) == 1'b1)
      begin
         data = 8'b11111011 ; // Start field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[3]) == 1'b1)
      begin
         data = 8'b11111011 ; // Start field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane4_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane4_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[5]) == 1'b1)
      begin
         data = data_field[41:34] ; // Termimation.
         ctrl = 1'b0 ;
      end
      else if ((type_reg[11]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:12] != 3'b000)
      begin
         data = data_field[49:42] ; // Data byte 4.
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the fifth data byte.
         data = data_field[41:34] ;
         ctrl = 1'b0 ;
      end
      dataFifo[4].enq(data);
      ctrlFifo[4].enq(ctrl);
   endrule

   rule for_lane5 ;
      let type_reg <- toGet(typeRegFifo[5]).get();
      let control  <- toGet(controlFifo[5]).get();
      let data_field <- toGet(dataFieldFifo[5]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[11:6] != 6'b000000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[5:1] != 5'b00000)
      begin
         data = data_field[49:42] ; // Data byte 5
         ctrl = 1'b0 ;
      end
      else if ((type_reg[12]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:13] != 2'b00)
      begin
         data = data_field[57:50] ; // Data byte 5
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the sixth data byte.
         data = data_field[49:42] ;
         ctrl = 1'b0 ;
      end
      dataFifo[5].enq(data);
      ctrlFifo[5].enq(ctrl);
   endrule

   rule for_lane6 ;
      let type_reg <- toGet(typeRegFifo[6]).get();
      let control  <- toGet(controlFifo[6]).get();
      let data_field <- toGet(dataFieldFifo[6]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[12:6] != 7'b0000000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[5:1] != 5'b00000)
      begin
         data = data_field[57:50] ; // Data byte 6
         ctrl = 1'b0 ;
      end
      else if ((type_reg[13]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[14]) == 1'b1)
      begin
         data = data_field[65:58] ; // Data byte 6
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the seventh data byte.
         data = data_field[57:50] ;
         ctrl = 1'b0 ;
      end
      dataFifo[6].enq(data);
      ctrlFifo[6].enq(ctrl);
   endrule

   rule for_lane7 ;
      let type_reg <- toGet(typeRegFifo[7]).get();
      let control  <- toGet(controlFifo[7]).get();
      let data_field <- toGet(dataFieldFifo[7]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[13:6] != 8'b00000000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[5:1] != 5'b00000)
      begin
         data = data_field[65:58] ; // Data byte 7
         ctrl = 1'b0 ;
      end
      else if ((type_reg[14]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the last data byte.
         data = data_field[65:58] ;
         ctrl = 1'b0 ;
      end
      dataFifo[7].enq(data);
      ctrlFifo[7].enq(ctrl);
   endrule

   rule for_output;
      let data7 <- toGet(dataFifo[7]).get();
      let ctrl7 <- toGet(ctrlFifo[7]).get();
      let data6 <- toGet(dataFifo[6]).get();
      let ctrl6 <- toGet(ctrlFifo[6]).get();
      let data5 <- toGet(dataFifo[5]).get();
      let ctrl5 <- toGet(ctrlFifo[5]).get();
      let data4 <- toGet(dataFifo[4]).get();
      let ctrl4 <- toGet(ctrlFifo[4]).get();
      let data3 <- toGet(dataFifo[3]).get();
      let ctrl3 <- toGet(ctrlFifo[3]).get();
      let data2 <- toGet(dataFifo[2]).get();
      let ctrl2 <- toGet(ctrlFifo[2]).get();
      let data1 <- toGet(dataFifo[1]).get();
      let ctrl1 <- toGet(ctrlFifo[1]).get();
      let data0 <- toGet(dataFifo[0]).get();
      let ctrl0 <- toGet(ctrlFifo[0]).get();

      fifo_out.enq({ctrl7,data7,ctrl6,data6,ctrl5,data5,ctrl4,data4,
                    ctrl3,data3,ctrl2,data2,ctrl1,data1,ctrl0,data0});
   endrule

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   interface decoderIn=toPipeIn(fifo_in);
   interface decoderOut=toPipeOut(fifo_out);
   method PcsDbgRec dbg;
      return PcsDbgRec{bytes:debug_bytes, starts:debug_starts, ends:debug_ends, errorframes:debug_errorframes};
   endmethod
endmodule

endpackage

// Copyright (c) 2014 Cornell University.

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

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

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

package Decoder;

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

import Pipe::*;

import Ethernet::*;

interface Decoder;
   interface PipeIn#(Bit#(66)) decoderIn;
   interface PipeOut#(Bit#(72)) decoderOut;
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   method PcsDbgRec dbg;
endinterface

typedef enum {CONTROL, START, DATA, TERMINATE, ERROR} State
deriving (Bits, Eq);

(* synthesize *)
module mkDecoder(Decoder);

   let verbose = False;
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   Reg#(Bit#(32)) cycle                 <- mkReg(0);
   FIFOF#(Bit#(66))  fifo_in            <- mkBypassFIFOF;
   FIFOF#(Bit#(72))  fifo_out           <- mkBypassFIFOF;
   Vector#(8, FIFOF#(Bit#(8)))  dataFifo      <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(1)))  ctrlFifo      <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(8)))  controlFifo   <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(66))) dataFieldFifo <- replicateM(mkFIFOF);
   Vector#(8, FIFOF#(Bit#(15))) typeRegFifo   <- replicateM(mkFIFOF);
   FIFOF#(Bit#(1)) lane0Seq9cFifo       <- mkFIFOF;
   FIFOF#(Bit#(1)) lane0Seq5cFifo       <- mkFIFOF;
   FIFOF#(Bit#(1)) lane4Seq9cFifo       <- mkFIFOF;
   FIFOF#(Bit#(1)) lane4Seq5cFifo       <- mkFIFOF;

   Wire#(Bool) rx_ready_wire <- mkDWire(False);

   // for debugging
   Reg#(Bit#(64)) debug_bytes <- mkReg(0);
   Reg#(Bit#(64)) debug_starts <- mkReg(0);
   Reg#(Bit#(64)) debug_ends <- mkReg(0);
   Reg#(Bit#(64)) debug_errorframes <- mkReg(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   //-------------------------------------------------------------------------------
   // Extract the control bytes from the data_field bus. This is only
   // routed to the output when the sync_field is \"10\", indicating that
   // a control character has been sent. An idle is 0x00 at the input and this is
   // converted into a 0v07 for the xgmii. The others will be set to error. This
   // is because the other valid control characters except error are decoded
   // by the type field. The positions of each byte are given in figure 49-7 in the spec
   //-------------------------------------------------------------------------------
   rule stage1_decode(rx_ready_wire);
      let v <- toGet(fifo_in).get;
      Bit#(2) sync_field = 0;
      Bit#(8) type_field = 0;
      Bit#(66) data_field = 0;
      Bit#(1) type_1e = 0;
      Bit#(1) type_2d = 0;
      Bit#(1) type_33 = 0;
      Bit#(1) type_66 = 0;
      Bit#(1) type_55 = 0;
      Bit#(1) type_78 = 0;
      Bit#(1) type_4b = 0;
      Bit#(1) type_87 = 0;
      Bit#(1) type_99 = 0;
      Bit#(1) type_aa = 0;
      Bit#(1) type_b4 = 0;
      Bit#(1) type_cc = 0;
      Bit#(1) type_d2 = 0;
      Bit#(1) type_e1 = 0;
      Bit#(1) type_ff = 0;
      Bit#(1) data_word   = 0;
      Bit#(1) control_word = 0;

      Bit#(1) lane0Seq9c = 0;
      Bit#(1) lane0Seq5c = 0;
      Bit#(1) lane4Seq9c = 0;
      Bit#(1) lane4Seq5c = 0;

      Bit#(15) type_reg = 0;

      sync_field = v[1:0];
      type_field = v[9:2];
      data_field = v;

      if(verbose) $display("%d: data in %h", cycle, v);
      Vector#(8, Bit#(8)) ctrl;
      for (Integer i=0; i<8; i=i+1) begin
         Integer idx_hi = (i+1)*7+9;
         Integer idx_lo = (i+1)*7+3;
         if (data_field[idx_hi:idx_lo] == 7'b0000000) begin
            ctrl[i] = 8'b00000111 ; // Idle character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b0101101) begin
            ctrl[i] = 8'b00011100 ; // Reserved 0 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b0110011) begin
            ctrl[i] = 8'b00111100 ; // Reserved 1 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1001011) begin
            ctrl[i] = 8'b01111100 ; // Reserved 2 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1010101) begin
            ctrl[i] = 8'b10111100 ; // Reserved 3 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1100110) begin
            ctrl[i] = 8'b11011100 ; // Reserved 4 character.
         end
         else if (data_field[idx_hi:idx_lo] == 7'b1111000) begin
            ctrl[i] = 8'b11110111 ; // Reserved 5 character.
         end
         else begin
            ctrl[i] = 8'b11111110 ; // Error character.
         end
         controlFifo[i].enq(ctrl[i]);
      end

      //for (Integer i=0; i<8; i=i+1) begin
      //   if(verbose) $display("%d: ctrl[%d]=%h", cycle, i, ctrl[i]);
      //end

      //-------------------------------------------------------------------------------
      // Decode the sync field and the type field to determine what sort of data
      // word was transmitted. The different types are given in figure 49-7 in the spec.
      //-------------------------------------------------------------------------------
      data_word = ~(sync_field[0]) & sync_field[1] ;
      control_word = sync_field[0] & ~(sync_field[1]) ;
      type_1e = ~(type_field[7]) & ~(type_field[6]) & ~(type_field[5]) & type_field[4] & type_field[3] & type_field[2] & type_field[1] & ~(type_field[0]) ;
      type_2d = ~(type_field[7]) & ~(type_field[6]) & type_field[5] & ~(type_field[4]) & type_field[3] & type_field[2] & ~(type_field[1]) & type_field[0] ;
      type_33 = ~(type_field[7]) & ~(type_field[6]) & type_field[5] & type_field[4] & ~(type_field[3]) & ~(type_field[2]) & type_field[1] & type_field[0] ;
      type_66 = ~(type_field[7]) & type_field[6] & type_field[5] & ~(type_field[4]) & ~(type_field[3]) & type_field[2] & type_field[1] & ~(type_field[0]) ;
      type_55 = ~(type_field[7]) & type_field[6] & ~(type_field[5]) & type_field[4] & ~(type_field[3]) & type_field[2] & ~(type_field[1]) & type_field[0] ;
      type_78 = ~(type_field[7]) & type_field[6] & type_field[5] & type_field[4] & type_field[3] & ~(type_field[2]) & ~(type_field[1]) & ~(type_field[0]) ;
      type_4b = ~(type_field[7]) & type_field[6] & ~(type_field[5]) & ~(type_field[4]) & type_field[3] & ~(type_field[2]) & type_field[1] & type_field[0] ;
      type_87 = type_field[7] & ~(type_field[6]) & ~(type_field[5]) & ~(type_field[4]) & ~(type_field[3]) & type_field[2] & type_field[1] & type_field[0] ;
      type_99 = type_field[7] & ~(type_field[6]) & ~(type_field[5]) & type_field[4] & type_field[3] & ~(type_field[2]) & ~(type_field[1]) & type_field[0] ;
      type_aa = type_field[7] & ~(type_field[6]) & type_field[5] & ~(type_field[4]) & type_field[3] & ~(type_field[2]) & type_field[1] & ~(type_field[0]) ;
      type_b4 = type_field[7] & ~(type_field[6]) & type_field[5] & type_field[4] & ~(type_field[3]) & type_field[2] & ~(type_field[1]) & ~(type_field[0]) ;
      type_cc = type_field[7] & type_field[6] & ~(type_field[5]) & ~(type_field[4]) & type_field[3] & type_field[2] & ~(type_field[1]) & ~(type_field[0]) ;
      type_d2 = type_field[7] & type_field[6] & ~(type_field[5]) & type_field[4] & ~(type_field[3]) & ~(type_field[2]) & type_field[1] & ~(type_field[0]) ;
      type_e1 = type_field[7] & type_field[6] & type_field[5] & ~(type_field[4]) & ~(type_field[3]) & ~(type_field[2]) & ~(type_field[1]) & type_field[0] ;
      type_ff = type_field[7] & type_field[6] & type_field[5] & type_field[4] & type_field[3] & type_field[2] & type_field[1] & type_field[0] ;

      // debugging
      if (type_1e == 1'b1) begin
         debug_errorframes <= debug_errorframes + 1;
      end
      else if (type_33 == 1'b1) begin
         debug_starts <= debug_starts + 1;
         debug_bytes <= debug_bytes + 3;
      end
      else if (type_78 == 1'b1) begin
         debug_starts <= debug_starts + 1;
         debug_bytes <= debug_bytes + 7;
      end
      else if (type_87 == 1'b1) begin
         debug_ends <= debug_ends + 1;
      end
      else if (type_99 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 1;
      end
      else if (type_aa == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 2;
      end
      else if (type_b4 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 3;
      end
      else if (type_cc == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 4;
      end
      else if (type_d2 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 5;
      end
      else if (type_e1 == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 6;
      end
      else if (type_ff == 1'b1) begin
         debug_ends <= debug_ends + 1;
         debug_bytes <= debug_bytes + 7;
      end
      else if (data_word == 1'b1) begin
         debug_bytes <= debug_bytes + 8;
      end

      //-------------------------------------------------------------------------------
      // Translate these signals to give the type of data in each byte.
      // Prior to this the type signals above are registered as the delay through the
      // above equations could be considerable.
      //-------------------------------------------------------------------------------
      type_reg = ({(control_word & type_ff), (control_word & type_e1), (control_word & type_d2), (control_word & type_cc), (control_word & type_b4), (control_word & type_aa), (control_word & type_99), (control_word & type_87), (control_word & type_4b), (control_word & type_78), (control_word & type_55), (control_word & type_66), (control_word & type_33), (control_word & type_2d), (control_word & type_1e)}) ;

      if(verbose) $display("data_field %h", data_field);
      if(verbose) $display("typereg %h", type_reg);

      lane0Seq9c = (sync_field[0] & ~(sync_field[1])) & ((type_66 | type_55 | type_4b) & ~(data_field[35]) & ~(data_field[34]) & ~(data_field[33]) & ~(data_field[32])) ;
      lane0Seq5c = (sync_field[0] & ~(sync_field[1])) & ((type_66 | type_55 | type_4b) & data_field[35] & data_field[34] & data_field[33] & data_field[32]) ;
      lane4Seq9c = (sync_field[0] & ~(sync_field[1])) & ((type_2d | type_55) & ~(data_field[39]) & ~(data_field[38]) & ~(data_field[37]) & ~(data_field[36])) ;
      lane4Seq5c = (sync_field[0] & ~(sync_field[1])) & ((type_2d | type_55) & data_field[39] & data_field[38] & data_field[37] & data_field[36]) ;

      if(verbose) $display("laneseq %d %d %d %d", lane0Seq9c, lane0Seq5c, lane4Seq9c, lane4Seq5c);

      for (Integer i=0; i<8; i=i+1) begin
         dataFieldFifo[i].enq(data_field);
         typeRegFifo[i].enq(type_reg);
      end
      lane0Seq9cFifo.enq(lane0Seq9c);
      lane0Seq5cFifo.enq(lane0Seq5c);
      lane4Seq9cFifo.enq(lane4Seq9c);
      lane4Seq5cFifo.enq(lane4Seq5c);
   endrule

   //-------------------------------------------------------------------------------
   // Put the input data into the correct byte lane at the output.
   //-------------------------------------------------------------------------------
   rule for_lane0;
      let type_reg <- toGet(typeRegFifo[0]).get();
      let control  <- toGet(controlFifo[0]).get();
      let data_field <- toGet(dataFieldFifo[0]).get();
      let lane0_seq_9c <- toGet(lane0Seq9cFifo).get();
      let lane0_seq_5c <- toGet(lane0Seq5cFifo).get();

      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[3]) == 1'b1 && lane0_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field (9C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[3]) == 1'b1 && lane0_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field (5C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane0_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field (9C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane0_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field (5C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[5]) == 1'b1)
      begin
         data = 8'b11111011 ; // Start field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[6]) == 1'b1 && lane0_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field (9C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[6]) == 1'b1 && lane0_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field (5C).
         ctrl = 1'b1 ;
      end
      else if ((type_reg[7]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termimation.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:8] != 7'b0000000)
      begin
         data = data_field[17:10] ; // Data byte 0.
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the first data byte.
         data = data_field[9:2] ;
         ctrl = 1'b0 ;
      end
      dataFifo[0].enq(data);
      ctrlFifo[0].enq(ctrl);
   endrule

   rule for_lane1 ;
      let type_reg <- toGet(typeRegFifo[1]).get();
      let control  <- toGet(controlFifo[1]).get();
      let data_field <- toGet(dataFieldFifo[1]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[6:3] != 4'b0000)
      begin
         data = data_field[17:10] ; // Data byte 1
         ctrl = 1'b0 ;
      end
      else if ((type_reg[7]) == 1'b1)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[8]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:9] != 6'b000000)
      begin
         data = data_field[25:18] ; // Data byte 1
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the second data byte.
         data = data_field[17:10] ;
         ctrl = 1'b0 ;
      end
      dataFifo[1].enq(data);
      ctrlFifo[1].enq(ctrl);
   endrule

   rule for_lane2 ;
      let type_reg <- toGet(typeRegFifo[2]).get();
      let control  <- toGet(controlFifo[2]).get();
      let data_field <- toGet(dataFieldFifo[2]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000 || type_reg[8:7] != 2'b00)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[6:3] != 4'b0000)
      begin
         data = data_field[25:18] ; // Data byte 2
         ctrl = 1'b0 ;
      end
      else if ((type_reg[9]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:10] != 5'b00000)
      begin
         data = data_field[33:26] ; // Data byte 2
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the third data byte.
         data = data_field[25:18] ;
         ctrl = 1'b0 ;
      end
      dataFifo[2].enq(data);
      ctrlFifo[2].enq(ctrl);
   endrule

   rule for_lane3 ;
      let type_reg <- toGet(typeRegFifo[3]).get();
      let control  <- toGet(controlFifo[3]).get();
      let data_field <- toGet(dataFieldFifo[3]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if (type_reg[2:0] != 3'b000 || type_reg[9:7] != 3'b000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[6:3] != 4'b0000)
      begin
         data = data_field[33:26] ; // Data byte 3
         ctrl = 1'b0 ;
      end
      else if ((type_reg[10]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:11] != 4'b0000)
      begin
         data = data_field[41:34] ; // Data byte 3
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the fourth data byte.
         data = data_field[33:26] ;
         ctrl = 1'b0 ;
      end
      dataFifo[3].enq(data);
      ctrlFifo[3].enq(ctrl);
   endrule

   rule for_lane4 ;
      let type_reg <- toGet(typeRegFifo[4]).get();
      let control  <- toGet(controlFifo[4]).get();
      let data_field <- toGet(dataFieldFifo[4]).get();
      let lane4_seq_9c <- toGet(lane4Seq9cFifo).get();
      let lane4_seq_5c <- toGet(lane4Seq5cFifo).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[10:6] != 5'b00000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[1]) == 1'b1 && lane4_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[1]) == 1'b1 && lane4_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[2]) == 1'b1)
      begin
         data = 8'b11111011 ; // Start field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[3]) == 1'b1)
      begin
         data = 8'b11111011 ; // Start field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane4_seq_9c == 1'b1)
      begin
         data = 8'b10011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[4]) == 1'b1 && lane4_seq_5c == 1'b1)
      begin
         data = 8'b01011100 ; // Sequence field.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[5]) == 1'b1)
      begin
         data = data_field[41:34] ; // Termimation.
         ctrl = 1'b0 ;
      end
      else if ((type_reg[11]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:12] != 3'b000)
      begin
         data = data_field[49:42] ; // Data byte 4.
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the fifth data byte.
         data = data_field[41:34] ;
         ctrl = 1'b0 ;
      end
      dataFifo[4].enq(data);
      ctrlFifo[4].enq(ctrl);
   endrule

   rule for_lane5 ;
      let type_reg <- toGet(typeRegFifo[5]).get();
      let control  <- toGet(controlFifo[5]).get();
      let data_field <- toGet(dataFieldFifo[5]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[11:6] != 6'b000000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[5:1] != 5'b00000)
      begin
         data = data_field[49:42] ; // Data byte 5
         ctrl = 1'b0 ;
      end
      else if ((type_reg[12]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if (type_reg[14:13] != 2'b00)
      begin
         data = data_field[57:50] ; // Data byte 5
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the sixth data byte.
         data = data_field[49:42] ;
         ctrl = 1'b0 ;
      end
      dataFifo[5].enq(data);
      ctrlFifo[5].enq(ctrl);
   endrule

   rule for_lane6 ;
      let type_reg <- toGet(typeRegFifo[6]).get();
      let control  <- toGet(controlFifo[6]).get();
      let data_field <- toGet(dataFieldFifo[6]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[12:6] != 7'b0000000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[5:1] != 5'b00000)
      begin
         data = data_field[57:50] ; // Data byte 6
         ctrl = 1'b0 ;
      end
      else if ((type_reg[13]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else if ((type_reg[14]) == 1'b1)
      begin
         data = data_field[65:58] ; // Data byte 6
         ctrl = 1'b0 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the seventh data byte.
         data = data_field[57:50] ;
         ctrl = 1'b0 ;
      end
      dataFifo[6].enq(data);
      ctrlFifo[6].enq(ctrl);
   endrule

   rule for_lane7 ;
      let type_reg <- toGet(typeRegFifo[7]).get();
      let control  <- toGet(controlFifo[7]).get();
      let data_field <- toGet(dataFieldFifo[7]).get();
      Bit#(8) data = 0;
      Bit#(1) ctrl = 0;
      if ((type_reg[0]) == 1'b1 || type_reg[13:6] != 8'b00000000)
      begin
         data = control; // Control character.
         ctrl = 1'b1 ;
      end
      else if (type_reg[5:1] != 5'b00000)
      begin
         data = data_field[65:58] ; // Data byte 7
         ctrl = 1'b0 ;
      end
      else if ((type_reg[14]) == 1'b1)
      begin
         data = 8'b11111101 ; // Termination.
         ctrl = 1'b1 ;
      end
      else
      begin
         // If the input doesn\'t contain a control character then the type field
         // is set to be the last data byte.
         data = data_field[65:58] ;
         ctrl = 1'b0 ;
      end
      dataFifo[7].enq(data);
      ctrlFifo[7].enq(ctrl);
   endrule

   rule for_output;
      let data7 <- toGet(dataFifo[7]).get();
      let ctrl7 <- toGet(ctrlFifo[7]).get();
      let data6 <- toGet(dataFifo[6]).get();
      let ctrl6 <- toGet(ctrlFifo[6]).get();
      let data5 <- toGet(dataFifo[5]).get();
      let ctrl5 <- toGet(ctrlFifo[5]).get();
      let data4 <- toGet(dataFifo[4]).get();
      let ctrl4 <- toGet(ctrlFifo[4]).get();
      let data3 <- toGet(dataFifo[3]).get();
      let ctrl3 <- toGet(ctrlFifo[3]).get();
      let data2 <- toGet(dataFifo[2]).get();
      let ctrl2 <- toGet(ctrlFifo[2]).get();
      let data1 <- toGet(dataFifo[1]).get();
      let ctrl1 <- toGet(ctrlFifo[1]).get();
      let data0 <- toGet(dataFifo[0]).get();
      let ctrl0 <- toGet(ctrlFifo[0]).get();

      fifo_out.enq({ctrl7,data7,ctrl6,data6,ctrl5,data5,ctrl4,data4,
                    ctrl3,data3,ctrl2,data2,ctrl1,data1,ctrl0,data0});
   endrule

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   interface decoderIn=toPipeIn(fifo_in);
   interface decoderOut=toPipeOut(fifo_out);
   method PcsDbgRec dbg;
      return PcsDbgRec{bytes:debug_bytes, starts:debug_starts, ends:debug_ends, errorframes:debug_errorframes};
   endmethod
endmodule

endpackage


use a ConfigCounter to track number of tags available

// 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 BRAMFIFO::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import BRAM::*;
import RegFile::*;

// CONNECTAL Libraries
import MemTypes::*;
import ConnectalMemory::*;
import ConfigCounter::*;

interface TagGen#(numeric type numTags);
   method ActionValue#(Bit#(TLog#(numTags))) getTag;
   method Action returnTag(Bit#(TLog#(numTags)) tag);
   method ActionValue#(Bit#(TLog#(numTags))) complete;
endinterface

module mkTagGen(TagGen#(numTags))
   provisos(Log#(numTags,tsz));

   BRAM_Configure cfg = defaultValue;
   cfg.outFIFODepth = 1;
   //BRAM2Port#(Bit#(tsz),Bool) tags <- mkBRAM2Server(cfg);
   Vector#(numTags, Reg#(Bool)) tags <- replicateM(mkReg(False));
   //RegFile#(Bit#(tsz),Bool)     tags <- mkRegFile(0, fromInteger(valueOf(numTags)-1));
   Reg#(Bit#(tsz))        head_ptr <- mkReg(0);
   Reg#(Bit#(tsz))        tail_ptr <- mkReg(0);
   Reg#(Bool)               inited <- mkReg(False);
   FIFO#(Bit#(tsz))      comp_fifo <- mkFIFO;
   Reg#(Bit#(numTags))  comp_state <- mkReg(0);
   ConfigCounter#(TAdd#(tsz,1)) counter <- mkConfigCounter(fromInteger(valueOf(numTags)));

   let retFifo <- mkFIFO;
   let tagFifo <- mkFIFO;

   //rule complete_rule0 (comp_state[0] != 0);
      //tags.portB.request.put(BRAMRequest{write:False, address:tail_ptr, datain: ?, responseOnWrite: ?});
   //endrule

   rule complete_rule1 (comp_state[0] != 0);
      //let rv <- tags.portB.response.get;
      //let rv = tags.sub(tail_ptr);
      let rv = tags[tail_ptr];
      if (!rv) begin
	 tail_ptr <= tail_ptr+1;
	 counter.increment(1);
	 comp_state <= comp_state >> 1;
	 comp_fifo.enq(tail_ptr);
      end
   endrule

   // this used to be in the body of returnTag, but form some reason bsc does not
   // consider access to portA and portB to be conflict free **sigh**
   rule ret_rule;
      let tag <- toGet(retFifo).get;
      //tags.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tag, datain:False});
      //tags.upd(tag, False);
      tags[tag] <= False;
      comp_state <= 1 | (comp_state << 1);
   endrule

   rule init_rule(!inited);
      //tags.portA.request.put(BRAMRequest{write:True,address:head_ptr,responseOnWrite:False,datain:False});
      //tags.upd(head_ptr, False);
      //Not needed: tags[head_ptr] <= False;
      head_ptr <= head_ptr+1;
      inited <= head_ptr+1==0;
   endrule

   rule tag_rule if (inited && counter.positive);
      //tags.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head_ptr, datain:True});
      //tags.upd(head_ptr, True);
      tags[head_ptr] <= True;
      head_ptr <= head_ptr+1;
      tagFifo.enq(head_ptr);
      counter.decrement(1);
   endrule

   method ActionValue#(Bit#(tsz)) getTag();
      let tag <- toGet(tagFifo).get();
      return tag;
   endmethod

   method Action returnTag(Bit#(tsz) tag) if (inited);
      retFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(tsz)) complete;
      comp_fifo.deq;
      return comp_fifo.first;
   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.

// BSV Libraries
import BRAMFIFO::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import BRAM::*;
import RegFile::*;

// CONNECTAL Libraries
import MemTypes::*;
import ConnectalMemory::*;

interface TagGen#(numeric type numTags);
   method ActionValue#(Bit#(TLog#(numTags))) getTag;
   method Action returnTag(Bit#(TLog#(numTags)) tag);
   method ActionValue#(Bit#(TLog#(numTags))) complete;
endinterface

module mkTagGen(TagGen#(numTags))
   provisos(Log#(numTags,tsz));

   BRAM_Configure cfg = defaultValue;
   cfg.outFIFODepth = 1;
   //BRAM2Port#(Bit#(tsz),Bool) tags <- mkBRAM2Server(cfg);
   Vector#(numTags, Reg#(Bool)) tags <- replicateM(mkReg(False));
   //RegFile#(Bit#(tsz),Bool)     tags <- mkRegFile(0, fromInteger(valueOf(numTags)-1));
   Reg#(Bit#(tsz))        head_ptr <- mkReg(0);
   Reg#(Bit#(tsz))        tail_ptr <- mkReg(0);
   Reg#(Bool)               inited <- mkReg(False);
   FIFO#(Bit#(tsz))      comp_fifo <- mkFIFO;
   Reg#(Bit#(numTags))  comp_state <- mkReg(0);

   let retFifo <- mkFIFO;
   let tagFifo <- mkFIFO;

   //rule complete_rule0 (comp_state[0] != 0);
      //tags.portB.request.put(BRAMRequest{write:False, address:tail_ptr, datain: ?, responseOnWrite: ?});
   //endrule

   rule complete_rule1 (comp_state[0] != 0);
      //let rv <- tags.portB.response.get;
      //let rv = tags.sub(tail_ptr);
      let rv = tags[tail_ptr];
      if (!rv) begin
	 tail_ptr <= tail_ptr+1;
	 comp_state <= comp_state >> 1;
	 comp_fifo.enq(tail_ptr);
      end
   endrule

   // this used to be in the body of returnTag, but form some reason bsc does not
   // consider access to portA and portB to be conflict free **sigh**
   rule ret_rule;
      let tag <- toGet(retFifo).get;
      //tags.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tag, datain:False});
      //tags.upd(tag, False);
      tags[tag] <= False;
      comp_state <= 1 | (comp_state << 1);
   endrule

   rule init_rule(!inited);
      //tags.portA.request.put(BRAMRequest{write:True,address:head_ptr,responseOnWrite:False,datain:False});
      //tags.upd(head_ptr, False);
      //Not needed: tags[head_ptr] <= False;
      head_ptr <= head_ptr+1;
      inited <= head_ptr+1==0;
   endrule

   rule tag_rule if (inited && (head_ptr+1 != tail_ptr));
      //tags.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head_ptr, datain:True});
      //tags.upd(head_ptr, True);
      tags[head_ptr] <= True;
      head_ptr <= head_ptr+1;
      tagFifo.enq(head_ptr);
   endrule

   method ActionValue#(Bit#(tsz)) getTag();
      let tag <- toGet(tagFifo).get();
      return tag;
   endmethod

   method Action returnTag(Bit#(tsz) tag) if (inited);
      retFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(tsz)) complete;
      comp_fifo.deq;
      return comp_fifo.first;
   endmethod

endmodule