ethPhy fifo should be depth 1

ethPhy fifo should be depth 1

// 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 EthPhy;

import Clocks                        ::*;
import Vector                        ::*;
import Connectable                   ::*;
import Pipe                          ::*;
import FIFO                          ::*;
import BRAMFIFO                      ::*;
import FIFOF                         ::*;
import SpecialFIFOs                  ::*;
import GetPut                        ::*;
import Ethernet                      ::*;
import EthSonicPma                   ::*;
import EthPcsTx                      ::*;
import EthPcsRx                      ::*;
import DtpTx                         ::*;
import DtpRx                         ::*;
import DtpSwitch                     ::*;
import ALTERA_SI570_WRAPPER          ::*;
import ALTERA_EDGE_DETECTOR_WRAPPER  ::*;
import AlteraExtra                   ::*;

`ifdef NUMBER_OF_10G_PORTS
typedef `NUMBER_OF_10G_PORTS NumPorts;
`else
typedef 4 NumPorts;
`endif

interface EthPhyIfc#(numeric type numPorts);
   interface Vector#(numPorts, PipeIn#(Bit#(72)))  tx;
   interface Vector#(numPorts, PipeOut#(Bit#(72))) rx;
   (* always_ready, always_enabled *)
   interface Vector#(numPorts, SerialIfc) serial;
   interface Vector#(numPorts, Clock) tx_clkout;
   interface Vector#(numPorts, Clock) rx_clkout;
   (* always_ready, always_enabled *)
   interface LoopbackIfc loopback;

   interface Vector#(numPorts, Bool) led_rx_ready;
   interface Vector#(numPorts, DtpToPhyIfc) api;
   interface PipeIn#(Bit#(1)) switchMode;
   interface PipeOut#(Bit#(53)) globalOut;
endinterface

function Bit#(n) reverseBits(Bit#(n) x);
   Vector#(n, Bit#(1)) vx = unpack(x);
   Vector#(n, Bit#(1)) rvx = Vector::reverse(vx);
   Bit#(n) prvx = pack(rvx);
   return(prvx);
endfunction

