minor update for reset

minor update for reset

// 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 DtpDCFifo            ::*;
import ALTERA_SI570_WRAPPER          ::*;
import ALTERA_EDGE_DETECTOR_WRAPPER  ::*;
import AlteraExtra                   ::*;
import BuildVector                  ::*;

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

interface DtpPhyIfc#(numeric type numPorts);
   interface Vector#(numPorts, PipeIn#(Bit#(72)))  tx;
   interface Vector#(numPorts, PipeOut#(Bit#(72))) rx;
   (*always_ready, always_enabled*)
   method Vector#(numPorts,Bit#(1)) serial_tx;
   (*always_ready, always_enabled*)
   method Action serial_rx(Vector#(numPorts,Bit#(1)) data);
   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;
   interface Vector#(numPorts, PipeOut#(PcsDbgRec)) tx_dbg;
   interface Vector#(numPorts, PipeOut#(PcsDbgRec)) rx_dbg;
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)(DtpPhyIfc#(numPorts));
   let verbose = True;

   Reg#(Bit#(32)) cycle <- mkReg(0);
   Reset defaultReset <- exposeCurrentReset;
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, mgmt_clk);
   Reset rst_156_25_n <- mkAsyncReset(2, defaultReset, clk_156_25);
   //let rst_156_25_n = defaultReset;

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

   let bypass_dtp = 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;

`ifdef SYNTHESIS
   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
`else
   Vector#(numPorts, Reg#(Bool)) rx_ready_tx;
   Vector#(numPorts, Reg#(Bool)) tx_ready_tx;
   Vector#(numPorts, Reg#(Bool)) rx_ready_rx;
   Vector#(numPorts, Reg#(Bool)) tx_ready_rx;
   Vector#(numPorts, Reg#(Bool)) lock_tx;
   for (Integer i=0; i<valueOf(numPorts); i=i+1) begin
      rx_ready_tx[i] <- mkReg(True);
      tx_ready_tx[i] <- mkReg(True);
      rx_ready_rx[i] <- mkReg(True);
      tx_ready_rx[i] <- mkReg(True);
      lock_tx[i] <- mkReg(False);
   end
`endif

   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;

   // Debugging
   Vector#(numPorts, SyncFIFOIfc#(PcsDbgRec)) phyRxDebug = newVector;
   Vector#(numPorts, FIFOF#(PcsDbgRec)) phyTxDebug <- replicateM(mkFIFOF(clocked_by clk_156_25, reset_by rst_156_25_n));

   // 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
`ifdef SYNTHESIS
      Clock rxClock = pma4.rx_clkout[i];
      Reset rxReset = pma4.rx_reset[i];
`else
      Clock rxClock = clk_156_25;
      Reset rxReset = rst_156_25_n;
`endif

      rxFifo[i] <- mkFIFOF(clocked_by rxClock, reset_by rxReset);
      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, rxClock);//, pma4.rx_reset[i]);
      lpbkSyncPipeOut[i] = toPipeOut(lpbkSyncFifo[i]);
      lpbkSyncPipeIn[i] = toPipeIn(lpbkSyncFifo[i]);

      //pcs_rx[i]    <- mkEthPcsRxTop(clocked_by rxClock, reset_by rxReset);
      //pcs_tx[i]    <- mkEthPcsTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);
      pcs_rx[i]    <- mkEthPcsRx(i, clocked_by rxClock, reset_by rxReset);
      pcs_tx[i]    <- mkEthPcsTx(i, clocked_by clk_156_25, reset_by rst_156_25_n);
      dtp_rx[i]    <- mkDtpRxTop(clocked_by rxClock, reset_by rxReset);
      dtp_tx[i]    <- mkDtpTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);

      dtpEventFifo[i] <- mkSyncFIFO(10, rxClock, rxReset, clk_156_25);//, rst_156_25_n);
      //dtpEventFifo[i] <- mkDtpDCFifo(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, rxClock, rxReset, clk_156_25);//, rst_156_25_n);
      dtpErrCntOut[i] = toPipeOut(dtpErrCntFifo[i]);
      dtpErrCntIn[i]  = toPipeIn(dtpErrCntFifo[i]);

      if (bypass_dtp) begin
          // Rx Path: bypassing dtp
          mkConnection(pcs_rx[i].dtpRxIn, pcs_rx[i].dtpRxOut);
      end
      else begin
          // 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);
      end
      // 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);
      if (bypass_dtp) begin
          // Tx Path: bypassing dtp
          mkConnection(pcs_tx[i].dtpTxIn, pcs_tx[i].dtpTxOut);
      end
      else begin
          // 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);
      end

`ifdef SYNTHESIS
      // debugging
      phyRxDebug[i] <- mkSyncFIFO(4, pma4.rx_clkout[i], pma4.rx_reset[i], clk_156_25);
      rule update_rx_debug;
         let v = pcs_rx[i].dbg;
         phyRxDebug[i].enq(v);
      endrule
      rule update_tx_debug ;
        let v = pcs_tx[i].dbg;
        phyTxDebug[i].enq(v);
      endrule
`endif

      // 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);
      let rx_lpbk_en = False;
      let tx_lpbk_en = False;

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

`ifdef SYNTHESIS
      // 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
`else
    rule tx_sim;
        let v <- toGet(pcs_tx[i].scramblerOut).get;
        lpbkSyncPipeIn[i].enq(v);
    endrule
    rule rx_sim;
        let v <- toGet(lpbkSyncPipeOut[i]).get;
        pcs_rx[i].bsyncIn.enq(v);
    endrule
`endif
   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);
`ifdef SYNTHESIS
         dtp_tx[i].bsync_lock(lock_tx[i].crossed);
`else
         dtp_tx[i].bsync_lock(lock_tx[i]);
`endif

      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;
         if (verbose) $display("EthPhy %d: decoderOut=%h", i, v);
         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
   function PcsDbgRec getPcsTxDbgRec (EthPcsTx tx);
    return tx.dbg;
   endfunction
   function PcsDbgRec getPcsRxDbgRec (EthPcsRx rx);
    return rx.dbg;
   endfunction

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

`ifdef SYNTHESIS
   interface rx_clkout = pma4.rx_clkout;
   interface tx_clkout = pma4.tx_clkout;
   method serial_tx = pma4.serial_tx;
   method serial_rx = pma4.serial_rx;
   interface led_rx_ready = pma4.rx_ready;
`else
    interface rx_clkout = replicate(clk_156_25);
    interface tx_clkout = replicate(clk_156_25);