(* synthesize *)
module mkEthPhy#(Clock mgmt_clk, Clock clk_156_25, Clock clk_644, Reset rst_n)(EthPhyIfc#(NumPorts));

   Reg#(Bit#(32)) cycle <- mkReg(0);
   Reset rst_50_n <- mkAsyncReset(2, rst_n, mgmt_clk);
   Reset rst_156_25_n <- mkAsyncReset(2, rst_n, clk_156_25);

   Reg#(Bool) loopback_en <- mkReg(False);
   Reg#(Bool) switch_en <- mkReg(False);

   Vector#(NumPorts, EthPcsRx) pcs_rx = newVector;
   Vector#(NumPorts, EthPcsTx) pcs_tx = newVector;
   Vector#(NumPorts, DtpRx)    dtp_rx = newVector;
   Vector#(NumPorts, DtpTx)    dtp_tx = newVector;

   EthSonicPma#(NumPorts)      pma4 <- mkEthSonicPma(mgmt_clk, clk_644, clk_156_25, rst_50_n, clocked_by mgmt_clk, reset_by rst_50_n);

   Vector#(NumPorts, ReadOnly#(Bool)) rx_ready_tx;
   Vector#(NumPorts, ReadOnly#(Bool)) tx_ready_tx;
   Vector#(NumPorts, ReadOnly#(Bool)) rx_ready_rx;
   Vector#(NumPorts, ReadOnly#(Bool)) tx_ready_rx;
   Vector#(NumPorts, CrossingReg#(Bool)) lock_tx;
   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rx_ready_tx[i] <- mkNullCrossingWire(clk_156_25, pma4.rx_ready[i]);
      tx_ready_tx[i] <- mkNullCrossingWire(clk_156_25, pma4.tx_ready[i]);
      rx_ready_rx[i] <- mkNullCrossingWire(pma4.rx_clkout[i], pma4.rx_ready[i]);
      tx_ready_rx[i] <- mkNullCrossingWire(pma4.rx_clkout[i], pma4.tx_ready[i]);
      lock_tx[i] <- mkNullCrossingReg(clk_156_25, False, clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
   end

   Vector#(NumPorts, FIFOF#(Bit#(72)))   txFifo     = newVector;
   Vector#(NumPorts, FIFOF#(Bit#(72)))   rxFifo     = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(72)))  vRxPipeIn  = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(72))) vRxPipeOut = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(72)))  vTxPipeIn  = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(72))) vTxPipeOut = newVector;

   // Loopback FIFO
   Vector#(NumPorts, SyncFIFOIfc#(Bit#(66))) lpbkSyncFifo = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(66))) lpbkSyncPipeOut = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(66))) lpbkSyncPipeIn = newVector;

   // DtpRx to DtpTx Fifo
   Vector#(NumPorts, SyncFIFOIfc#(DtpEvent)) dtpEventFifo = newVector;
   Vector#(NumPorts, PipeOut#(DtpEvent)) dtpEventOut = newVector;
   Vector#(NumPorts, PipeIn#(DtpEvent)) dtpEventIn = newVector;
   Vector#(NumPorts, SyncFIFOIfc#(Bit#(32))) dtpErrCntFifo = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(32))) dtpErrCntOut = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(32))) dtpErrCntIn = newVector;

   // 156.25MHz to pma4.tx
   Vector#(NumPorts, SyncFIFOIfc#(Bit#(66))) txSyncFifo = newVector;

   FIFOF#(Bit#(1)) switchModeFifo <- mkFIFOF();

   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rxFifo[i] <- mkFIFOF(clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
      txFifo[i] <- mkFIFOF(clocked_by clk_156_25, reset_by rst_156_25_n);
      vRxPipeIn[i] = toPipeIn(rxFifo[i]);
      vRxPipeOut[i] = toPipeOut(rxFifo[i]);
      vTxPipeIn[i] = toPipeIn(txFifo[i]);
      vTxPipeOut[i] = toPipeOut(txFifo[i]);

      // Gearbox Level Loopback FIFO
      lpbkSyncFifo[i] <- mkSyncFIFO(10, clk_156_25, rst_156_25_n, pma4.rx_clkout[i]);//, pma4.rx_reset[i]);
      lpbkSyncPipeOut[i] = toPipeOut(lpbkSyncFifo[i]);
      lpbkSyncPipeIn[i] = toPipeIn(lpbkSyncFifo[i]);

      pcs_rx[i]    <- mkEthPcsRxTop(clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
      pcs_tx[i]    <- mkEthPcsTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);
      dtp_rx[i]    <- mkDtpRxTop(clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
      dtp_tx[i]    <- mkDtpTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);

      dtpEventFifo[i] <- mkSyncFIFO(10, pma4.rx_clkout[i], pma4.rx_reset[i], clk_156_25);//, rst_156_25_n);
      dtpEventOut[i] = toPipeOut(dtpEventFifo[i]);
      dtpEventIn[i]  = toPipeIn(dtpEventFifo[i]);

      dtpErrCntFifo[i] <- mkSyncFIFO(10, pma4.rx_clkout[i], pma4.rx_reset[i], clk_156_25);//, rst_156_25_n);
      dtpErrCntOut[i] = toPipeOut(dtpErrCntFifo[i]);
      dtpErrCntIn[i]  = toPipeIn(dtpErrCntFifo[i]);

      // Rx Path: PcsRx -> DtpRx
      mkConnection(pcs_rx[i].dtpRxIn, dtp_rx[i].dtpRxIn);
      // Rx Path: DtpRx -> PcsRx
      mkConnection(dtp_rx[i].dtpRxOut, pcs_rx[i].dtpRxOut);
      // Rx Path: DtpRx -> SyncFIFO
      mkConnection(dtp_rx[i].dtpEventOut, dtpEventIn[i]);
      // Rx Path DtpRx -> SyncFifo
      mkConnection(dtp_rx[i].dtpErrCnt, dtpErrCntIn[i]);

      // Tx Path SyncFIfo -> DtpTx
      mkConnection(dtpErrCntOut[i], dtp_tx[i].dtpErrCnt);
      // Tx Path; SyncFifo -> DtpTx
      mkConnection(dtpEventOut[i], dtp_tx[i].dtpEventIn);
      // Tx Path: Mac -> Encoder
      mkConnection(vTxPipeOut[i], pcs_tx[i].encoderIn);
      // Tx Path: PcsTx -> DtpTx
      mkConnection(pcs_tx[i].dtpTxIn, dtp_tx[i].dtpTxIn);
      // Tx Path: DtpTx -> PcsTx
      mkConnection(dtp_tx[i].dtpTxOut, pcs_tx[i].dtpTxOut);

      // Loopback Enable Signal
      ReadOnly#(Bool) rx_lpbk_en <- mkNullCrossingWire(pma4.rx_clkout[i], loopback_en);
      ReadOnly#(Bool) tx_lpbk_en <- mkNullCrossingWire(clk_156_25, loopback_en);

      rule cross_lock_tx;
         lock_tx[i] <= pcs_rx[i].lock;
      endrule

      // Normal Operation: XCVR -> Pcs
      rule rx_no_loopback(!rx_lpbk_en);
         let v <- toGet(pma4.rx[i]).get;
         let reversed_v = reverseBits(v);
         pcs_rx[i].bsyncIn.enq(reversed_v);
      endrule
      rule tx_no_loopback(!tx_lpbk_en);
         let v <- toGet(pcs_tx[i].scramblerOut).get;
         let reversed_v = reverseBits(v);
         pma4.tx[i].enq(reversed_v);
      endrule
      // END Normal Operation

      // Loopback Operation: Pcs -> lpbk Fifo -> Pcs
      ReadOnly#(Bit#(32)) cycle_cross <- mkNullCrossingWire(clk_156_25, cycle);
      rule tx_loopback(tx_lpbk_en);
         let v <- toGet(pcs_tx[i].scramblerOut).get;
         lpbkSyncPipeIn[i].enq(v);
      endrule
      rule tx_pma_loopback(tx_lpbk_en);
         // Make sure PMA is up by sending fake data.
         Bit#(66) count = 66'hAAAAA55555AAAAAA;
         pma4.tx[i].enq(count);
      endrule
      rule rx_loopback(rx_lpbk_en);
         let v <- toGet(lpbkSyncPipeOut[i]).get;
         pcs_rx[i].bsyncIn.enq(v);
      endrule
      rule rx_pma_loopback(rx_lpbk_en);
         let v <- toGet(pma4.rx[i]).get;
      endrule
      // END Loopback Operation
   end

   rule cyc;
      cycle <= cycle + 1;
   endrule

   ReadOnly#(Bool) switch_en_tx;
   switch_en_tx <- mkNullCrossingWire(clk_156_25, switch_en);

   DtpSwitch#(4) dtpswitch <- mkDtpSwitch(clocked_by clk_156_25, reset_by rst_156_25_n);
   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      mkConnection(dtp_tx[i].dtpLocalOut, dtpswitch.dtpLocalIn[i]);
      mkConnection(dtpswitch.dtpGlobalOut[i], dtp_tx[i].dtpGlobalIn);
   end

   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rule pcs_tx_every1;
         pcs_tx[i].tx_ready(tx_ready_tx[i]);
      endrule
      rule pcs_rx_every1;
         pcs_rx[i].rx_ready(rx_ready_rx[i]);
      endrule
      rule dtp_tx_every1;
         dtp_tx[i].tx_ready(tx_ready_tx[i]);
         dtp_tx[i].rx_ready(rx_ready_tx[i]);
         dtp_tx[i].switch_mode(switch_en_tx);
         dtp_tx[i].bsync_lock(lock_tx[i].crossed);
      endrule
      rule dtp_rx_every1;
         dtp_rx[i].rx_ready(rx_ready_rx[i]);
         dtp_rx[i].bsync_lock(pcs_rx[i].lock);
      endrule
   end

   rule switch_mode;
      let v <- toGet(switchModeFifo).get;
      switch_en <= unpack(v);
   endrule

   rule dtpswitch_mode;
      dtpswitch.switch_mode(switch_en_tx);
   endrule

   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rule receive;
         let v <- toGet(pcs_rx[i].decoderOut).get;
         vRxPipeIn[i].enq(v);
      endrule
   end

   Vector#(NumPorts, DtpToPhyIfc) vapi;
   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      vapi[i] = dtp_tx[i].api;
   end

   interface loopback = (interface LoopbackIfc;
      method Action lpbk_en (Bool en);
         loopback_en <= en;
      endmethod
   endinterface);

   interface rx_clkout = pma4.rx_clkout;
   interface tx_clkout = pma4.tx_clkout;
   interface serial = pma4.pmd;
   interface rx = vRxPipeOut;
   interface tx = vTxPipeIn;
   interface led_rx_ready = pma4.rx_ready;

   interface api = vapi;
   interface switchMode = toPipeIn(switchModeFifo);
   interface globalOut = dtpswitch.globalOut;

endmodule: mkEthPhy
endpackage: EthPhy

// 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 EthPhy;

import Clocks                        ::*;
import Vector                        ::*;
import Connectable                   ::*;
import Pipe                          ::*;
import FIFO                          ::*;
import BRAMFIFO                      ::*;
import FIFOF                         ::*;
import SpecialFIFOs                  ::*;
import GetPut                        ::*;
import Ethernet                      ::*;
import EthSonicPma                   ::*;
import EthPcsTx                      ::*;
import EthPcsRx                      ::*;
import DtpTx                         ::*;
import DtpRx                         ::*;
import DtpSwitch                     ::*;
import ALTERA_SI570_WRAPPER          ::*;
import ALTERA_EDGE_DETECTOR_WRAPPER  ::*;
import AlteraExtra                   ::*;

`ifdef NUMBER_OF_10G_PORTS
typedef `NUMBER_OF_10G_PORTS NumPorts;
`else
typedef 4 NumPorts;
`endif

interface EthPhyIfc#(numeric type numPorts);
   interface Vector#(numPorts, PipeIn#(Bit#(72)))  tx;
   interface Vector#(numPorts, PipeOut#(Bit#(72))) rx;
   (* always_ready, always_enabled *)
   interface Vector#(numPorts, SerialIfc) serial;
   interface Vector#(numPorts, Clock) tx_clkout;
   interface Vector#(numPorts, Clock) rx_clkout;
   (* always_ready, always_enabled *)
   interface LoopbackIfc loopback;

   interface Vector#(numPorts, Bool) led_rx_ready;
   interface Vector#(numPorts, DtpToPhyIfc) api;
   interface PipeIn#(Bit#(1)) switchMode;
   interface PipeOut#(Bit#(53)) globalOut;
endinterface

function Bit#(n) reverseBits(Bit#(n) x);
   Vector#(n, Bit#(1)) vx = unpack(x);
   Vector#(n, Bit#(1)) rvx = Vector::reverse(vx);
   Bit#(n) prvx = pack(rvx);
   return(prvx);
endfunction

(* synthesize *)
module mkEthPhy#(Clock mgmt_clk, Clock clk_156_25, Clock clk_644, Reset rst_n)(EthPhyIfc#(NumPorts));

   Reg#(Bit#(32)) cycle <- mkReg(0);
   Reset rst_50_n <- mkAsyncReset(2, rst_n, mgmt_clk);
   Reset rst_156_25_n <- mkAsyncReset(2, rst_n, clk_156_25);

   Reg#(Bool) loopback_en <- mkReg(False);
   Reg#(Bool) switch_en <- mkReg(False);

   Vector#(NumPorts, EthPcsRx) pcs_rx = newVector;
   Vector#(NumPorts, EthPcsTx) pcs_tx = newVector;
   Vector#(NumPorts, DtpRx)    dtp_rx = newVector;
   Vector#(NumPorts, DtpTx)    dtp_tx = newVector;

   EthSonicPma#(NumPorts)      pma4 <- mkEthSonicPma(mgmt_clk, clk_644, clk_156_25, rst_50_n, clocked_by mgmt_clk, reset_by rst_50_n);

   Vector#(NumPorts, ReadOnly#(Bool)) rx_ready_tx;
   Vector#(NumPorts, ReadOnly#(Bool)) tx_ready_tx;
   Vector#(NumPorts, ReadOnly#(Bool)) rx_ready_rx;
   Vector#(NumPorts, ReadOnly#(Bool)) tx_ready_rx;
   Vector#(NumPorts, CrossingReg#(Bool)) lock_tx;
   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rx_ready_tx[i] <- mkNullCrossingWire(clk_156_25, pma4.rx_ready[i]);
      tx_ready_tx[i] <- mkNullCrossingWire(clk_156_25, pma4.tx_ready[i]);
      rx_ready_rx[i] <- mkNullCrossingWire(pma4.rx_clkout[i], pma4.rx_ready[i]);
      tx_ready_rx[i] <- mkNullCrossingWire(pma4.rx_clkout[i], pma4.tx_ready[i]);
      lock_tx[i] <- mkNullCrossingReg(clk_156_25, False, clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
   end

   Vector#(NumPorts, FIFOF#(Bit#(72)))   txFifo     = newVector;
   Vector#(NumPorts, FIFOF#(Bit#(72)))   rxFifo     = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(72)))  vRxPipeIn  = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(72))) vRxPipeOut = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(72)))  vTxPipeIn  = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(72))) vTxPipeOut = newVector;

   // Loopback FIFO
   Vector#(NumPorts, SyncFIFOIfc#(Bit#(66))) lpbkSyncFifo = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(66))) lpbkSyncPipeOut = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(66))) lpbkSyncPipeIn = newVector;

   // DtpRx to DtpTx Fifo
   Vector#(NumPorts, SyncFIFOIfc#(DtpEvent)) dtpEventFifo = newVector;
   Vector#(NumPorts, PipeOut#(DtpEvent)) dtpEventOut = newVector;
   Vector#(NumPorts, PipeIn#(DtpEvent)) dtpEventIn = newVector;
   Vector#(NumPorts, SyncFIFOIfc#(Bit#(32))) dtpErrCntFifo = newVector;
   Vector#(NumPorts, PipeOut#(Bit#(32))) dtpErrCntOut = newVector;
   Vector#(NumPorts, PipeIn#(Bit#(32))) dtpErrCntIn = newVector;

   // 156.25MHz to pma4.tx
   Vector#(NumPorts, SyncFIFOIfc#(Bit#(66))) txSyncFifo = newVector;

   FIFOF#(Bit#(1)) switchModeFifo <- mkSizedFIFOF(4);

   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rxFifo[i] <- mkFIFOF(clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
      txFifo[i] <- mkFIFOF(clocked_by clk_156_25, reset_by rst_156_25_n);
      vRxPipeIn[i] = toPipeIn(rxFifo[i]);
      vRxPipeOut[i] = toPipeOut(rxFifo[i]);
      vTxPipeIn[i] = toPipeIn(txFifo[i]);
      vTxPipeOut[i] = toPipeOut(txFifo[i]);

      // Gearbox Level Loopback FIFO
      lpbkSyncFifo[i] <- mkSyncFIFO(10, clk_156_25, rst_156_25_n, pma4.rx_clkout[i]);//, pma4.rx_reset[i]);
      lpbkSyncPipeOut[i] = toPipeOut(lpbkSyncFifo[i]);
      lpbkSyncPipeIn[i] = toPipeIn(lpbkSyncFifo[i]);

      pcs_rx[i]    <- mkEthPcsRxTop(clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
      pcs_tx[i]    <- mkEthPcsTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);
      dtp_rx[i]    <- mkDtpRxTop(clocked_by pma4.rx_clkout[i], reset_by pma4.rx_reset[i]);
      dtp_tx[i]    <- mkDtpTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);

      dtpEventFifo[i] <- mkSyncFIFO(10, pma4.rx_clkout[i], pma4.rx_reset[i], clk_156_25);//, rst_156_25_n);
      dtpEventOut[i] = toPipeOut(dtpEventFifo[i]);
      dtpEventIn[i]  = toPipeIn(dtpEventFifo[i]);

      dtpErrCntFifo[i] <- mkSyncFIFO(10, pma4.rx_clkout[i], pma4.rx_reset[i], clk_156_25);//, rst_156_25_n);
      dtpErrCntOut[i] = toPipeOut(dtpErrCntFifo[i]);
      dtpErrCntIn[i]  = toPipeIn(dtpErrCntFifo[i]);

      // Rx Path: PcsRx -> DtpRx
      mkConnection(pcs_rx[i].dtpRxIn, dtp_rx[i].dtpRxIn);
      // Rx Path: DtpRx -> PcsRx
      mkConnection(dtp_rx[i].dtpRxOut, pcs_rx[i].dtpRxOut);
      // Rx Path: DtpRx -> SyncFIFO
      mkConnection(dtp_rx[i].dtpEventOut, dtpEventIn[i]);
      // Rx Path DtpRx -> SyncFifo
      mkConnection(dtp_rx[i].dtpErrCnt, dtpErrCntIn[i]);

      // Tx Path SyncFIfo -> DtpTx
      mkConnection(dtpErrCntOut[i], dtp_tx[i].dtpErrCnt);
      // Tx Path; SyncFifo -> DtpTx
      mkConnection(dtpEventOut[i], dtp_tx[i].dtpEventIn);
      // Tx Path: Mac -> Encoder
      mkConnection(vTxPipeOut[i], pcs_tx[i].encoderIn);
      // Tx Path: PcsTx -> DtpTx
      mkConnection(pcs_tx[i].dtpTxIn, dtp_tx[i].dtpTxIn);
      // Tx Path: DtpTx -> PcsTx
      mkConnection(dtp_tx[i].dtpTxOut, pcs_tx[i].dtpTxOut);

      // Loopback Enable Signal
      ReadOnly#(Bool) rx_lpbk_en <- mkNullCrossingWire(pma4.rx_clkout[i], loopback_en);
      ReadOnly#(Bool) tx_lpbk_en <- mkNullCrossingWire(clk_156_25, loopback_en);

      rule cross_lock_tx;
         lock_tx[i] <= pcs_rx[i].lock;
      endrule

      // Normal Operation: XCVR -> Pcs
      rule rx_no_loopback(!rx_lpbk_en);
         let v <- toGet(pma4.rx[i]).get;
         let reversed_v = reverseBits(v);
         pcs_rx[i].bsyncIn.enq(reversed_v);
      endrule
      rule tx_no_loopback(!tx_lpbk_en);
         let v <- toGet(pcs_tx[i].scramblerOut).get;
         let reversed_v = reverseBits(v);
         pma4.tx[i].enq(reversed_v);
      endrule
      // END Normal Operation

      // Loopback Operation: Pcs -> lpbk Fifo -> Pcs
      ReadOnly#(Bit#(32)) cycle_cross <- mkNullCrossingWire(clk_156_25, cycle);
      rule tx_loopback(tx_lpbk_en);
         let v <- toGet(pcs_tx[i].scramblerOut).get;
         lpbkSyncPipeIn[i].enq(v);
      endrule
      rule tx_pma_loopback(tx_lpbk_en);
         // Make sure PMA is up by sending fake data.
         Bit#(66) count = 66'hAAAAA55555AAAAAA;
         pma4.tx[i].enq(count);
      endrule
      rule rx_loopback(rx_lpbk_en);
         let v <- toGet(lpbkSyncPipeOut[i]).get;
         pcs_rx[i].bsyncIn.enq(v);
      endrule
      rule rx_pma_loopback(rx_lpbk_en);
         let v <- toGet(pma4.rx[i]).get;
      endrule
      // END Loopback Operation
   end

   rule cyc;
      cycle <= cycle + 1;
   endrule

   ReadOnly#(Bool) switch_en_tx;
   switch_en_tx <- mkNullCrossingWire(clk_156_25, switch_en);

   DtpSwitch#(4) dtpswitch <- mkDtpSwitch(clocked_by clk_156_25, reset_by rst_156_25_n);
   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      mkConnection(dtp_tx[i].dtpLocalOut, dtpswitch.dtpLocalIn[i]);
      mkConnection(dtpswitch.dtpGlobalOut[i], dtp_tx[i].dtpGlobalIn);
   end

   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rule pcs_tx_every1;
         pcs_tx[i].tx_ready(tx_ready_tx[i]);
      endrule
      rule pcs_rx_every1;
         pcs_rx[i].rx_ready(rx_ready_rx[i]);
      endrule
      rule dtp_tx_every1;
         dtp_tx[i].tx_ready(tx_ready_tx[i]);
         dtp_tx[i].rx_ready(rx_ready_tx[i]);
         dtp_tx[i].switch_mode(switch_en_tx);
         dtp_tx[i].bsync_lock(lock_tx[i].crossed);
      endrule
      rule dtp_rx_every1;
         dtp_rx[i].rx_ready(rx_ready_rx[i]);
         dtp_rx[i].bsync_lock(pcs_rx[i].lock);
      endrule
   end

   rule switch_mode;
      let v <- toGet(switchModeFifo).get;
      switch_en <= unpack(v);
   endrule

   rule dtpswitch_mode;
      dtpswitch.switch_mode(switch_en_tx);
   endrule

   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      rule receive;
         let v <- toGet(pcs_rx[i].decoderOut).get;
         vRxPipeIn[i].enq(v);
      endrule
   end

   Vector#(NumPorts, DtpToPhyIfc) vapi;
   for (Integer i=0; i<valueOf(NumPorts); i=i+1) begin
      vapi[i] = dtp_tx[i].api;
   end

   interface loopback = (interface LoopbackIfc;
      method Action lpbk_en (Bool en);
         loopback_en <= en;
      endmethod
   endinterface);

   interface rx_clkout = pma4.rx_clkout;
   interface tx_clkout = pma4.tx_clkout;
   interface serial = pma4.pmd;
   interface rx = vRxPipeOut;
   interface tx = vTxPipeIn;
   interface led_rx_ready = pma4.rx_ready;

   interface api = vapi;
   interface switchMode = toPipeIn(switchModeFifo);
   interface globalOut = dtpswitch.globalOut;

endmodule: mkEthPhy
endpackage: EthPhy


added 'OR' module for Bscan

added 'OR' module for Bscan

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

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

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

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

import FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

interface BscanTop;
   interface Reset    rst;
   interface Clock    tck;
   method Bit#(1)     reset();
   method Bit#(1)     capture();
   method Bit#(1)     shift();
   method Bit#(1)     tdi();
   method Action      tdo(Bit#(1) v);
   method Bit#(1)     update();
   method Bool        first();
endinterface
module mkBscanTop#(Integer bus)(BscanTop);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   BscanE2 bscan <- mkBscanE2(bus);
   Clock mytck <- mkClockBUFG(clocked_by bscan.tck);
   Reset myrst <- mkAsyncReset(2, defaultReset, mytck);
   SyncBitIfc#(Bool) selected <- mkSyncBits(False, mytck, myrst, defaultClock, defaultReset);
   Reg#(Bool) selectdelay <- mkReg(False);

   rule updater;
       selected.send(bscan.sel() == 1);
   endrule
   rule writed;
       selectdelay <= selected.read();
   endrule

   interface tck = mytck;
   interface rst = myrst;
   method tdi = bscan.tdi;
   method tdo = bscan.tdo;
   method capture;
       return bscan.sel & bscan.capture;
   endmethod
   method shift;
       return bscan.sel & bscan.shift;
   endmethod
   method update;
       return bscan.sel & bscan.update;
   endmethod
   method first();
      return selected.read() && !selectdelay;
   endmethod
endmodule

interface BscanLocal;
   method Action tdo1(Bit#(1) v);
   method Action tdo2(Bit#(1) v);
endinterface

module mkBscanLocal#(BscanTop bscan)(BscanLocal);
   Wire#(Bit#(1)) tdo_wire1 <- mkDWire(0);
   Wire#(Bit#(1)) tdo_wire2 <- mkDWire(0);

   rule tdo_rule;
       bscan.tdo(tdo_wire1 | tdo_wire2);
   endrule

   method Action tdo1(Bit#(1) v);
       tdo_wire1 <= v;
   endmethod
   method Action tdo2(Bit#(1) v);
       tdo_wire2 <= v;
   endmethod
endmodule

interface BscanBram#(type atype, type dtype);
   interface BRAMClient#(atype, dtype) bramClient;
   method Bit#(1) data_out();
endinterface

module mkBscanBram#(Integer id, atype addr, BscanTop bscan)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz), Add#(1, a__, dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   Reg#(Bit#(asz)) addrReg <- mkReg(0);
   Reg#(Bool) readData <- mkReg(False);
   Reg#(Bool) firstItem <- mkReg(False);
   Reg#(Bool) selected <- mkReg(False);
   SyncBitIfc#(Bool) selectedj <- mkSyncBits(False, defaultClock, defaultReset, bscan.tck, bscan.rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by bscan.tck, reset_by bscan.rst);
   SyncBitIfc#(Bit#(dsz)) tojtag <- mkSyncBits(0, defaultClock, defaultReset, bscan.tck, bscan.rst);
   SyncBitIfc#(Bit#(dsz)) fromjtag <- mkSyncBits(0, bscan.tck, bscan.rst, defaultClock, defaultReset);
   SyncPulseIfc startWrite <- mkSyncHandshake(bscan.tck, bscan.rst, defaultClock);

   rule captureRule if(bscan.capture() == 1);
       shiftReg <= tojtag.read();
   endrule
   rule shiftRule if (bscan.shift() == 1);
       shiftReg <= { bscan.tdi(), shiftReg[dsz-1:1] };
   endrule
   rule updateRule if(bscan.update() == 1);
       startWrite.send();
       fromjtag.send(shiftReg);
   endrule

   rule firstRule if (bscan.first());
       firstItem <= True;
       selected <= False;
       selectedj.send(False);
       tojtag.send(0);
   endrule
   rule addrRule if (startWrite.pulse());
       let v = fromInteger(0);  // first time USER1, reset address
       if (firstItem) begin
           selected <= fromjtag.read() == fromInteger(id);
           selectedj.send(fromjtag.read() == fromInteger(id));
       end
       else
           v = addrReg + 1;
       addrReg <= v;
       firstItem <= False;
   endrule
   rule readdataRule;
       readData <= startWrite.pulse();
   endrule

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if ((selected && startWrite.pulse()) || readData);
            return BRAMRequest {write:!readData, responseOnWrite:False, address:unpack(addrReg), datain:unpack(fromjtag.read())};
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
            tojtag.send(pack(d));
	 endmethod
      endinterface
   endinterface
   method Bit#(1) data_out();
      // the output lines are all OR'ed together when going back to the BSCAN core
      if (selectedj.read())
          return shiftReg[0];
      else
          return 0;
   endmethod
endmodule

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

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

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

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

import FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

interface BscanTop;
   interface Reset    rst;
   interface Clock    tck;
   method Bit#(1)     reset();
   method Bit#(1)     capture();
   method Bit#(1)     shift();
   method Bit#(1)     tdi();
   method Action      tdo(Bit#(1) v);
   method Bit#(1)     update();
   method Bool        first();
endinterface
module mkBscanTop#(Integer bus)(BscanTop);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   BscanE2 bscan <- mkBscanE2(bus);
   Clock mytck <- mkClockBUFG(clocked_by bscan.tck);
   Reset myrst <- mkAsyncReset(2, defaultReset, mytck);
   SyncBitIfc#(Bool) selected <- mkSyncBits(False, mytck, myrst, defaultClock, defaultReset);
   Reg#(Bool) selectdelay <- mkReg(False);

   rule updater;
       selected.send(bscan.sel() == 1);
   endrule
   rule writed;
       selectdelay <= selected.read();
   endrule

   interface tck = mytck;
   interface rst = myrst;
   method tdi = bscan.tdi;
   method tdo = bscan.tdo;
   method capture;
       return bscan.sel & bscan.capture;
   endmethod
   method shift;
       return bscan.sel & bscan.shift;
   endmethod
   method update;
       return bscan.sel & bscan.update;
   endmethod
   method first();
      return selected.read() && !selectdelay;
   endmethod
endmodule

interface BscanBram#(type atype, type dtype);
   interface BRAMClient#(atype, dtype) bramClient;
   method Bit#(1) data_out();
endinterface

module mkBscanBram#(Integer id, atype addr, BscanTop bscan)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz), Add#(1, a__, dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   Reg#(Bit#(asz)) addrReg <- mkReg(0);
   Reg#(Bool) readData <- mkReg(False);
   Reg#(Bool) firstItem <- mkReg(False);
   Reg#(Bool) selected <- mkReg(False);
   SyncBitIfc#(Bool) selectedj <- mkSyncBits(False, defaultClock, defaultReset, bscan.tck, bscan.rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by bscan.tck, reset_by bscan.rst);
   SyncBitIfc#(Bit#(dsz)) tojtag <- mkSyncBits(0, defaultClock, defaultReset, bscan.tck, bscan.rst);
   SyncBitIfc#(Bit#(dsz)) fromjtag <- mkSyncBits(0, bscan.tck, bscan.rst, defaultClock, defaultReset);
   SyncPulseIfc startWrite <- mkSyncHandshake(bscan.tck, bscan.rst, defaultClock);

   rule captureRule if(bscan.capture() == 1);
       shiftReg <= tojtag.read();
   endrule
   rule shiftRule if (bscan.shift() == 1);
       shiftReg <= { bscan.tdi(), shiftReg[dsz-1:1] };
   endrule
   rule updateRule if(bscan.update() == 1);
       startWrite.send();
       fromjtag.send(shiftReg);
   endrule

   rule firstRule if (bscan.first());
       firstItem <= True;
       selected <= False;
       selectedj.send(False);
       tojtag.send(0);
   endrule
   rule addrRule if (startWrite.pulse());
       let v = fromInteger(0);  // first time USER1, reset address
       if (firstItem) begin
           selected <= fromjtag.read() == fromInteger(id);
           selectedj.send(fromjtag.read() == fromInteger(id));
       end
       else
           v = addrReg + 1;
       addrReg <= v;
       firstItem <= False;
   endrule
   rule readdataRule;
       readData <= startWrite.pulse();
   endrule

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if ((selected && startWrite.pulse()) || readData);
            return BRAMRequest {write:!readData, responseOnWrite:False, address:unpack(addrReg), datain:unpack(fromjtag.read())};
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
            tojtag.send(pack(d));
	 endmethod
      endinterface
   endinterface
   method Bit#(1) data_out();
      // the output lines are all OR'ed together when going back to the BSCAN core
      if (selectedj.read())
          return shiftReg[0];
      else
          return 0;
   endmethod
endmodule


break up par;endpar FSM to multiple seq;endseq FSM

// Copyright (c) 2015 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.

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

import BuildVector::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import Pipe::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;

import Ethernet::*;
import P4Types::*;

interface Parser;
   // derive parseReset from start of packet
   method Action parserReset();
   interface PipeIn#(EtherData) frameIn;
   interface PipeOut#(void) parseDone;
   interface PipeOut#(MatchKey_port_mapping) match_key_port_mapping;
   interface PipeOut#(MatchKey_bd) match_key_bd;
   interface PipeOut#(MatchKey_ipv4_fib) match_key_ipv4_fib;
   interface PipeOut#(MatchKey_ipv4_fib_lpm) match_key_ipv4_fib_lpm;
   interface PipeOut#(MatchKey_nexthop) match_key_nexthop;
   interface PipeOut#(MatchKey_rewrite_mac) match_rewrite_mac;
   interface PipeOut#(Bit#(128)) payloadOut;
endinterface

interface ParseEthernet;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeOut#(Ethernet_t) parsedOut;
   interface PipeOut#(Bit#(16)) unparsedOutIpv4; // number is parse state id
   interface PipeOut#(Bit#(16)) unparsedOutVlan; // number is parse state id
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseVlan;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Vlan_tag_t) parsedOut;
   interface PipeOut#(Bit#(112)) unparsedOutVlan0;
   interface PipeOut#(Bit#(80)) unparsedOutVlan1;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseIpv4;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Ipv4_t) parsedOut;
   interface PipeIn#(Bit#(112)) unparsedInVlan0;
   interface PipeIn#(Bit#(80)) unparsedInVlan1;
   interface PipeOut#(Bit#(112)) unparsedOut;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

typedef enum {S0, S1, S2, S3, S4} ParserState deriving (Bits, Eq);
instance FShow#(ParserState);
   function Fmt fshow (ParserState state);
      return $format(" State %x", state);
   endfunction
endinstance

module mkParseEthernet(ParseEthernet);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Ethernet_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_ipv4_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_vlan_fifo <- mkSizedFIFOF(1);
   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule cycleRule if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
   endrule

   Stmt parse_ethernet =
   seq
   action // parse_ethernet
      //let data <- toGet(packet_in_fifo).get;
      let data = packet_in_wire;
      Vector#(128, Bit#(1)) dataVec = unpack(data);
      let ethernet = extrace_ethernet(pack(takeAt(0, dataVec)));
      Vector#(16, Bit#(1)) unparsed = takeAt(112, dataVec);
      if (verbose) $display(fshow(cycle)
                            +fshow(" ether.dstAddr=")+fshow(ethernet.dstAddr)
                            +fshow(" ether.srcAddr=")+fshow(ethernet.srcAddr)
                            +fshow(" ether.etherType=")+fshow(ethernet.etherType));

      ParserState nextState = S0;
      case (byteSwap2B(ethernet.etherType)) matches
         'h_8100: begin
            unparsed_out_parse_vlan_fifo.enq(pack(unparsed));
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            unparsed_out_parse_ipv4_fifo.enq(pack(unparsed));
            nextState = S3;
         end
         default: begin
            $display("null");
         end
      endcase
      next_state_fifo.enq(nextState);
   endaction
   endseq;

   FSM fsm_parse_ethernet <- mkFSMWithPred(parse_ethernet, True);
   //Once once_parse_ethernet <- mkOnce(fsm_parse_ethernet.start);

   //method Action start = once_parse_ethernet.start;
   method Action start = fsm_parse_ethernet.start;
   method Action clear();
      //once_parse_ethernet.clear;
      fsm_parse_ethernet.abort;
      //packet_in_fifo.clear;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedOutIpv4 = toPipeOut(unparsed_out_parse_ipv4_fifo);
   interface unparsedOutVlan = toPipeOut(unparsed_out_parse_vlan_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseVlanArbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(2, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseVlanArbiter(ParseVlanArbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(2, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<2; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

// Parse second VLAN
module mkParseVlan(ParseVlan);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan0 <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan1 <- mkBypassFIFOF;
   FIFOF#(Vlan_tag_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(112)) unparsed_out_parse_vlan0_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(80)) unparsed_out_parse_vlan1_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseVlanArbiter nextStateArbiter <- mkParseVlanArbiter();

   function ParserState compute_next_state(Bit#(16) etherType);
      ParserState nextState = S0;
      case (byteSwap2B(etherType)) matches
         'h_8100: begin
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            nextState = S3;
         end
      endcase
      return nextState;
   endfunction

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      if (verbose) $display(fshow(cycle) + fshow("load packet in"));
   endrule

   rule load_unparsed_in;
      let data_delayed <- toGet(unparsed_in_fifo).get;
      unparsed_in_fifo_vlan0.enq(data_delayed);
      unparsed_in_fifo_vlan1.enq(data_delayed);
      if (verbose) $display(fshow(cycle) + fshow("load unparsed in"));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_vlan =
   par
      // VLAN
      seq
      action
         let data_delayed <- toGet(unparsed_in_fifo_vlan0).get;
         let data_current = packet_in_wire;
         $display("VLAN %x", data_current);
         Bit#(144) data = {data_current, data_delayed};
         Vector#(144, Bit#(1)) dataVec = unpack(data);
         let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
         let nextState0 = compute_next_state(vlan0.etherType);
         let residue0 = takeAt(32, dataVec);
         if (nextState0 == S3) begin
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
            unparsed_out_parse_vlan0_fifo.enq(pack(residue0));
            nextStateArbiter.in[0].enq(nextState0);
         end
      endaction
      endseq
      // VLAN|VLAN
      seq
      action
         let data_delayed <- toGet(unparsed_in_fifo_vlan1).get;
         let data_current = packet_in_wire;
         $display("VLAN|VLAN %x", data_current);
         Bit#(144) data = {data_current, data_delayed};
         Vector#(144, Bit#(1)) dataVec = unpack(data);
         let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
         let nextState0 = compute_next_state(vlan0.etherType);
         let residue0 = takeAt(32, dataVec);
         let vlan1 = extract_vlan(pack(takeAt(32, dataVec)));
         let nextState1 = compute_next_state(vlan1.etherType);
         let residue1 = takeAt(64, dataVec);
         if (nextState0 == S2 && nextState1 == S3) begin
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan1.etherType));
            unparsed_out_parse_vlan1_fifo.enq(pack(residue1));
            nextStateArbiter.in[1].enq(nextState1);
         end
      endaction
      endseq
   endpar;

   FSM fsm_parse_vlan <- mkFSMWithPred(parse_vlan, True);
   //Once once_parse_vlan <- mkOnce(fsm_parse_vlan.start);

   //method Action start = once_parse_vlan.start;
   method Action start = fsm_parse_vlan.start;
   method Action clear;
      //once_parse_vlan.clear;
      fsm_parse_vlan.abort;
      //packet_in_fifo.clear;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedOutVlan0 = toPipeOut(unparsed_out_parse_vlan0_fifo);
   interface unparsedOutVlan1 = toPipeOut(unparsed_out_parse_vlan1_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseIpv4Arbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(3, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseIpv4Arbiter(ParseIpv4Arbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(3, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<3; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

module mkParseIpv4(ParseIpv4);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;

   FIFOF#(Ipv4_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_in_vlan0_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(80)) unparsed_in_vlan1_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(144)) internal_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseIpv4Arbiter nextStateArbiter <- mkParseIpv4Arbiter();

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      $display(fshow("loading packet") + fshow(data_current));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_ipv4_0 =
   // IP
   seq
   action // parse_ipv4
      let residue_last <- toGet(unparsed_in_fifo).get; // 16-bit
      let data_current = packet_in_wire;
      Bit#(144) data = {data_current, residue_last};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      internal_fifo.enq(data);
      if (verbose) $display(fshow(cycle) + fshow("wait one cycle!"));
   endaction
   action // parse_ipv4 0
      let data_delayed <- toGet(internal_fifo).get;
      let data_current = packet_in_wire;
      Bit#(272) data = {data_current, data_delayed};
      Vector#(272, Bit#(1)) dataVec = unpack(data);
      Vector#(112, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[0].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_1 =
   // VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan0_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(240) data = {data_current, residue_last};
      Vector#(240, Bit#(1)) dataVec = unpack(data);
      Vector#(80, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[1].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_2 =
   // VLAN|VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan1_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(208) data = {data_current, residue_last};
      Vector#(208, Bit#(1)) dataVec = unpack(data);
      Vector#(48, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[2].enq(S4);
   endaction
   endseq;

   FSM fsm_parse_ipv4_0 <- mkFSMWithPred(parse_ipv4_0, True);
   FSM fsm_parse_ipv4_1 <- mkFSMWithPred(parse_ipv4_1, True);
   FSM fsm_parse_ipv4_2 <- mkFSMWithPred(parse_ipv4_2, True);

   method Action start();
      fsm_parse_ipv4_0.start;
      fsm_parse_ipv4_1.start;
      fsm_parse_ipv4_2.start;
   endmethod
   method Action clear();
      fsm_parse_ipv4_0.abort;
      fsm_parse_ipv4_1.abort;
      fsm_parse_ipv4_2.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedInVlan0 = toPipeIn(unparsed_in_vlan0_fifo);
   interface unparsedInVlan1 = toPipeIn(unparsed_in_vlan1_fifo);
   interface unparsedOut = toPipeOut(unparsed_out_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

(* synthesize *)
module mkParser(Parser);
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(void) parse_done_fifo <- mkSizedFIFOF(1);

   ParseEthernet parse_ethernet <- mkParseEthernet();
   ParseVlan parse_vlan <- mkParseVlan();
   ParseIpv4 parse_ipv4 <- mkParseIpv4();

   List#(Reg#(Vlan_tag_t)) vlan_tag_stack <- List::replicateM(2, mkReg(defaultValue));

   mkConnection(parse_ethernet.unparsedOutIpv4, parse_ipv4.unparsedIn);
   mkConnection(parse_ethernet.unparsedOutVlan, parse_vlan.unparsedIn);
   mkConnection(parse_vlan.unparsedOutVlan0, parse_ipv4.unparsedInVlan0);
   mkConnection(parse_vlan.unparsedOutVlan1, parse_ipv4.unparsedInVlan1);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Reg#(ParserState) curr_state <- mkReg(S0);
   Reg#(Bool) started <- mkReg(False);

   rule start_fsm (curr_state == S0 && data_in_fifo.notEmpty);
      //$display(fshow(cycle) + fshow("started"));
      if (!started) begin
         parse_ethernet.start;
         parse_vlan.start;
         parse_ipv4.start;
         started <= True;
      end
   endrule

   rule stop_fsm (curr_state == S4);
      //$display(fshow(cycle) + fshow("end"));
      if (started) begin
         parse_ethernet.clear;
         parse_ipv4.clear;
         parse_vlan.clear;
         started <= False;
      end
   endrule

   // Parsing Graph
   (* fire_when_enabled *)
   rule state_S0 (curr_state == S0 && data_in_fifo.notEmpty);
      let v = data_in_fifo.first;
      if (v.sop) begin
         curr_state <= S1;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
      else begin
         data_in_fifo.deq;
      end
   endrule
   (* fire_when_enabled *)
   rule state_S1 (curr_state == S1);
      let v <- toGet(parse_ethernet.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S2 (curr_state == S2);
      let v <- toGet(parse_vlan.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S3 (curr_state == S3);
      let v <- toGet(parse_ipv4.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S4 (curr_state == S4);
      let v <- toGet(data_in_fifo).get;
      if (v.eop) begin
         curr_state <= S0;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
   endrule

   // Data dispatcher.
   rule state_S1_input (curr_state == S1);
      let v <- toGet(data_in_fifo).get;
      parse_ethernet.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ethernet enqueue ")+ fshow(v));
   endrule
   rule state_S2_input (curr_state == S2);
      let v <- toGet(data_in_fifo).get;
      parse_vlan.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_vlan enqueue ")+ fshow(v));
   endrule
   rule state_S3_input (curr_state == S3);
      let v <- toGet(data_in_fifo).get;
      parse_ipv4.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ipv4 enqueue ") + fshow(v));
   endrule

   // derive parse done from state machine
   interface frameIn = toPipeIn(data_in_fifo);
   interface parseDone = toPipeOut(parse_done_fifo);
endmodule

// Copyright (c) 2015 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.

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

import BuildVector::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import Pipe::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;

import Ethernet::*;
import P4Types::*;

interface Parser;
   // derive parseReset from start of packet
   method Action parserReset();
   interface PipeIn#(EtherData) frameIn;
   interface PipeOut#(void) parseDone;
   interface PipeOut#(MatchKey_port_mapping) match_key_port_mapping;
   interface PipeOut#(MatchKey_bd) match_key_bd;
   interface PipeOut#(MatchKey_ipv4_fib) match_key_ipv4_fib;
   interface PipeOut#(MatchKey_ipv4_fib_lpm) match_key_ipv4_fib_lpm;
   interface PipeOut#(MatchKey_nexthop) match_key_nexthop;
   interface PipeOut#(MatchKey_rewrite_mac) match_rewrite_mac;
   interface PipeOut#(Bit#(128)) payloadOut;
endinterface

interface ParseEthernet;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeOut#(Ethernet_t) parsedOut;
   interface PipeOut#(Bit#(16)) unparsedOutIpv4; // number is parse state id
   interface PipeOut#(Bit#(16)) unparsedOutVlan; // number is parse state id
   interface PipeOut#(ParserState) nextState;
   method Action init;
   method Action clear;
endinterface

interface ParseVlan;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Vlan_tag_t) parsedOut;
   interface PipeOut#(Bit#(112)) unparsedOutVlan0;
   interface PipeOut#(Bit#(80)) unparsedOutVlan1;
   interface PipeOut#(ParserState) nextState;
   method Action init;
   method Action clear;
endinterface

interface ParseIpv4;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Ipv4_t) parsedOut;
   interface PipeIn#(Bit#(112)) unparsedInVlan0;
   interface PipeIn#(Bit#(80)) unparsedInVlan1;
   interface PipeOut#(Bit#(112)) unparsedOut;
   interface PipeOut#(ParserState) nextState;
   method Action init;
   method Action clear;
endinterface

typedef enum {S0, S1, S2, S3, S4} ParserState deriving (Bits, Eq);
instance FShow#(ParserState);
   function Fmt fshow (ParserState state);
      return $format(" State %x", state);
   endfunction
endinstance

module mkParseEthernet(ParseEthernet);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Ethernet_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_ipv4_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_vlan_fifo <- mkSizedFIFOF(1);
   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule cycleRule if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Stmt parse_ethernet =
   seq
   action // parse_ethernet
      let data <- toGet(packet_in_fifo).get;
      Vector#(128, Bit#(1)) dataVec = unpack(data);
      let ethernet = extrace_ethernet(pack(takeAt(0, dataVec)));
      Vector#(16, Bit#(1)) unparsed = takeAt(112, dataVec);
      if (verbose) $display(fshow(cycle)
                            +fshow(" ether.dstAddr=")+fshow(ethernet.dstAddr)
                            +fshow(" ether.srcAddr=")+fshow(ethernet.srcAddr)
                            +fshow(" ether.etherType=")+fshow(ethernet.etherType));

      ParserState nextState = S0;
      case (byteSwap2B(ethernet.etherType)) matches
         'h_8100: begin
            unparsed_out_parse_vlan_fifo.enq(pack(unparsed));
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            unparsed_out_parse_ipv4_fifo.enq(pack(unparsed));
            nextState = S3;
         end
         default: begin
            $display("null");
         end
      endcase
      next_state_fifo.enq(nextState);
   endaction
   endseq;

   FSM fsm_parse_ethernet <- mkFSMWithPred(parse_ethernet, True);
   Once once_parse_ethernet <- mkOnce(fsm_parse_ethernet.start);

   method Action init = once_parse_ethernet.start;
   method Action clear = once_parse_ethernet.clear;
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedOutIpv4 = toPipeOut(unparsed_out_parse_ipv4_fifo);
   interface unparsedOutVlan = toPipeOut(unparsed_out_parse_vlan_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseVlanArbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(2, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseVlanArbiter(ParseVlanArbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(2, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<2; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

// Parse second VLAN
module mkParseVlan(ParseVlan);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan0 <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan1 <- mkBypassFIFOF;
   FIFOF#(Vlan_tag_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(112)) unparsed_out_parse_vlan0_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(80)) unparsed_out_parse_vlan1_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseVlanArbiter nextStateArbiter <- mkParseVlanArbiter();

   function ParserState compute_next_state(Bit#(16) etherType);
      ParserState nextState = S0;
      case (byteSwap2B(etherType)) matches
         'h_8100: begin
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            nextState = S3;
         end
      endcase
      return nextState;
   endfunction

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      if (verbose) $display(fshow(cycle) + fshow("load packet in"));
   endrule

   rule load_unparsed_in;
      let data_delayed <- toGet(unparsed_in_fifo).get;
      unparsed_in_fifo_vlan0.enq(data_delayed);
      unparsed_in_fifo_vlan1.enq(data_delayed);
      if (verbose) $display(fshow(cycle) + fshow("load unparsed in"));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_vlan =
   par
      // VLAN
      seq
      action
         let data_delayed <- toGet(unparsed_in_fifo_vlan0).get;
         let data_current = packet_in_wire;
         $display("VLAN %x", data_current);
         Bit#(144) data = {data_current, data_delayed};
         Vector#(144, Bit#(1)) dataVec = unpack(data);
         let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
         let nextState0 = compute_next_state(vlan0.etherType);
         let residue0 = takeAt(32, dataVec);
         if (nextState0 == S3) begin
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
            unparsed_out_parse_vlan0_fifo.enq(pack(residue0));
            nextStateArbiter.in[0].enq(nextState0);
         end
      endaction
      endseq
      // VLAN|VLAN
      seq
      action
         let data_delayed <- toGet(unparsed_in_fifo_vlan1).get;
         let data_current = packet_in_wire;
         $display("VLAN|VLAN %x", data_current);
         Bit#(144) data = {data_current, data_delayed};
         Vector#(144, Bit#(1)) dataVec = unpack(data);
         let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
         let nextState0 = compute_next_state(vlan0.etherType);
         let residue0 = takeAt(32, dataVec);
         let vlan1 = extract_vlan(pack(takeAt(32, dataVec)));
         let nextState1 = compute_next_state(vlan1.etherType);
         let residue1 = takeAt(64, dataVec);
         if (nextState0 == S2 && nextState1 == S3) begin
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan1.etherType));
            unparsed_out_parse_vlan1_fifo.enq(pack(residue1));
            nextStateArbiter.in[1].enq(nextState1);
         end
      endaction
      endseq
   endpar;

   FSM fsm_parse_vlan <- mkFSMWithPred(parse_vlan, True);
   Once once_parse_vlan <- mkOnce(fsm_parse_vlan.start);

   method Action init = once_parse_vlan.start;
   method Action clear = once_parse_vlan.clear;
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedOutVlan0 = toPipeOut(unparsed_out_parse_vlan0_fifo);
   interface unparsedOutVlan1 = toPipeOut(unparsed_out_parse_vlan1_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseIpv4Arbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(3, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseIpv4Arbiter(ParseIpv4Arbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(3, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<3; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

module mkParseIpv4(ParseIpv4);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;

   FIFOF#(Ipv4_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_in_vlan0_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(80)) unparsed_in_vlan1_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(144)) internal_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseIpv4Arbiter nextStateArbiter <- mkParseIpv4Arbiter();

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   // We need a collection for fields to extract. not all fields are required
   // break multiple possible path into multiple modules..
   Stmt parse_ipv4 =
   par
   // IP
   seq
   action // parse_ipv4
      let residue_last <- toGet(unparsed_in_fifo).get; // 16-bit
      let data_current = packet_in_wire;
      Bit#(144) data = {data_current, residue_last};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      internal_fifo.enq(data);
      if (verbose) $display(fshow(cycle) + fshow("wait one cycle!"));
   endaction
   action // parse_ipv4 0
      let data_delayed <- toGet(internal_fifo).get;
      let data_current = packet_in_wire;
      Bit#(272) data = {data_current, data_delayed};
      Vector#(272, Bit#(1)) dataVec = unpack(data);
      Vector#(112, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[0].enq(S4);
   endaction
   endseq
   // VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan0_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(240) data = {data_current, residue_last};
      Vector#(240, Bit#(1)) dataVec = unpack(data);
      Vector#(80, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[1].enq(S4);
   endaction
   endseq
   // VLAN|VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan1_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(208) data = {data_current, residue_last};
      Vector#(208, Bit#(1)) dataVec = unpack(data);
      Vector#(48, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[2].enq(S4);
   endaction
   endseq
   endpar;

   FSM fsm_parse_ipv4 <- mkFSMWithPred(parse_ipv4, True);
   Once once_parse_ipv4 <- mkOnce(fsm_parse_ipv4.start);

   method Action init = once_parse_ipv4.start;
   method Action clear = once_parse_ipv4.clear;
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedInVlan0 = toPipeIn(unparsed_in_vlan0_fifo);
   interface unparsedInVlan1 = toPipeIn(unparsed_in_vlan1_fifo);
   interface unparsedOut = toPipeOut(unparsed_out_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

(* synthesize *)
module mkParser(Parser);
   FIFOF#(EtherData) data_in_fifo <- mkSizedBypassFIFOF(4);
   FIFOF#(void) parse_done_fifo <- mkSizedFIFOF(1);

   ParseEthernet parse_ethernet <- mkParseEthernet();
   ParseVlan parse_vlan <- mkParseVlan();
   ParseIpv4 parse_ipv4 <- mkParseIpv4();

   List#(Reg#(Vlan_tag_t)) vlan_tag_stack <- List::replicateM(2, mkReg(defaultValue));

   mkConnection(parse_ethernet.unparsedOutIpv4, parse_ipv4.unparsedIn);
   mkConnection(parse_ethernet.unparsedOutVlan, parse_vlan.unparsedIn);
   mkConnection(parse_vlan.unparsedOutVlan0, parse_ipv4.unparsedInVlan0);
   mkConnection(parse_vlan.unparsedOutVlan1, parse_ipv4.unparsedInVlan1);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Reg#(ParserState) curr_state <- mkReg(S0);

   // Parsing Graph
   (* fire_when_enabled *)
   rule state_S0 (curr_state == S0 && data_in_fifo.notEmpty);
      let v = data_in_fifo.first;
      if (v.sop) begin
         curr_state <= S1;
         parse_ethernet.init;
         parse_vlan.init;
         parse_ipv4.init;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
      else begin
         data_in_fifo.deq;
      end
   endrule
   (* fire_when_enabled *)
   rule state_S1 (curr_state == S1);
      let v <- toGet(parse_ethernet.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S2 (curr_state == S2);
      let v <- toGet(parse_vlan.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S3 (curr_state == S3);
      let v <- toGet(parse_ipv4.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S4 (curr_state == S4);
      let v <- toGet(data_in_fifo).get;
      if (v.eop) begin
         curr_state <= S0;
         parse_ethernet.clear;
         parse_ipv4.clear;
         parse_vlan.clear;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
   endrule

   // Data dispatcher.
   rule state_S1_input (curr_state == S1);
      let v <- toGet(data_in_fifo).get;
      parse_ethernet.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ethernet enqueue ")+ fshow(v));
   endrule
   rule state_S2_input (curr_state == S2);
      let v <- toGet(data_in_fifo).get;
      parse_vlan.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_vlan enqueue ")+ fshow(v));
   endrule
   rule state_S3_input (curr_state == S3);
      let v <- toGet(data_in_fifo).get;
      parse_ipv4.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ipv4 enqueue ") + fshow(v));
   endrule

   // derive parse done from state machine
   interface frameIn = toPipeIn(data_in_fifo);
   interface parseDone = toPipeOut(parse_done_fifo);
endmodule


retiming load_ctxt logic in memwrite engine to match the logic in memread engine

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

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

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

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

import Vector::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import GetPut::*;
import ClientServer::*;
import BRAM::*;
import BRAMFIFO::*;
import Connectable::*;

import ConfigCounter::*;
import PortalMemory::*;
import MemTypes::*;
import Pipe::*;
import MemUtils::*;

module mkMemwriteEngine(MemwriteEngineV#(dataWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(dataWidth, 8), 8, dataWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Pipe::FunnelPipesPipelined#(1, numServers,Tuple2#(Bit#(TLog#(numServers)), MemTypes::MemengineCmd), TMin#(2,TLog#(numServers)))
	    ,Pipe::FunnelPipesPipelined#(1, numServers,Tuple2#(Bit#(dataWidth),Bool),TMin#(2, TLog#(numServers)))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(1, d__, dataWidth)
	    ,FunnelPipesPipelined#(1, numServers, Tuple3#(Bit#(2),Bit#(dataWidth),Bool), TMin#(2, TLog#(numServers)))
	    ,FunnelPipesPipelined#(1, numServers,Tuple3#(Bit#(TLog#(numServers)), Bit#(dataWidth), Bool), TMin#(2,TLog#(numServers)))
	    );
   let rv <- mkMemwriteEngineBuff(256);
   return rv;
endmodule

interface BurstFunnel#(numeric type k, numeric type w);
   method Action loadIdx(Bit#(TLog#(k)) i);
   interface Vector#(k, PipeIn#(Bit#(w))) dataIn;
   interface Vector#(k, Reg#(Bit#(8))) burstLen;
   interface PipeOut#(Tuple2#(Bit#(TLog#(k)),Bit#(w))) dataOut;
endinterface

module mkBurstFunnel#(Integer maxBurstLen)(BurstFunnel#(k,w))
   provisos( Log#(k,logk)
	    ,Min#(2,logk,bpc)
	    ,FunnelPipesPipelined#(1, k, Tuple3#(Bit#(2),Bit#(w),Bool), bpc)
	    );

   Reg#(Bit#(2)) nameGen <- mkReg(0);
   UGBramFifos#(4,16,Tuple2#(Bit#(w),Bool)) complBuff <- mkUGBramFifos;
   Vector#(4, ConfigCounter#(16)) compCnts <- replicateM(mkConfigCounter(0));
   Vector#(k,FIFOF#(Tuple3#(Bit#(2), Bit#(w), Bool))) data_in <- replicateM(mkFIFOF);
   Vector#(k,Reg#(Bit#(8))) burst_len <- replicateM(mkReg(0));
   Vector#(k,Reg#(Bit#(8))) drain_cnt <- replicateM(mkReg(0));
   Reg#(Bit#(8)) inj_ctrl <- mkReg(0);
   FIFO#(Tuple2#(Bit#(TAdd#(1,logk)),Bit#(2))) loadIdxs <- mkSizedFIFO(32);
   FIFO#(Tuple2#(Bit#(TAdd#(1,logk)),Bit#(2))) inFlight <- mkSizedFIFO(4);
   FunnelPipe#(1, k, Tuple3#(Bit#(2),Bit#(w),Bool),bpc) data_in_funnel <- mkFunnelPipesPipelined(map(toPipeOut,data_in));
   Reg#(Bit#(8)) drainCnt <- mkReg(0);
   FIFOF#(Tuple2#(Bit#(TLog#(k)),Bit#(w))) exit_data <- mkFIFOF;
   FIFO#(Bit#(logk)) drainRename <- mkFIFO;

   Reg#(Bit#(32)) cycle <- mkReg(0);
   Reg#(Bit#(32)) last_entry <- mkReg(0);

   rule cyc;
      cycle <= cycle+1;
   endrule

   function PipeIn#(Bit#(w)) enter_data(FIFOF#(Tuple3#(Bit#(2), Bit#(w), Bool)) f, Integer i) =
      (interface PipeIn;
   	  method Bool notFull = f.notFull;
   	  method Action enq(Bit#(w) v) if (tpl_1(loadIdxs.first) == fromInteger(i));
	     last_entry <= cycle;
	     match {.old_name, .new_name} = loadIdxs.first;
	     let first = inj_ctrl == 0;
	     let cnt = first ? burst_len[i] : inj_ctrl;
	     let new_cnt = cnt-1;
	     let last = new_cnt == 0;
	     inj_ctrl <= new_cnt;
	     if (first)
		inFlight.enq(loadIdxs.first);
	     if (last)
		loadIdxs.deq;
	     f.enq(tuple3(new_name, v, last));
	     //$display("%d enq %d", cycle-last_entry, i);
	  endmethod
       endinterface);
   Vector#(k, PipeIn#(Bit#(w))) data_in_pipes = zipWith(enter_data, data_in, genVector);

   function Reg#(Bit#(8)) check(Reg#(Bit#(8)) r) =
      (interface Reg;
	  method Action _write(Bit#(8) v);
	     if(v > 16) begin
		$display("ERROR mkBurstFunnel: burstLen too large");
		$finish;
	     end
	     r <= v;
	  endmethod
	  method Bit#(8) _read = r._read;
       endinterface);

   rule drain_funnel;
      match{.new_name,.data,.last} = data_in_funnel[0].first;
      data_in_funnel[0].deq;
      complBuff.enq(new_name,tuple2(data,last));
      compCnts[new_name].increment(1);
   endrule

   rule drain_req (compCnts[tpl_2(inFlight.first)].read > 0);
      match {.old_name, .new_name} = inFlight.first;
      let new_drainCnt = drainCnt-1;
      if (drainCnt == 0) begin
	 new_drainCnt = burst_len[old_name]-1;
	 drainRename.enq(truncate(old_name));
      end
      if (new_drainCnt == 0) begin
	 inFlight.deq;
      end
      complBuff.first_req(new_name);
      drainCnt <= new_drainCnt;
      compCnts[new_name].decrement(1);
      complBuff.deq(new_name);
   endrule

   rule drain_resp;
      match {.data,.last} <- complBuff.first_resp;
      if (last)
	 drainRename.deq;
      exit_data.enq(tuple2(drainRename.first,data));
   endrule

   method Action loadIdx(Bit#(logk) idx);
      loadIdxs.enq(tuple2(extend(idx),nameGen));
      nameGen <= nameGen+1;
   endmethod
   interface burstLen = map(check,burst_len);
   interface dataIn = data_in_pipes;
   interface PipeOut dataOut = toPipeOut(exit_data);
endmodule

module mkMemwriteEngineBuff#(Integer bufferSizeBytes)(MemwriteEngineV#(dataWidth, cmdQDepth, numServers))
   provisos ( Div#(dataWidth,8,dataWidthBytes)
	     ,Mul#(dataWidthBytes,8,dataWidth)
	     ,Log#(dataWidthBytes,beatShift)
	     ,Log#(cmdQDepth,logCmdQDepth)
	     ,Mul#(cmdQDepth,numServers,cmdBuffSz)
	     ,Log#(cmdBuffSz, cmdBuffAddrSz)
	     ,Log#(numServers, serverIdxSz)
	     ,Add#(1,logCmdQDepth, outCntSz)
	     ,Add#(1, c__, numServers)
	     ,Add#(b__, TLog#(numServers), cmdBuffAddrSz)
	     ,Add#(e__, TLog#(numServers), TAdd#(1, cmdBuffAddrSz))
	     ,Add#(a__, serverIdxSz, cmdBuffAddrSz)
	     ,Min#(2,TLog#(numServers),bpc)
	     ,FunnelPipesPipelined#(1,numServers,Tuple2#(Bit#(serverIdxSz),MemengineCmd),bpc)
	     ,FunnelPipesPipelined#(1,numServers,Tuple2#(Bit#(dataWidth),Bool),bpc)
	     ,FunnelPipesPipelined#(1, numServers, Tuple3#(Bit#(2),Bit#(dataWidth),Bool), TMin#(2, serverIdxSz))
	     ,Add#(1, d__, dataWidth)
	     ,FunnelPipesPipelined#(1, numServers, Tuple3#(Bit#(serverIdxSz),Bit#(dataWidth), Bool), TMin#(2, serverIdxSz))
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(dataWidthBytes);
   Vector#(numServers, Reg#(Bit#(outCntSz)))     outs1 <- replicateM(mkReg(0));
   Vector#(numServers, Reg#(Bit#(outCntSz)))     outs0 <- replicateM(mkReg(0));
   Vector#(numServers, ConfigCounter#(16))           buffCap <- replicateM(mkConfigCounter(0));
   UGBramFifos#(numServers,cmdQDepth,MemengineCmd) cmdBuf <- mkUGBramFifos;

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple2#(MemengineCmd,Bool))              loadf_b <- mkSizedFIFO(1);
   FIFO#(Tuple2#(Bit#(serverIdxSz),MemengineCmd)) loadf_c <- mkSizedFIFO(1);
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool))   workf <- mkSizedFIFO(32); // is this the right size?
   FIFO#(Tuple2#(Bit#(serverIdxSz),Bool))           donef <- mkSizedFIFO(32); // is this the right size?

   Vector#(numServers, FIFO#(void))              outfs <- replicateM(mkSizedFIFO(1));
   Vector#(numServers, FIFOF#(Tuple2#(Bit#(serverIdxSz), MemengineCmd))) cmds_in <- replicateM(mkSizedFIFOF(1));
   FunnelPipe#(1, numServers, Tuple2#(Bit#(serverIdxSz), MemengineCmd),bpc) cmds_in_funnel <- mkFunnelPipesPipelined(map(toPipeOut,cmds_in));
   Vector#(numServers, FIFOF#(Bit#(dataWidth)))  write_data_buffs <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   Vector#(numServers, PipeOut#(Bit#(dataWidth))) foo = map(toPipeOut, write_data_buffs);
   BurstFunnel#(numServers,dataWidth) write_data_funnel <- mkBurstFunnel(bufferSizeBeats);
   zipWithM(mkConnection, foo, write_data_funnel.dataIn);

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

   rule store_cmd;
      match {.idx, .cmd} <- toGet(cmds_in_funnel[0]).get;
      outs1[idx] <= outs1[idx]+1;
      cmdBuf.enq(idx,cmd);
      //$display("store_cmd %d", idx);
   endrule

   rule load_ctxt_a (!load_in_progress);
      if (outs1[loadIdx] > 0) begin
	 load_in_progress <= True;
	 cmdBuf.first_req(loadIdx);
      end
      else begin
	 loadIdx <= loadIdx+1;
      end
   endrule

   rule load_ctxt_b;
      let cmd <- cmdBuf.first_resp;
      let cond = buffCap[loadIdx].read() >= unpack(extend(cmd.burstLen>>beat_shift));
      loadf_b.enq(tuple2(cmd,cond));
   endrule

   rule load_ctxt_c;
      load_in_progress <= False;
      loadIdx <= loadIdx+1;
      match {.cmd,.cond} <- toGet(loadf_b).get;
      if  (cond) begin
	 //$display("load_ctxt_b %h %d", cmd.base, idx);
	 buffCap[loadIdx].decrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 loadf_c.enq(tuple2(loadIdx,cmd));
	 write_data_funnel.loadIdx(loadIdx);
	 if (cmd.len <= extend(cmd.burstLen)) begin
	    outs1[loadIdx] <= outs1[loadIdx]-1;
	    cmdBuf.deq(loadIdx);
	 end
	 else begin
	    let new_cmd = MemengineCmd{pointer:cmd.pointer, base:cmd.base+extend(cmd.burstLen), burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen)};
	    cmdBuf.upd_head(loadIdx,new_cmd);
	 end
      end
   endrule

   function PipeIn#(Bit#(w)) check_in(FIFOF#(Bit#(w)) f, Integer i) =
      (interface PipeIn;
   	  method Bool notFull = f.notFull;
   	  method Action enq(Bit#(w) v);
	     f.enq(v);
	     buffCap[i].increment(1);
	     //$display("check_in %d", i);
	     // if(i==2)
	     // 	for(Integer j = 0; j < valueOf(w); j=j+32) begin
	     // 	   Bit#(32) xx = v[j+31:j];
	     // 	   $display("%h", xx);
	     // 	end
	  endmethod
       endinterface);

   Vector#(numServers, Server#(MemengineCmd,Bool)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface Server#(MemengineCmd,Bool);
		  interface Put request;
		     method Action put(MemengineCmd c) if (outs0[i] < cmd_q_depth);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
			if(extend(c.burstLen) > bsb)
			   $display("mkMemwriteEngineV::unsupportedBurstLen");
			outs0[i] <= outs0[i]+1;
			cmds_in[i].enq(tuple2(fromInteger(i),c));
			write_data_funnel.burstLen[i] <= c.burstLen >> beat_shift;
			//$display("(%d) %h %h %h", i, c.base, c.len, c.burstLen);
 		     endmethod
		  endinterface
		  interface Get response;
		     method ActionValue#(Bool) get;
			outfs[i].deq;
	 		outs0[i] <= outs0[i]-1;
			return True;
		     endmethod
		  endinterface
	       endinterface);
   interface writeServers = rs;
   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get();
	    match {.idx, .cmd} <- toGet(loadf_c).get;
	    Bit#(8) bl = cmd.burstLen;
	    Bool last = False;
	    if (cmd.len <= extend(bl)) begin
	       last = True;
	       bl = truncate(cmd.len);
	    end
	    workf.enq(tuple3(truncate(bl>>beat_shift), idx, last));
	    //$display("writeReq %d, %h %h %h", idx, cmd.base, bl, last);
	    return ObjectRequest { pointer: cmd.pointer, offset: cmd.base, burstLen:bl, tag: 0 };
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get;
	    match {.rc, .idx, .last} = workf.first;
	    let new_respCnt = respCnt+1;
	    if (new_respCnt == rc) begin
	       respCnt <= 0;
	       workf.deq;
	       donef.enq(tuple2(idx,last));
	    end
	    else begin
	       respCnt <= new_respCnt;
	    end
	    match {._idx, .wd} <- toGet(write_data_funnel.dataOut).get;
	    if(_idx != idx) begin
	       $display("ERROR mkMemwriteEngineBuf: bursts oo %d %d", idx, _idx);
	       $finish;
	    end
	    return ObjectData{data:wd, tag:0, last: False};
	 endmethod
      endinterface
      interface Put writeDone;
	 method Action put(Bit#(6) tag);
	    match {.idx, .last} <- toGet(donef).get;
	    if (last)
	       outfs[idx].enq(?);
	    //$display("writeDone %d %d", idx, last);
	 endmethod
      endinterface
   endinterface
   interface dataPipes = zipWith(check_in, write_data_buffs, genVector);
endmodule

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

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

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

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

import Vector::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import GetPut::*;
import ClientServer::*;
import BRAM::*;
import BRAMFIFO::*;
import Connectable::*;

import ConfigCounter::*;
import PortalMemory::*;
import MemTypes::*;
import Pipe::*;
import MemUtils::*;

module mkMemwriteEngine(MemwriteEngineV#(dataWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(dataWidth, 8), 8, dataWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Pipe::FunnelPipesPipelined#(1, numServers,Tuple2#(Bit#(TLog#(numServers)), MemTypes::MemengineCmd), TMin#(2,TLog#(numServers)))
	    ,Pipe::FunnelPipesPipelined#(1, numServers,Tuple2#(Bit#(dataWidth),Bool),TMin#(2, TLog#(numServers)))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(1, d__, dataWidth)
	    ,FunnelPipesPipelined#(1, numServers, Tuple3#(Bit#(2),Bit#(dataWidth),Bool), TMin#(2, TLog#(numServers)))
	    ,FunnelPipesPipelined#(1, numServers,Tuple3#(Bit#(TLog#(numServers)), Bit#(dataWidth), Bool), TMin#(2,TLog#(numServers)))
	    );
   let rv <- mkMemwriteEngineBuff(256);
   return rv;
endmodule

interface BurstFunnel#(numeric type k, numeric type w);
   method Action loadIdx(Bit#(TLog#(k)) i);
   interface Vector#(k, PipeIn#(Bit#(w))) dataIn;
   interface Vector#(k, Reg#(Bit#(8))) burstLen;
   interface PipeOut#(Tuple2#(Bit#(TLog#(k)),Bit#(w))) dataOut;
endinterface

module mkBurstFunnel#(Integer maxBurstLen)(BurstFunnel#(k,w))
   provisos( Log#(k,logk)
	    ,Min#(2,logk,bpc)
	    ,FunnelPipesPipelined#(1, k, Tuple3#(Bit#(2),Bit#(w),Bool), bpc)
	    );

   Reg#(Bit#(2)) nameGen <- mkReg(0);
   UGBramFifos#(4,16,Tuple2#(Bit#(w),Bool)) complBuff <- mkUGBramFifos;
   Vector#(4, ConfigCounter#(16)) compCnts <- replicateM(mkConfigCounter(0));
   Vector#(k,FIFOF#(Tuple3#(Bit#(2), Bit#(w), Bool))) data_in <- replicateM(mkFIFOF);
   Vector#(k,Reg#(Bit#(8))) burst_len <- replicateM(mkReg(0));
   Vector#(k,Reg#(Bit#(8))) drain_cnt <- replicateM(mkReg(0));
   Reg#(Bit#(8)) inj_ctrl <- mkReg(0);
   FIFO#(Tuple2#(Bit#(TAdd#(1,logk)),Bit#(2))) loadIdxs <- mkSizedFIFO(32);
   FIFO#(Tuple2#(Bit#(TAdd#(1,logk)),Bit#(2))) inFlight <- mkSizedFIFO(4);
   FunnelPipe#(1, k, Tuple3#(Bit#(2),Bit#(w),Bool),bpc) data_in_funnel <- mkFunnelPipesPipelined(map(toPipeOut,data_in));
   Reg#(Bit#(8)) drainCnt <- mkReg(0);
   FIFOF#(Tuple2#(Bit#(TLog#(k)),Bit#(w))) exit_data <- mkFIFOF;
   FIFO#(Bit#(logk)) drainRename <- mkFIFO;

   Reg#(Bit#(32)) cycle <- mkReg(0);
   Reg#(Bit#(32)) last_entry <- mkReg(0);

   rule cyc;
      cycle <= cycle+1;
   endrule

   function PipeIn#(Bit#(w)) enter_data(FIFOF#(Tuple3#(Bit#(2), Bit#(w), Bool)) f, Integer i) =
      (interface PipeIn;
   	  method Bool notFull = f.notFull;
   	  method Action enq(Bit#(w) v) if (tpl_1(loadIdxs.first) == fromInteger(i));
	     last_entry <= cycle;
	     match {.old_name, .new_name} = loadIdxs.first;
	     let first = inj_ctrl == 0;
	     let cnt = first ? burst_len[i] : inj_ctrl;
	     let new_cnt = cnt-1;
	     let last = new_cnt == 0;
	     inj_ctrl <= new_cnt;
	     if (first)
		inFlight.enq(loadIdxs.first);
	     if (last)
		loadIdxs.deq;
	     f.enq(tuple3(new_name, v, last));
	     //$display("%d enq %d", cycle-last_entry, i);
	  endmethod
       endinterface);
   Vector#(k, PipeIn#(Bit#(w))) data_in_pipes = zipWith(enter_data, data_in, genVector);

   function Reg#(Bit#(8)) check(Reg#(Bit#(8)) r) =
      (interface Reg;
	  method Action _write(Bit#(8) v);
	     if(v > 16) begin
		$display("ERROR mkBurstFunnel: burstLen too large");
		$finish;
	     end
	     r <= v;
	  endmethod
	  method Bit#(8) _read = r._read;
       endinterface);

   rule drain_funnel;
      match{.new_name,.data,.last} = data_in_funnel[0].first;
      data_in_funnel[0].deq;
      complBuff.enq(new_name,tuple2(data,last));
      compCnts[new_name].increment(1);
   endrule

   rule drain_req (compCnts[tpl_2(inFlight.first)].read > 0);
      match {.old_name, .new_name} = inFlight.first;
      let new_drainCnt = drainCnt-1;
      if (drainCnt == 0) begin
	 new_drainCnt = burst_len[old_name]-1;
	 drainRename.enq(truncate(old_name));
      end
      if (new_drainCnt == 0) begin
	 inFlight.deq;
      end
      complBuff.first_req(new_name);
      drainCnt <= new_drainCnt;
      compCnts[new_name].decrement(1);
      complBuff.deq(new_name);
   endrule

   rule drain_resp;
      match {.data,.last} <- complBuff.first_resp;
      if (last)
	 drainRename.deq;
      exit_data.enq(tuple2(drainRename.first,data));
   endrule

   method Action loadIdx(Bit#(logk) idx);
      loadIdxs.enq(tuple2(extend(idx),nameGen));
      nameGen <= nameGen+1;
   endmethod
   interface burstLen = map(check,burst_len);
   interface dataIn = data_in_pipes;
   interface PipeOut dataOut = toPipeOut(exit_data);
endmodule

module mkMemwriteEngineBuff#(Integer bufferSizeBytes)(MemwriteEngineV#(dataWidth, cmdQDepth, numServers))
   provisos ( Div#(dataWidth,8,dataWidthBytes)
	     ,Mul#(dataWidthBytes,8,dataWidth)
	     ,Log#(dataWidthBytes,beatShift)
	     ,Log#(cmdQDepth,logCmdQDepth)
	     ,Mul#(cmdQDepth,numServers,cmdBuffSz)
	     ,Log#(cmdBuffSz, cmdBuffAddrSz)
	     ,Log#(numServers, serverIdxSz)
	     ,Add#(1,logCmdQDepth, outCntSz)
	     ,Add#(1, c__, numServers)
	     ,Add#(b__, TLog#(numServers), cmdBuffAddrSz)
	     ,Add#(e__, TLog#(numServers), TAdd#(1, cmdBuffAddrSz))
	     ,Add#(a__, serverIdxSz, cmdBuffAddrSz)
	     ,Min#(2,TLog#(numServers),bpc)
	     ,FunnelPipesPipelined#(1,numServers,Tuple2#(Bit#(serverIdxSz),MemengineCmd),bpc)
	     ,FunnelPipesPipelined#(1,numServers,Tuple2#(Bit#(dataWidth),Bool),bpc)
	     ,FunnelPipesPipelined#(1, numServers, Tuple3#(Bit#(2),Bit#(dataWidth),Bool), TMin#(2, serverIdxSz))
	     ,Add#(1, d__, dataWidth)
	     ,FunnelPipesPipelined#(1, numServers, Tuple3#(Bit#(serverIdxSz),Bit#(dataWidth), Bool), TMin#(2, serverIdxSz))
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(dataWidthBytes);
   Vector#(numServers, Reg#(Bit#(outCntSz)))     outs1 <- replicateM(mkReg(0));
   Vector#(numServers, Reg#(Bit#(outCntSz)))     outs0 <- replicateM(mkReg(0));
   Vector#(numServers, ConfigCounter#(16))           buffCap <- replicateM(mkConfigCounter(0));
   UGBramFifos#(numServers,cmdQDepth,MemengineCmd) cmdBuf <- mkUGBramFifos;

   FIFO#(Bit#(serverIdxSz))                       loadf_a <- mkSizedFIFO(1);
   FIFO#(MemengineCmd)                            loadf_b <- mkSizedFIFO(1);
   FIFO#(Tuple2#(Bit#(serverIdxSz),MemengineCmd)) loadf_c <- mkSizedFIFO(1);
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool))   workf <- mkSizedFIFO(32); // is this the right size?
   FIFO#(Tuple2#(Bit#(serverIdxSz),Bool))           donef <- mkSizedFIFO(32); // is this the right size?

   Vector#(numServers, FIFO#(void))              outfs <- replicateM(mkSizedFIFO(1));
   Vector#(numServers, FIFOF#(Tuple2#(Bit#(serverIdxSz), MemengineCmd))) cmds_in <- replicateM(mkSizedFIFOF(1));
   FunnelPipe#(1, numServers, Tuple2#(Bit#(serverIdxSz), MemengineCmd),bpc) cmds_in_funnel <- mkFunnelPipesPipelined(map(toPipeOut,cmds_in));
   Vector#(numServers, FIFOF#(Bit#(dataWidth)))  write_data_buffs <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   Vector#(numServers, PipeOut#(Bit#(dataWidth))) foo = map(toPipeOut, write_data_buffs);
   BurstFunnel#(numServers,dataWidth) write_data_funnel <- mkBurstFunnel(bufferSizeBeats);
   zipWithM(mkConnection, foo, write_data_funnel.dataIn);

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

   rule store_cmd;
      match {.idx, .cmd} <- toGet(cmds_in_funnel[0]).get;
      outs1[idx] <= outs1[idx]+1;
      cmdBuf.enq(idx,cmd);
      //$display("store_cmd %d", idx);
   endrule

   rule load_ctxt_a;
      loadIdx <= loadIdx+1;
      if (outs1[loadIdx] > 0) begin
	 cmdBuf.first_req(loadIdx);
	 loadf_a.enq(loadIdx);
	 //$display("load_ctxt_a %d", loadIdx);
      end
   endrule

   rule load_ctxt_b;
      let cmd <- cmdBuf.first_resp;
      loadf_b.enq(cmd);
   endrule

   rule load_ctxt_c;
      let idx <- toGet(loadf_a).get;
      let cmd <- toGet(loadf_b).get;
      //$display("%d %d %d", outs1[idx], buffCap[idx].read(), cmd.burstLen>>beat_shift);
      if (outs1[idx] > 0 && buffCap[idx].read() >= unpack(extend(cmd.burstLen>>beat_shift))) begin
	 //$display("load_ctxt_b %h %d", cmd.base, idx);
	 buffCap[idx].decrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 loadf_c.enq(tuple2(idx,cmd));
	 write_data_funnel.loadIdx(idx);
	 if (cmd.len <= extend(cmd.burstLen)) begin
	    outs1[idx] <= outs1[idx]-1;
	    cmdBuf.deq(idx);
	 end
	 else begin
	    let new_cmd = MemengineCmd{pointer:cmd.pointer, base:cmd.base+extend(cmd.burstLen), burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen)};
	    cmdBuf.upd_head(idx,new_cmd);
	 end
      end
   endrule

   function PipeIn#(Bit#(w)) check_in(FIFOF#(Bit#(w)) f, Integer i) =
      (interface PipeIn;
   	  method Bool notFull = f.notFull;
   	  method Action enq(Bit#(w) v);
	     f.enq(v);
	     buffCap[i].increment(1);
	     //$display("check_in %d", i);
	     // if(i==2)
	     // 	for(Integer j = 0; j < valueOf(w); j=j+32) begin
	     // 	   Bit#(32) xx = v[j+31:j];
	     // 	   $display("%h", xx);
	     // 	end
	  endmethod
       endinterface);

   Vector#(numServers, Server#(MemengineCmd,Bool)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface Server#(MemengineCmd,Bool);
		  interface Put request;
		     method Action put(MemengineCmd c) if (outs0[i] < cmd_q_depth);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
			if(extend(c.burstLen) > bsb)
			   $display("mkMemwriteEngineV::unsupportedBurstLen");
			outs0[i] <= outs0[i]+1;
			cmds_in[i].enq(tuple2(fromInteger(i),c));
			write_data_funnel.burstLen[i] <= c.burstLen >> beat_shift;
			//$display("(%d) %h %h %h", i, c.base, c.len, c.burstLen);
 		     endmethod
		  endinterface
		  interface Get response;
		     method ActionValue#(Bool) get;
			outfs[i].deq;
	 		outs0[i] <= outs0[i]-1;
			return True;
		     endmethod
		  endinterface
	       endinterface);
   interface writeServers = rs;
   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get();
	    match {.idx, .cmd} <- toGet(loadf_c).get;
	    Bit#(8) bl = cmd.burstLen;
	    Bool last = False;
	    if (cmd.len <= extend(bl)) begin
	       last = True;
	       bl = truncate(cmd.len);
	    end
	    workf.enq(tuple3(truncate(bl>>beat_shift), idx, last));
	    //$display("writeReq %d, %h %h %h", idx, cmd.base, bl, last);
	    return ObjectRequest { pointer: cmd.pointer, offset: cmd.base, burstLen:bl, tag: 0 };
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get;
	    match {.rc, .idx, .last} = workf.first;
	    let new_respCnt = respCnt+1;
	    if (new_respCnt == rc) begin
	       respCnt <= 0;
	       workf.deq;
	       donef.enq(tuple2(idx,last));
	    end
	    else begin
	       respCnt <= new_respCnt;
	    end
	    match {._idx, .wd} <- toGet(write_data_funnel.dataOut).get;
	    if(_idx != idx) begin
	       $display("ERROR mkMemwriteEngineBuf: bursts oo %d %d", idx, _idx);
	       $finish;
	    end
	    return ObjectData{data:wd, tag:0, last: False};
	 endmethod
      endinterface
      interface Put writeDone;
	 method Action put(Bit#(6) tag);
	    match {.idx, .last} <- toGet(donef).get;
	    if (last)
	       outfs[idx].enq(?);
	    //$display("writeDone %d %d", idx, last);
	 endmethod
      endinterface
   endinterface
   interface dataPipes = zipWith(check_in, write_data_buffs, genVector);
endmodule