`endif
   interface rx = vRxPipeOut;
   interface tx = vTxPipeIn;

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

   interface tx_dbg = map(toPipeOut, phyTxDebug);
   interface rx_dbg = map(toPipeOut, phyRxDebug);

   //method Vector#(numPorts, PcsDbgRec) tx_dbg = map(getPcsTxDbgRec, pcs_tx);//cons(pcs_tx[0].dbg, cons(pcs_tx[1].dbg, cons(pcs_tx[2].dbg, cons(pcs_tx[3].dbg, nil))));//vec(map(getPcsTxDbgRec, pcs_tx));
   //method Vector#(numPorts, PcsDbgRec) rx_dbg = map(getPcsRxDbgRec, pcs_rx);
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 DtpDCFifo            ::*;
import ALTERA_SI570_WRAPPER          ::*;
import ALTERA_EDGE_DETECTOR_WRAPPER  ::*;
import AlteraExtra                   ::*;
import BuildVector                  ::*;

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

interface DtpPhyIfc#(numeric type numPorts);
   interface Vector#(numPorts, PipeIn#(Bit#(72)))  tx;
   interface Vector#(numPorts, PipeOut#(Bit#(72))) rx;
   (*always_ready, always_enabled*)
   method Vector#(numPorts,Bit#(1)) serial_tx;
   (*always_ready, always_enabled*)
   method Action serial_rx(Vector#(numPorts,Bit#(1)) data);
   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;
   interface Vector#(numPorts, PipeOut#(PcsDbgRec)) tx_dbg;
   interface Vector#(numPorts, PipeOut#(PcsDbgRec)) rx_dbg;
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)(DtpPhyIfc#(numPorts));
   let verbose = True;

   Reg#(Bit#(32)) cycle <- mkReg(0);
   Reset defaultReset <- exposeCurrentReset;
   Reset rst_50_n <- mkSyncReset(0, defaultReset, mgmt_clk);
   Reset rst_156_25_n <- mkSyncReset(0, defaultReset, clk_156_25);
   //let rst_156_25_n = defaultReset;

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

   let bypass_dtp = 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;

`ifdef SYNTHESIS
   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
`else
   Vector#(numPorts, Reg#(Bool)) rx_ready_tx;
   Vector#(numPorts, Reg#(Bool)) tx_ready_tx;
   Vector#(numPorts, Reg#(Bool)) rx_ready_rx;
   Vector#(numPorts, Reg#(Bool)) tx_ready_rx;
   Vector#(numPorts, Reg#(Bool)) lock_tx;
   for (Integer i=0; i<valueOf(numPorts); i=i+1) begin
      rx_ready_tx[i] <- mkReg(True);
      tx_ready_tx[i] <- mkReg(True);
      rx_ready_rx[i] <- mkReg(True);
      tx_ready_rx[i] <- mkReg(True);
      lock_tx[i] <- mkReg(False);
   end
`endif

   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;

   // Debugging
   Vector#(numPorts, SyncFIFOIfc#(PcsDbgRec)) phyRxDebug = newVector;
   Vector#(numPorts, FIFOF#(PcsDbgRec)) phyTxDebug <- replicateM(mkFIFOF(clocked_by clk_156_25, reset_by rst_156_25_n));

   // 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
`ifdef SYNTHESIS
      Clock rxClock = pma4.rx_clkout[i];
      Reset rxReset = pma4.rx_reset[i];
`else
      Clock rxClock = clk_156_25;
      Reset rxReset = rst_156_25_n;
`endif

      rxFifo[i] <- mkFIFOF(clocked_by rxClock, reset_by rxReset);
      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, rxClock);//, pma4.rx_reset[i]);
      lpbkSyncPipeOut[i] = toPipeOut(lpbkSyncFifo[i]);
      lpbkSyncPipeIn[i] = toPipeIn(lpbkSyncFifo[i]);

      //pcs_rx[i]    <- mkEthPcsRxTop(clocked_by rxClock, reset_by rxReset);
      //pcs_tx[i]    <- mkEthPcsTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);
      pcs_rx[i]    <- mkEthPcsRx(i, clocked_by rxClock, reset_by rxReset);
      pcs_tx[i]    <- mkEthPcsTx(i, clocked_by clk_156_25, reset_by rst_156_25_n);
      dtp_rx[i]    <- mkDtpRxTop(clocked_by rxClock, reset_by rxReset);
      dtp_tx[i]    <- mkDtpTxTop(clocked_by clk_156_25, reset_by rst_156_25_n);

      dtpEventFifo[i] <- mkSyncFIFO(10, rxClock, rxReset, clk_156_25);//, rst_156_25_n);
      //dtpEventFifo[i] <- mkDtpDCFifo(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, rxClock, rxReset, clk_156_25);//, rst_156_25_n);
      dtpErrCntOut[i] = toPipeOut(dtpErrCntFifo[i]);
      dtpErrCntIn[i]  = toPipeIn(dtpErrCntFifo[i]);

      if (bypass_dtp) begin
          // Rx Path: bypassing dtp
          mkConnection(pcs_rx[i].dtpRxIn, pcs_rx[i].dtpRxOut);
      end
      else begin
          // 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);
      end
      // 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);
      if (bypass_dtp) begin
          // Tx Path: bypassing dtp
          mkConnection(pcs_tx[i].dtpTxIn, pcs_tx[i].dtpTxOut);
      end
      else begin
          // 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);
      end

`ifdef SYNTHESIS
      // debugging
      phyRxDebug[i] <- mkSyncFIFO(4, pma4.rx_clkout[i], pma4.rx_reset[i], clk_156_25);
      rule update_rx_debug;
         let v = pcs_rx[i].dbg;
         phyRxDebug[i].enq(v);
      endrule
      rule update_tx_debug ;
        let v = pcs_tx[i].dbg;
        phyTxDebug[i].enq(v);
      endrule
`endif

      // 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);
      let rx_lpbk_en = False;
      let tx_lpbk_en = False;

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

`ifdef SYNTHESIS
      // 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
`else
    rule tx_sim;
        let v <- toGet(pcs_tx[i].scramblerOut).get;
        lpbkSyncPipeIn[i].enq(v);
    endrule
    rule rx_sim;
        let v <- toGet(lpbkSyncPipeOut[i]).get;
        pcs_rx[i].bsyncIn.enq(v);
    endrule
`endif
   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);
`ifdef SYNTHESIS
         dtp_tx[i].bsync_lock(lock_tx[i].crossed);
`else
         dtp_tx[i].bsync_lock(lock_tx[i]);
`endif

      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;
         if (verbose) $display("EthPhy %d: decoderOut=%h", i, v);
         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
   function PcsDbgRec getPcsTxDbgRec (EthPcsTx tx);
    return tx.dbg;
   endfunction
   function PcsDbgRec getPcsRxDbgRec (EthPcsRx rx);
    return rx.dbg;
   endfunction

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

`ifdef SYNTHESIS
   interface rx_clkout = pma4.rx_clkout;
   interface tx_clkout = pma4.tx_clkout;
   method serial_tx = pma4.serial_tx;
   method serial_rx = pma4.serial_rx;
   interface led_rx_ready = pma4.rx_ready;
`else
    interface rx_clkout = replicate(clk_156_25);
    interface tx_clkout = replicate(clk_156_25);
`endif
   interface rx = vRxPipeOut;
   interface tx = vTxPipeIn;

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

   interface tx_dbg = map(toPipeOut, phyTxDebug);
   interface rx_dbg = map(toPipeOut, phyRxDebug);

   //method Vector#(numPorts, PcsDbgRec) tx_dbg = map(getPcsTxDbgRec, pcs_tx);//cons(pcs_tx[0].dbg, cons(pcs_tx[1].dbg, cons(pcs_tx[2].dbg, cons(pcs_tx[3].dbg, nil))));//vec(map(getPcsTxDbgRec, pcs_tx));
   //method Vector#(numPorts, PcsDbgRec) rx_dbg = map(getPcsRxDbgRec, pcs_rx);
endmodule: mkEthPhy
endpackage: EthPhy


add defaultClock method for bcsan.sel

add defaultClock method for bcsan.sel

// 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)     sel();
   method Bit#(1)     shift();
   method Bit#(1)     tdi();
   method Action      tdo(Bit#(1) v);
   method Bit#(1)     update();
   method Bool        first();
   method Bit#(1)     selsync();
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 capture = bscan.capture;
   method sel = bscan.sel;
   method shift = bscan.shift;
   method tdi = bscan.tdi;
   method tdo = bscan.tdo;
   method update = bscan.update;
   method first();
      return selected.read() && !selectdelay;
   endmethod
   method selsync();
      return pack(selected.read());
   endmethod
endmodule

interface BscanBram#(type atype, type dtype);
   interface BRAMClient#(atype, dtype) bramClient;
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#(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);

   let readNext = startWrite.pulse() || bscan.first();

   rule capturer if(bscan.capture() == 1);
       shiftReg <= tojtag.read();
   endrule
   rule shiftrule if (bscan.shift() == 1);
       shiftReg <= { bscan.tdi(), shiftReg[dsz-1:1] };
   endrule
   rule tdo;
      bscan.tdo(shiftReg[0]);
   endrule
   rule sendwrite if(bscan.sel() == 1 && bscan.update() == 1);
       startWrite.send();
       fromjtag.send(shiftReg);
   endrule

   rule addrRule if (readNext);
       let v = fromInteger(0);  // first time USER1, reset address
       if (startWrite.pulse())
           v = addrReg + 1;
       addrReg <= v;
   endrule
   rule readClear;
       readData <= readNext;
   endrule

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (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
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)     sel();
   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 capture = bscan.capture;
   method sel = bscan.sel;
   method shift = bscan.shift;
   method tdi = bscan.tdi;
   method tdo = bscan.tdo;
   method update = bscan.update;
   method first();
      return selected.read() && !selectdelay;
   endmethod
endmodule

interface BscanBram#(type atype, type dtype);
   interface BRAMClient#(atype, dtype) bramClient;
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#(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);

   let readNext = startWrite.pulse() || bscan.first();

   rule capturer if(bscan.capture() == 1);
       shiftReg <= tojtag.read();
   endrule
   rule shiftrule if (bscan.shift() == 1);
       shiftReg <= { bscan.tdi(), shiftReg[dsz-1:1] };
   endrule
   rule tdo;
      bscan.tdo(shiftReg[0]);
   endrule
   rule sendwrite if(bscan.sel() == 1 && bscan.update() == 1);
       startWrite.send();
       fromjtag.send(shiftReg);
   endrule

   rule addrRule if (readNext);
       let v = fromInteger(0);  // first time USER1, reset address
       if (startWrite.pulse())
           v = addrReg + 1;
       addrReg <= v;
   endrule
   rule readClear;
       readData <= readNext;
   endrule

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (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
endmodule


replacing definition of mkAxi3SlaveOutOfRange with mkAxi3SlaveFromRegFile(nullRegFile)

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

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

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

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

import FIFO::*;
import GetPut::*;
import Connectable::*;
import RegFile::*;

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

function Bit#(3) axiBusSize(Integer busWidth);
   if (busWidth == 32)
      return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
   else if (busWidth == 64)
      return 3'b011;
   else if (busWidth == 128)
      return 3'b100;
   else
      return 3'b011;
endfunction

typedef struct {
   Bit#(busWidth) data;
   Bit#(2) resp;
   Bit#(1) last;
   Bit#(idWidth) id;
} Axi3ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi3WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi3WriteResponse#(type idWidth) deriving (Bits);

interface Axi3Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Get#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi3Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

function Put#(t) null_put();
   return (interface Put;
	      method Action put(t x) if (False);
		 noAction;
	      endmethod
	   endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
	      method ActionValue#(t) get() if (False);
		 return ?;
	      endmethod
	   endinterface);
endfunction

function  Axi3Master#(addrWidth, busWidth, idWidth) null_axi_master();
   return (interface Axi3Master;
	      interface Get req_ar = null_get;
	      interface Put resp_read = null_put;
	      interface Get req_aw = null_get;
	      interface Get resp_write = null_get;
	      interface Put resp_b = null_put;
	   endinterface);
endfunction

interface RegFileA#(type index_t, type data_t);
   method Action upd(index_t addr, data_t d);
   method ActionValue#(data_t) sub(index_t addr);
endinterface

module mkRegFileANull#(data_t defv) (RegFileA#(index_t,data_t));
   method Action upd(index_t addr, data_t d);
      noAction;
   endmethod
   method ActionValue#(data_t) sub(index_t addr);
      return defv;
   endmethod
endmodule

module mkAxi3SlaveOutOfRange (Axi3Slave#(addrWidth, busWidth, idWidth));
   RegFileA#(Bit#(addrWidth), Bit#(busWidth)) rf <- mkRegFileANull(0);
   let rv <- mkAxi3SlaveFromRegFile(rf);
   return rv;
endmodule

module mkAxi3SlaveFromRegFile#(RegFileA#(Bit#(regFileBusWidth), Bit#(busWidth)) rf) (Axi3Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));

   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();
   let req_ar_fifo <- mkSizedFIFO(1);

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
   	 req_ar_fifo.enq(tuple3(truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8)))), req.id, req.len+1));
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get();
   	 let addr = readAddrReg;
   	 let id = readIdReg;
   	 let burstCount = readBurstCountReg;
   	 if (readBurstCountReg == 0) begin
            addr = tpl_1(req_ar_fifo.first);
   	    id = tpl_2(req_ar_fifo.first);
            burstCount = tpl_3(req_ar_fifo.first);
   	    req_ar_fifo.deq;
   	 end
         let data <- rf.sub(addr);
         if (verbose) $display("axiSlave.read.readData %h %h %d", addr, data, burstCount);
         readBurstCountReg <= burstCount - 1;
         readAddrReg <= addr + 1;
   	 readIdReg <= id;
         return Axi3ReadResponse { data: data, last: (burstCount == 1) ? 1 : 0, id: id, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(2) resp;
    Bit#(1) last;
    Bit#(idWidth) id;
} Axi4ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi4WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi4WriteResponse#(type idWidth) deriving (Bits);

interface Axi4Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;

   interface Get#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi4Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

module mkAxi4SlaveFromRegFile#(RegFile#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi4Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi4ReadRequest#(addrWidth,idWidth) req) if (readBurstCountReg == 0);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
         readAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
	 readIdReg <= req.id;
         readBurstCountReg <= truncate(req.len)+1;
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi4ReadResponse#(busWidth,idWidth)) get() if (readBurstCountReg > 0);
         let data = rf.sub(readAddrReg);
         if (verbose) $display("axiSlave.read.readData %h %h %d", readAddrReg, data, readBurstCountReg);
         readBurstCountReg <= readBurstCountReg - 1;
         readAddrReg <= readAddrReg + 1;
         return Axi4ReadResponse { data: data, last: (readBurstCountReg == 1) ? 1 : 0, id: readIdReg, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi4WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= truncate(req.len)+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi4WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi4WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi4WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

instance Connectable#(Axi3Master#(addrWidth, busWidth,idWidth), Axi3Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi3Master#(addrWidth, busWidth,idWidth) m, Axi3Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance

instance Connectable#(Axi4Master#(addrWidth, busWidth,idWidth), Axi4Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi4Master#(addrWidth, busWidth,idWidth) m, Axi4Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance

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

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

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

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

import FIFO::*;
import GetPut::*;
import Connectable::*;
import RegFile::*;

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

function Bit#(3) axiBusSize(Integer busWidth);
   if (busWidth == 32)
      return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
   else if (busWidth == 64)
      return 3'b011;
   else if (busWidth == 128)
      return 3'b100;
   else
      return 3'b011;
endfunction

typedef struct {
   Bit#(busWidth) data;
   Bit#(2) resp;
   Bit#(1) last;
   Bit#(idWidth) id;
} Axi3ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi3WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi3WriteResponse#(type idWidth) deriving (Bits);

interface Axi3Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Get#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi3Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

function Put#(t) null_put();
   return (interface Put;
	      method Action put(t x) if (False);
		 noAction;
	      endmethod
	   endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
	      method ActionValue#(t) get() if (False);
		 return ?;
	      endmethod
	   endinterface);
endfunction

function  Axi3Master#(addrWidth, busWidth, idWidth) null_axi_master();
   return (interface Axi3Master;
	      interface Get req_ar = null_get;
	      interface Put resp_read = null_put;
	      interface Get req_aw = null_get;
	      interface Get resp_write = null_get;
	      interface Put resp_b = null_put;
	   endinterface);
endfunction

interface RegFileA#(type index_t, type data_t);
   method Action upd(index_t addr, data_t d);
   method ActionValue#(data_t) sub(index_t addr);
endinterface

module mkAxi3SlaveFromRegFile#(RegFileA#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi3Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();
   let req_ar_fifo <- mkSizedFIFO(1);

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
   	 req_ar_fifo.enq(tuple3(truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8)))), req.id, req.len+1));
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get();
   	 let addr = readAddrReg;
   	 let id = readIdReg;
   	 let burstCount = readBurstCountReg;
   	 if (readBurstCountReg == 0) begin
            addr = tpl_1(req_ar_fifo.first);
   	    id = tpl_2(req_ar_fifo.first);
            burstCount = tpl_3(req_ar_fifo.first);
   	    req_ar_fifo.deq;
   	 end
         let data <- rf.sub(addr);
         if (verbose) $display("axiSlave.read.readData %h %h %d", addr, data, burstCount);
         readBurstCountReg <= burstCount - 1;
         readAddrReg <= addr + 1;
   	 readIdReg <= id;
         return Axi3ReadResponse { data: data, last: (burstCount == 1) ? 1 : 0, id: id, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

module mkAxi3SlaveOutOfRange (Axi3Slave#(addrWidth, busWidth, idWidth));

   Reg#(Bit#(addrWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(addrWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();
   let req_ar_fifo <- mkSizedFIFO(1);

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
   	 req_ar_fifo.enq(tuple3(truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8)))), req.id, req.len+1));
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get();
   	 let addr = readAddrReg;
   	 let id = readIdReg;
   	 let burstCount = readBurstCountReg;
   	 if (readBurstCountReg == 0) begin
            addr = tpl_1(req_ar_fifo.first);
   	    id = tpl_2(req_ar_fifo.first);
            burstCount = tpl_3(req_ar_fifo.first);
   	    req_ar_fifo.deq;
   	 end
         let data = 0;
         if (verbose) $display("axiSlave.read.readData %h %h %d", addr, data, burstCount);
         readBurstCountReg <= burstCount - 1;
         readAddrReg <= addr + 1;
   	 readIdReg <= id;
         return Axi3ReadResponse { data: data, last: (burstCount == 1) ? 1 : 0, id: id, resp: 2'b11 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         writeAddrReg <= req.address/fromInteger(valueOf(TDiv#(busWidth,8)));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(2'b11);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(2) resp;
    Bit#(1) last;
    Bit#(idWidth) id;
} Axi4ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi4WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi4WriteResponse#(type idWidth) deriving (Bits);

interface Axi4Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;

   interface Get#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi4Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

module mkAxi4SlaveFromRegFile#(RegFile#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi4Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi4ReadRequest#(addrWidth,idWidth) req) if (readBurstCountReg == 0);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
         readAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
	 readIdReg <= req.id;
         readBurstCountReg <= truncate(req.len)+1;
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi4ReadResponse#(busWidth,idWidth)) get() if (readBurstCountReg > 0);
         let data = rf.sub(readAddrReg);
         if (verbose) $display("axiSlave.read.readData %h %h %d", readAddrReg, data, readBurstCountReg);
         readBurstCountReg <= readBurstCountReg - 1;
         readAddrReg <= readAddrReg + 1;
         return Axi4ReadResponse { data: data, last: (readBurstCountReg == 1) ? 1 : 0, id: readIdReg, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi4WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= truncate(req.len)+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi4WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi4WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi4WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

instance Connectable#(Axi3Master#(addrWidth, busWidth,idWidth), Axi3Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi3Master#(addrWidth, busWidth,idWidth) m, Axi3Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance

instance Connectable#(Axi4Master#(addrWidth, busWidth,idWidth), Axi4Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi4Master#(addrWidth, busWidth,idWidth) m, Axi4Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance


In MemreadEngine, correctly decrement buffCap on last_burst

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

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

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

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

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

import ConnectalMemory::*;
import MemTypes::*;
import Pipe::*;
import MemUtils::*;

module mkMemreadEngine(MemreadEngine#(dataWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(dataWidth, 8), 8, dataWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(d__, TLog#(numServers), 6)
	    );
   let rv <- mkMemreadEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemreadEngineBuff#(Integer bufferSizeBytes) (MemreadEngine#(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),
	     Add#(d__, TLog#(numServers), TAdd#(1, serverIdxSz)),
	     Add#(f__, serverIdxSz, 6));

   let verbose = False;

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(dataWidthBytes);
   Vector#(numServers, Reg#(Bool))               outs1 <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))     buffCap <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))     cmdRegs <- replicateM(mkReg(unpack(0)));

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple4#(MemengineCmd,Bool,Bool,Bit#(BurstLenSize)))              loadf_b <- mkSizedFIFO(1);
   FIFO#(Tuple4#(Bit#(serverIdxSz),MemengineCmd,Bool,Bit#(BurstLenSize))) loadf_c <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool))        workf <- mkSizedFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(void))              outfs <- replicateM(mkSizedFIFO(valueOf(cmdQDepth)));
   Vector#(numServers, FIFO#(MemengineCmd))    cmds_in <- replicateM(mkFIFO());

   FIFOF#(MemData#(dataWidth))                             read_data <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemData#(dataWidth)))  read_data_buffs <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(Bit#(dataWidth)) check_out(PipeOut#(MemData#(dataWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method Bit#(dataWidth) first;
	     return inpipe.first.data;
	  endmethod
	  method Action deq;
	     if (verbose) $display("mkMemreadEngineBuff::check_out: idx %d data %h buffCap %d eob %d", i, inpipe.first.data, buffCap[i].read(), inpipe.first.last);
	     inpipe.deq;
	     buffCap[i].increment(1);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(Bit#(dataWidth))) read_data_pipes = zipWith(check_out, map(toPipeOut,read_data_buffs), genVector);

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

   function Action incr_loadIdx =
      (action
       if(loadIdx+1 >= fromInteger(valueOf(numServers)))
	  loadIdx <= 0;
       else
	  loadIdx <= loadIdx+1;
       endaction);

   for (Integer idx = 0; idx < valueOf(numServers); idx = idx + 1)
      rule store_cmd if (!outs1[idx]);
	 let cmd <- toGet(cmds_in[idx]).get();
	 outs1[idx] <= True;
	 cmdRegs[idx] <= cmd;
	 if (verbose) $display("mkMemreadEngineBuff::store_cmd %d %d", idx, buffCap[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (outs1[loadIdx]) begin
	 load_in_progress <= True;
	 let cmd = cmdRegs[loadIdx];
         let last_burst = cmd.len <= extend(cmd.burstLen);
         Bit#(BurstLenSize) cmd_len = cmd.burstLen;
	 if (last_burst)
             cmd_len = truncate(cmd.len);
	 let cond0 <- buffCap[loadIdx].maybeDecrement(unpack(extend(cmd_len>>beat_shift)));
	 loadf_b.enq(tuple4(cmd,cond0,last_burst,cmd_len));
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_b buffCap %d burstLen %d cond0 %d last_burst %d", buffCap[loadIdx].read(), cmd_len>>beat_shift, cond0, last_burst);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for outs1 to avoid the need for this pragma
   (* descending_urgency = "load_ctxt_c, store_cmd" *)
   rule load_ctxt_c if (load_in_progress);
      load_in_progress <= False;
      incr_loadIdx;
      match {.cmd,.cond0,.last_burst,.cmd_len} <- toGet(loadf_b).get;
      if  (cond0) begin
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", cmd.len, loadIdx, cond0, last_burst);
	 loadf_c.enq(tuple4(truncate(loadIdx),cmd,last_burst,cmd_len));
	 if (last_burst) begin
	    if (verbose) $display("mkMemreadEngineBuff::load_ctxt_b last_burst %d", last_burst);
	    outfs[loadIdx].enq(?);
	    outs1[loadIdx] <= False;
	 end
	 else begin
	    let new_cmd = MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
				       burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	    cmdRegs[loadIdx] <= new_cmd;
	 end
      end
   endrule

   rule read_data_rule;
      let d <- toGet(read_data).get();
      match {.rc, .idx, .last_burst} = workf.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("mkMemreadEngineBuff::%h new_respCnt %d rc %d last_burst %d idx %d outs1 %d eob %d", d.data, new_respCnt, rc, last_burst, idx, outs1[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 workf.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      d.last = l;
      read_data_buffs[idx].enq(d);
   endrule

   function MemreadServer#(dataWidth) toMemreadServer(Server#(MemengineCmd,Bool) cs, PipeOut#(Bit#(dataWidth)) p) =
      (interface MemreadServer;
	  interface cmdServer = cs;
	  interface dataPipe  = p;
       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 cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef BSIM
			Bit#(32) dw = fromInteger(valueOf(dataWidthBytes));
			let mdw = ((cmd.len)/dw)*dw != cmd.len;
			let bbl = extend(cmd.burstLen) > bsb;
			if(bbl || mdw) begin
			   if (bbl)
			      $display("XXXXXXXXXX mkMemreadEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
			   if (mdw)
			      $display("XXXXXXXXXX mkMemreadEngineBuff::unsupported len %d", cmd.len);
			end
			else begin
`endif
			   cmds_in[i].enq(cmd);
`ifdef BSIM
			end
`endif
 		     endmethod
		  endinterface
		  interface Get response;
		     method ActionValue#(Bool) get;
			outfs[i].deq;
			return True;
		     endmethod
		  endinterface
	       endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd, .last_burst, .bl} <- toGet(loadf_c).get;
	    workf.enq(tuple3(truncate(bl>>beat_shift), idx, last_burst));
	    if (verbose) $display("MemreadEngine::readReq idx %d offset %h burstLenBytes %h last_burst %d", idx, cmd.base, bl, last_burst);
	    return MemRequest { sglId: cmd.sglId, offset: cmd.base, burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)};
	 endmethod
      endinterface
      interface Put readData = toPut(read_data);
   endinterface
   interface dataPipes = read_data_pipes;
   interface read_servers = zipWith(toMemreadServer, rs, read_data_pipes);
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 Assert::*;
import ClientServer::*;
import BRAM::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import Connectable::*;

import ConnectalMemory::*;
import MemTypes::*;
import Pipe::*;
import MemUtils::*;

module mkMemreadEngine(MemreadEngine#(dataWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(dataWidth, 8), 8, dataWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(d__, TLog#(numServers), 6)
	    );
   let rv <- mkMemreadEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemreadEngineBuff#(Integer bufferSizeBytes) (MemreadEngine#(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),
	     Add#(d__, TLog#(numServers), TAdd#(1, serverIdxSz)),
	     Add#(f__, serverIdxSz, 6));

   let verbose = False;

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(dataWidthBytes);
   Vector#(numServers, Reg#(Bool))               outs1 <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))     buffCap <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))     cmdRegs <- replicateM(mkReg(unpack(0)));

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))              loadf_b <- mkSizedFIFO(1);
   FIFO#(Tuple3#(Bit#(serverIdxSz),MemengineCmd,Bool)) loadf_c <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool))        workf <- mkSizedFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(void))              outfs <- replicateM(mkSizedFIFO(valueOf(cmdQDepth)));
   Vector#(numServers, FIFO#(MemengineCmd))    cmds_in <- replicateM(mkFIFO());

   FIFOF#(MemData#(dataWidth))                             read_data <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemData#(dataWidth)))  read_data_buffs <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(Bit#(dataWidth)) check_out(PipeOut#(MemData#(dataWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method Bit#(dataWidth) first;
	     return inpipe.first.data;
	  endmethod
	  method Action deq;
	     if (verbose) $display("mkMemreadEngineBuff::check_out: idx %d data %h buffCap %d eob %d", i, inpipe.first.data, buffCap[i].read(), inpipe.first.last);
	     inpipe.deq;
	     buffCap[i].increment(1);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(Bit#(dataWidth))) read_data_pipes = zipWith(check_out, map(toPipeOut,read_data_buffs), genVector);

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

   function Action incr_loadIdx =
      (action
       if(loadIdx+1 >= fromInteger(valueOf(numServers)))
	  loadIdx <= 0;
       else
	  loadIdx <= loadIdx+1;
       endaction);

   for (Integer idx = 0; idx < valueOf(numServers); idx = idx + 1)
      rule store_cmd if (!outs1[idx]);
	 let cmd <- toGet(cmds_in[idx]).get();
	 outs1[idx] <= True;
	 cmdRegs[idx] <= cmd;
	 if (verbose) $display("mkMemreadEngineBuff::store_cmd %d %d", idx, buffCap[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (outs1[loadIdx]) begin
	 load_in_progress <= True;
	 let cmd = cmdRegs[loadIdx];
	 let cond0 <- buffCap[loadIdx].maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let last_burst = cmd.len <= extend(cmd.burstLen);
	 loadf_b.enq(tuple3(cmd,cond0,last_burst));
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_b buffCap %d burstLen %d cond0 %d last_burst %d", buffCap[loadIdx].read(), cmd.burstLen>>beat_shift, cond0, last_burst);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for outs1 to avoid the need for this pragma
   (* descending_urgency = "load_ctxt_c, store_cmd" *)
   rule load_ctxt_c if (load_in_progress);
      load_in_progress <= False;
      incr_loadIdx;
      match {.cmd,.cond0,.last_burst} <- toGet(loadf_b).get;
      if  (cond0) begin
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", cmd.len, loadIdx, cond0, last_burst);
	 let x = cmd.burstLen;
	 if (cmd.len < extend(cmd.burstLen))
	    x = truncate(cmd.len);
	 loadf_c.enq(tuple3(truncate(loadIdx),cmd,last_burst));
	 if (last_burst) begin
	    if (verbose) $display("mkMemreadEngineBuff::load_ctxt_b last_burst %d", last_burst);
	    outfs[loadIdx].enq(?);
	    outs1[loadIdx] <= False;
	 end
	 else begin
	    let new_cmd = MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
				       burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	    cmdRegs[loadIdx] <= new_cmd;
	 end
      end
   endrule

   rule read_data_rule;
      let d <- toGet(read_data).get();
      match {.rc, .idx, .last_burst} = workf.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("mkMemreadEngineBuff::%h new_respCnt %d rc %d last_burst %d idx %d outs1 %d eob %d", d.data, new_respCnt, rc, last_burst, idx, outs1[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 workf.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      d.last = l;
      read_data_buffs[idx].enq(d);
   endrule

   function MemreadServer#(dataWidth) toMemreadServer(Server#(MemengineCmd,Bool) cs, PipeOut#(Bit#(dataWidth)) p) =
      (interface MemreadServer;
	  interface cmdServer = cs;
	  interface dataPipe  = p;
       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 cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef BSIM
			Bit#(32) dw = fromInteger(valueOf(dataWidthBytes));
			let mdw = ((cmd.len)/dw)*dw != cmd.len;
			let bbl = extend(cmd.burstLen) > bsb;
			if(bbl || mdw) begin
			   if (bbl)
			      $display("XXXXXXXXXX mkMemreadEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
			   if (mdw)
			      $display("XXXXXXXXXX mkMemreadEngineBuff::unsupported len %d", cmd.len);
			end
			else begin
`endif
			   cmds_in[i].enq(cmd);
`ifdef BSIM
			end
`endif
 		     endmethod
		  endinterface
		  interface Get response;
		     method ActionValue#(Bool) get;
			outfs[i].deq;
			return True;
		     endmethod
		  endinterface
	       endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd, .last_burst} <- toGet(loadf_c).get;
	    Bit#(BurstLenSize) bl = cmd.burstLen;
	    if (last_burst) begin
	       bl = truncate(cmd.len);
	    end
	    workf.enq(tuple3(truncate(bl>>beat_shift), idx, last_burst));
	    if (verbose) $display("MemreadEngine::readReq idx %d offset %h burstLenBytes %h last_burst %d", idx, cmd.base, bl, last_burst);
	    return MemRequest { sglId: cmd.sglId, offset: cmd.base, burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)};
	 endmethod
      endinterface
      interface Put readData = toPut(read_data);
   endinterface
   interface dataPipes = read_data_pipes;
   interface read_servers = zipWith(toMemreadServer, rs, read_data_pipes);
endmodule


adding more comments to Strstr.bsv.  I think there may actually be a bug in my implementation...

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

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

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

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

import FIFO::*;
import SpecialFIFOs::*;
import GetPutF::*;
import Vector::*;
import BRAM::*;
import Gearbox::*;

import AxiMasterSlave::*;
import Dma::*;
import DmaUtils::*;

interface StrstrRequest;
   method Action search(Bit#(32) needleHandle, Bit#(32) haystackHandle, Bit#(32) mpNextHandle, Bit#(32) needle_len, Bit#(32) haystack_len);
endinterface

interface StrstrIndication;
   method Action searchResult(Int#(32) v);
endinterface

typedef Bit#(8) Char;
typedef Bit#(64) DWord;
typedef Bit#(32) Word;

typedef 1024 MaxNeedleLen;
typedef Bit#(TLog#(MaxNeedleLen)) NeedleIdx;

typedef enum {Idle, Init, Run} Stage deriving (Eq, Bits);

module mkStrstrRequest#(StrstrIndication indication,
			DmaReadServer#(busWidth)   haystack_read_chan,
			DmaReadServer#(busWidth)     needle_read_chan,
			DmaReadServer#(busWidth)    mp_next_read_chan )(StrstrRequest)

   provisos(Add#(a__, 8, busWidth),
	    Div#(busWidth,8,nc),
	    Mul#(nc,8,busWidth),
	    Add#(1, b__, nc),
	    Add#(c__, 32, busWidth),
	    Add#(1, d__, TDiv#(busWidth, 32)),
	    Mul#(TDiv#(busWidth, 32), 32, busWidth));

   Clock clk <- exposeCurrentClock;
   Reset rst <- exposeCurrentReset;
   BRAM2Port#(NeedleIdx, Char) needle  <- mkBRAM2Server(defaultValue);
   BRAM2Port#(NeedleIdx, Bit#(32)) mpNext <- mkBRAM2Server(defaultValue);
   Gearbox#(nc,1,Char) haystack <- mkNto1Gearbox(clk,rst,clk,rst);

   Reg#(Stage) stage <- mkReg(Idle);
   Reg#(Bit#(32)) needleLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackLenReg <- mkReg(0);
   Reg#(Bit#(32)) iReg <- mkReg(0); // offset in needle
   Reg#(Bit#(32)) jReg <- mkReg(0); // offset in haystack
   Reg#(DmaPointer) haystackHandle <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) haystackPtr <- mkReg(0);

   DmaReadServer2BRAM#(NeedleIdx) n2b <- mkDmaReadServer2BRAM(needle_read_chan, needle.portB);
   DmaReadServer2BRAM#(NeedleIdx) mp2b <- mkDmaReadServer2BRAM(mp_next_read_chan, mpNext.portB);

   Reg#(Bit#(2)) epochReg <- mkReg(0);
   FIFO#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFO(2);
   Reg#(Bit#(32)) cycle <- mkReg(0);

   rule start (stage == Init);
      let x <- n2b.finished;
      let y <- mp2b.finished;
      stage <= Run;
      iReg <= 1;
      jReg <= 1;
   endrule

   (* descending_urgency = "mp2b_load, n2b_load, matchNeedleResp, matchNeedleReq" *)

   rule haystackReq (stage == Run);
      haystack_read_chan.readReq.put(DmaRequest {handle: haystackHandle, address: haystackPtr, burstLen: 1, tag: 0});
      haystackPtr <= haystackPtr + fromInteger(valueOf(nc));
   endrule

   rule haystackResp;
      let rv <- haystack_read_chan.readData.get;
      Vector#(nc,Char) pv = unpack(rv.data);
      haystack.enq(pv);
   endrule

   rule haystackDrain(stage != Run);
      haystack.deq;
   endrule

   rule matchNeedleReq(stage == Run);
      needle.portA.request.put(BRAMRequest{write:False, address:truncate(iReg-1)});
      mpNext.portA.request.put(BRAMRequest{write:False, address:truncate(iReg)});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= iReg+1;
      //$display("matchNeedleReq %d %d", epochReg, iReg);
   endrule

   rule hb (stage==Run);
      //$display("cycle %h **************************", cycle);
      cycle <= cycle+1;
   endrule

   rule matchNeedleResp(stage == Run);
      let nv <- needle.portA.response.get;
      let mp <- mpNext.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (epoch == epochReg) begin
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    indication.searchResult(-1);
	    stage <= Idle;
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    // $display("string match %d", j);
	    indication.searchResult(unpack(j-i));
	    epochReg <= epochReg+1;
	    iReg <= 1;
	 end
	 else if ((i>0) && (nv != hv[0])) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    // $display("char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    epochReg <= epochReg + 1;
	    iReg <= mp;
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    // $display("   char match %d %d", i, j);
	    jReg <= j+1;
	    haystack.deq;
	 end
      end
   endrule

   method Action search(Bit#(32) needle_handle, Bit#(32) haystack_handle, Bit#(32) mpNext_handle,
			Bit#(32) needle_len, Bit#(32) haystack_len) if (stage == Idle);

      $display("search %h %h", needle_len, haystack_len);
      needleLenReg <= needle_len;
      haystackLenReg <= haystack_len;
      n2b.start(needle_handle, pack(truncate(needle_len)));
      mp2b.start(mpNext_handle, pack(truncate(needle_len)));
      haystackHandle <= haystack_handle;
      stage <= Init;

   endmethod
endmodule

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

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

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

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

import FIFO::*;
import SpecialFIFOs::*;
import GetPutF::*;
import Vector::*;
import BRAM::*;
import Gearbox::*;

import AxiMasterSlave::*;
import Dma::*;
import DmaUtils::*;

interface StrstrRequest;
   method Action search(Bit#(32) needleHandle, Bit#(32) haystackHandle, Bit#(32) mpNextHandle, Bit#(32) needle_len, Bit#(32) haystack_len);
endinterface

interface StrstrIndication;
   method Action searchResult(Int#(32) v);
endinterface

typedef Bit#(8) Char;
typedef Bit#(64) DWord;
typedef Bit#(32) Word;

typedef 1024 MaxNeedleLen;
typedef Bit#(TLog#(MaxNeedleLen)) NeedleIdx;

typedef enum {Idle, Init, Run} Stage deriving (Eq, Bits);

module mkStrstrRequest#(StrstrIndication indication,
			DmaReadServer#(busWidth)   haystack_read_chan,
			DmaReadServer#(busWidth)     needle_read_chan,
			DmaReadServer#(busWidth)    mp_next_read_chan )(StrstrRequest)

   provisos(Add#(a__, 8, busWidth),
	    Div#(busWidth,8,nc),
	    Mul#(nc,8,busWidth),
	    Add#(1, b__, nc),
	    Add#(c__, 32, busWidth),
	    Add#(1, d__, TDiv#(busWidth, 32)),
	    Mul#(TDiv#(busWidth, 32), 32, busWidth));

   Clock clk <- exposeCurrentClock;
   Reset rst <- exposeCurrentReset;
   BRAM2Port#(NeedleIdx, Char) needle  <- mkBRAM2Server(defaultValue);
   BRAM2Port#(NeedleIdx, Bit#(32)) mpNext <- mkBRAM2Server(defaultValue);
   Gearbox#(nc,1,Char) haystack <- mkNto1Gearbox(clk,rst,clk,rst);

   Reg#(Stage) stage <- mkReg(Idle);
   Reg#(Bit#(32)) needleLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackLenReg <- mkReg(0);
   Reg#(Bit#(32)) iReg <- mkReg(0);
   Reg#(Bit#(32)) jReg <- mkReg(0);
   Reg#(DmaPointer) haystackHandle <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) haystackPtr <- mkReg(0);

   DmaReadServer2BRAM#(NeedleIdx) n2b <- mkDmaReadServer2BRAM(needle_read_chan, needle.portB);
   DmaReadServer2BRAM#(NeedleIdx) mp2b <- mkDmaReadServer2BRAM(mp_next_read_chan, mpNext.portB);

   Reg#(Bit#(2)) epochReg <- mkReg(0);
   FIFO#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFO(2);
   Reg#(Bit#(32)) cycle <- mkReg(0);

   rule start (stage == Init);
      let x <- n2b.finished;
      let y <- mp2b.finished;
      stage <= Run;
      iReg <= 1;
      jReg <= 1;
   endrule

   (* descending_urgency = "mp2b_load, n2b_load, matchNeedleResp, matchNeedleReq" *)

   rule haystackReq (stage == Run);
      haystack_read_chan.readReq.put(DmaRequest {handle: haystackHandle, address: haystackPtr, burstLen: 1, tag: 0});
      haystackPtr <= haystackPtr + fromInteger(valueOf(nc));
   endrule

   rule haystackResp;
      let rv <- haystack_read_chan.readData.get;
      Vector#(nc,Char) pv = unpack(rv.data);
      haystack.enq(pv);
   endrule

   rule haystackDrain(stage != Run);
      haystack.deq;
   endrule

   rule matchNeedleReq(stage == Run);
      needle.portA.request.put(BRAMRequest{write:False, address:truncate(iReg-1)});
      mpNext.portA.request.put(BRAMRequest{write:False, address:truncate(iReg)});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= iReg+1;
      //$display("matchNeedleReq %d %d", epochReg, iReg);
   endrule

   rule hb (stage==Run);
      //$display("cycle %h **************************", cycle);
      cycle <= cycle+1;
   endrule

   rule matchNeedleResp(stage == Run);
      let nv <- needle.portA.response.get;
      let mp <- mpNext.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (epoch == epochReg) begin
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (j > n) begin
	    indication.searchResult(-1);
	    stage <= Idle;
	 end
	 else if (i==m+1) begin
	    //$display("string match %d", j);
	    indication.searchResult(unpack(j-i));
	    epochReg <= epochReg+1;
	    iReg <= 1;
	 end
	 else if ((i==m+1) || ((i>0) && (nv != hv[0]))) begin
	    epochReg <= epochReg + 1;
	    iReg <= mp;
	    //$display("char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	 end
	 else begin
	    //$display("   char match %d %d", i, j);
	    jReg <= j+1;
	    haystack.deq;
	 end
      end
   endrule

   method Action search(Bit#(32) needle_handle, Bit#(32) haystack_handle, Bit#(32) mpNext_handle,
			Bit#(32) needle_len, Bit#(32) haystack_len) if (stage == Idle);

      $display("search %h %h", needle_len, haystack_len);
      needleLenReg <= needle_len;
      haystackLenReg <= haystack_len;
      n2b.start(needle_handle, pack(truncate(needle_len)));
      mp2b.start(mpNext_handle, pack(truncate(needle_len)));
      haystackHandle <= haystack_handle;
      stage <= Init;

   endmethod
endmodule