add vars to docall.  This will permit call following the cycle after a return but seems expensive.  Can arguments be optional?  Or should there be two versions of docall?

// 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.

/*
 * Implementation of:
 *    simple stack for a type
 *
 * Single cycle push and pop, provided that consecutive pops aren't
 * too far apart
 */

import BRAM::*;

interface StackReg#(numeric type stackSize, type pctype, type argstype, type varstype);
   method Action doreturn();
   method Action docall(pctype jumpto, pctype returnto, argstype args);
   method Action nextpc(pctype jumpto);
   method Bit#(16) setjmp();
   method Action longjump(Bit#(16) where);
   interface Reg#(pctype) pc;
   interface Reg#(argstype) args;
   interface Reg#(varstype) vars;
endinterface

module mkStackReg#(int stackSize, pctype initialpc)(StackReg#(stackSize, pctype, argstype, varstype))
   provisos(Log#(stackSize, addressBits),
      Bits#(pctype, a__),
      Bits#(argstype, b__),
      Bits#(varstype, c__));

   BRAM1Port#(Bit#(addressBits), pctype) pcstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), argstype) argsstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), varstype) varsstack  <- mkBRAM1Server(defaultValue);
   Reg#(pctype) pctop <- mkReg(initialpc);
   Reg#(pctype) pcnext <- mkReg(?);
   Reg#(argstype) argstop <- mkReg(?);
   Reg#(argstype) argsnext <- mkReg(?);
   Reg#(varstype) varstop <- mkReg(?);
   Reg#(varstype) varsnext <- mkReg(?);
   Reg#(Bit#(addressBits)) fp <- mkReg(0);
   PulseWire calling <- mkPulseWire();
   PulseWire returning <- mkPulseWire();
   Reg#(Bool) returningd1 <- mkReg(False);

/* The "next" registers are there to compensate for the pipelined reads
 * of the BRAMs.
 * A return in isolation pops next to top, and then replaces the contents of
 * next the following cycle when the BRAM read completes.
 * In the event that there are multiple returns in consecutive cycles, the
 * first return values are fed from the next registers into top, and the
 * following values are bypassed from the BRAMs direct to TOP.
 * Once return cycles stop happening, the final pending BRAM read data is
 * loaded into next
 *
 * If a call happens in the cycle after a return, the BRAM read <into> next and
 * the bram write <from> next are both supressed, and next is pushed from top
 *
 * The wire calling says there is a call in the current cycle. The signal
 * returning says there is a return in the current cycle. The signal returningd1
 * says there was a return in the previous cycle.
 */

/*
   Reg#(Bit#(8)) cyc <- mkReg(0);

   rule cc;
      cyc <= cyc + 1;
   endrule
  */

   /* The pop rules fire exactly when returningd1 is true */
   rule poppc;
     let v = ?;
      //$display("%d poppc (c %d)", cyc, calling);
      v <- pcstack.portA.response.get();
      if (!calling) pcnext <= v;
      if (returning) pctop <= v;
   endrule

   rule popargs;
     let v = ?;
      v <- argsstack.portA.response.get();
      if (!calling) argsnext <= v;
      if (returning) argstop <= v;
   endrule

   rule popvars;
     let v = ?;
      v <- varsstack.portA.response.get();
      if (!calling) varsnext <= v;
      if (returning) varstop <= v;
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule returning_delay;
      returningd1 <= returning;
   endrule

   method Action docall(pctype jumpto, pctype returnto, argstype args, varstype vars);
      fp <= min(fp+1, maxBound);
      calling.send();
      //$display("%d docall jumpto %d returnto %d (d1 %d)", cyc, jumpto, returnto, returningd1);
      if (! returningd1)
	 begin
	    pcstack.portA.request.put(BRAMRequest{write: True,
	       responseOnWrite: False,
	       address: fp, datain: pcnext});
	    argsstack.portA.request.put(BRAMRequest{write: True,
	       responseOnWrite: False,
	       address: fp, datain: argsnext});
	    varsstack.portA.request.put(BRAMRequest{write: True,
	       responseOnWrite: False,
	       address: fp, datain: varsnext});
	 end
      pcnext <= returnto;
      pctop <= jumpto;
      argsnext <= argstop;
      argstop <= args;
      varsnext <= varstop;
   endmethod

   method Action doreturn();
      fp <= max(fp-1, 0);
      returning.send();

      pcstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: ?});
      argsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: ?});
      varsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: ?});
      //$display("%d doreturn pctop getting %d", cyc, pcnext);
     if (!returningd1)
	begin
	   pctop <= pcnext;
	   argstop <= argsnext;
	   varstop <= varsnext;
	end
   endmethod

   method Action nextpc(pctype jumpto);
      pctop <= jumpto;
   endmethod

   method Bit#(16) setjmp();
      return 0;
   endmethod

   method Action longjump(Bit#(16) where);
   // set fp <= where and pop? something like that
   endmethod

interface pc = pctop;
interface args = argstop;
interface vars = varstop;

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.

/*
 * Implementation of:
 *    simple stack for a type
 *
 * Single cycle push and pop, provided that consecutive pops aren't
 * too far apart
 */

import BRAM::*;

interface StackReg#(numeric type stackSize, type pctype, type argstype, type varstype);
   method Action doreturn();
   method Action docall(pctype jumpto, pctype returnto, argstype args);
   method Action nextpc(pctype jumpto);
   method Bit#(16) setjmp();
   method Action longjump(Bit#(16) where);
   interface Reg#(pctype) pc;
   interface Reg#(argstype) args;
   interface Reg#(varstype) vars;
endinterface

module mkStackReg#(int stackSize, pctype initialpc)(StackReg#(stackSize, pctype, argstype, varstype))
   provisos(Log#(stackSize, addressBits),
      Bits#(pctype, a__),
      Bits#(argstype, b__),
      Bits#(varstype, c__));

   BRAM1Port#(Bit#(addressBits), pctype) pcstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), argstype) argsstack  <- mkBRAM1Server(defaultValue);
   BRAM1Port#(Bit#(addressBits), varstype) varsstack  <- mkBRAM1Server(defaultValue);
   Reg#(pctype) pctop <- mkReg(initialpc);
   Reg#(pctype) pcnext <- mkReg(?);
   Reg#(argstype) argstop <- mkReg(?);
   Reg#(argstype) argsnext <- mkReg(?);
   Reg#(varstype) varstop <- mkReg(?);
   Reg#(varstype) varsnext <- mkReg(?);
   Reg#(Bit#(addressBits)) fp <- mkReg(0);
   PulseWire calling <- mkPulseWire();
   PulseWire returning <- mkPulseWire();
   Reg#(Bool) returningd1 <- mkReg(False);

/* The "next" registers are there to compensate for the pipelined reads
 * of the BRAMs.
 * A return in isolation pops next to top, and then replaces the contents of
 * next the following cycle when the BRAM read completes.
 * In the event that there are multiple returns in consecutive cycles, the
 * first return values are fed from the next registers into top, and the
 * following values are bypassed from the BRAMs direct to TOP.
 * Once return cycles stop happening, the final pending BRAM read data is
 * loaded into next
 *
 * If a call happens in the cycle after a return, the BRAM read <into> next and
 * the bram write <from> next are both supressed, and next is pushed from top
 *
 * The wire calling says there is a call in the current cycle. The signal
 * returning says there is a return in the current cycle. The signal returningd1
 * says there was a return in the previous cycle.
 */

/*
   Reg#(Bit#(8)) cyc <- mkReg(0);

   rule cc;
      cyc <= cyc + 1;
   endrule
  */

   /* The pop rules fire exactly when returningd1 is true */
   rule poppc;
     let v = ?;
      //$display("%d poppc (c %d)", cyc, calling);
      v <- pcstack.portA.response.get();
      if (!calling) pcnext <= v;
      if (returning) pctop <= v;
   endrule

   rule popargs;
     let v = ?;
      v <- argsstack.portA.response.get();
      if (!calling) argsnext <= v;
      if (returning) argstop <= v;
   endrule

   rule popvars;
     let v = ?;
      v <- varsstack.portA.response.get();
      if (!calling) varsnext <= v;
      if (returning) varstop <= v;
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule returning_delay;
      returningd1 <= returning;
   endrule

   method Action docall(pctype jumpto, pctype returnto, argstype args);
      fp <= min(fp+1, maxBound);
      calling.send();
      //$display("%d docall jumpto %d returnto %d (d1 %d)", cyc, jumpto, returnto, returningd1);
      if (! returningd1)
	 begin
	    pcstack.portA.request.put(BRAMRequest{write: True,
	       responseOnWrite: False,
	       address: fp, datain: pcnext});
	    argsstack.portA.request.put(BRAMRequest{write: True,
	       responseOnWrite: False,
	       address: fp, datain: argsnext});
	    varsstack.portA.request.put(BRAMRequest{write: True,
	       responseOnWrite: False,
	       address: fp, datain: varsnext});
	 end
      pcnext <= returnto;
      pctop <= jumpto;
      argsnext <= argstop;
      argstop <= args;
      varsnext <= varstop;
   endmethod

   method Action doreturn();
      fp <= max(fp-1, 0);
      returning.send();

      pcstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: ?});
      argsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: ?});
      varsstack.portA.request.put(BRAMRequest{write: False,
	 responseOnWrite: False,
	 address: fp-1, datain: ?});
      //$display("%d doreturn pctop getting %d", cyc, pcnext);
     if (!returningd1)
	begin
	   pctop <= pcnext;
	   argstop <= argsnext;
	   varstop <= varsnext;
	end;
   endmethod

   method Action nextpc(pctype jumpto);
      pctop <= jumpto;
   endmethod

   method Bit#(16) setjmp();
      return 0;
   endmethod

   method Action longjump(Bit#(16) where);
   // set fp <= where and pop? something like that
   endmethod

interface pc = pctop;
interface args = argstop;
interface vars = varstop;

endmodule


remove provisos, import SDRTypes

remove provisos, import SDRTypes

// 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 DDS::*;
import Gearbox::*;
import ChannelSelect::*;
import Complex::*;
import SDRTypes::*;
import FPCMult::*;
import FixedPoint::*;
import Pipe::*;
import Vector::*;

/* rfreqDataWrite data is FixedPoint(2,14) */
/* setCoeff data is FixedPoint(2, 23) */
interface ChannelSelectTestRequest;
   method Action rfreqDataWrite(Bit#(32) dataRe, Bit#(32) dataIm);
   method Action setCoeff(Bit#(11) addr, Bit#(32) valueRe, Bit#(32) valueIm);
endinterface

/* rfreqDataWrite data is FixedPoint(2,14) */
interface ChannelSelectTestIndication;
   method Action ifreqData(Bit#(32) dataRe, Bit#(32) dataIm);
endinterface

module mkChannelSelectTestRequest#(ChannelSelectTestIndication indication) (ChannelSelectTestRequest);
   Clock clk <- exposeCurrentClock;
   Reset rst <- exposeCurrentReset;
   Gearbox#(1, 2, Complex#(Signal)) gb <- mk1toNGearbox(clk, rst, clk, rst);
   ChannelSelect cs <- mkChannelSelect(64);

   rule processRF;
      let data = gb.first();
      gb.deq();
      cs.rfreq.enq(data);
   endrule

   rule processIF;
      let data = cs.ifreq.first();
      cs.ifreq.deq();
      indication.ifreqData(zeroExtend(pack(data.rel)), zeroExtend(pack(data.img)));
   endrule

   method Action rfreqDataWrite(Bit#(32) dataRe, Bit#(32) dataIm);
      Signal re = unpack(truncate(dataRe));
      Signal im = unpack(truncate(dataIm));
      Vector#(1, Complex#(Signal)) x = newVector();
      x[0] = Complex{rel: re, img: im};
      gb.enq(x);
   endmethod

   method Action setCoeff(Bit#(11) addr, Bit#(32) valueRe, Bit#(32) valueIm);
    FixedPoint#(2, 23) re = unpack(pack(truncate(valueRe)));
    FixedPoint#(2, 23) im = unpack(pack(truncate(valueIm)));
      cs.setCoeff(addr, Complex{rel: re, img:im});
   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 DDS::*;
import Gearbox::*;
import ChannelSelect::*;
import Complex::*;
import FPCMult::*;
import FixedPoint::*;
import Pipe::*;
import Vector::*;

/* rfreqDataWrite data is FixedPoint(2,14) */
/* setCoeff data is FixedPoint(2, 23) */
interface ChannelSelectTestRequest;
   method Action rfreqDataWrite(Bit#(32) dataRe, Bit#(32) dataIm);
   method Action setCoeff(Bit#(11) addr, Bit#(32) valueRe, Bit#(32) valueIm);
endinterface

/* rfreqDataWrite data is FixedPoint(2,14) */
interface ChannelSelectTestIndication;
   method Action ifreqData(Bit#(32) dataRe, Bit#(32) dataIm);
endinterface

module mkChannelSelectTestRequest#(ChannelSelectTestIndication indication) (ChannelSelectTestRequest)
   provisos(Bits#(CoeffData, a__),
	    Bits#(ProductData, b__),
	    Bits#(MulData, c__));
   Clock clk <- exposeCurrentClock;
   Reset rst <- exposeCurrentReset;
   Gearbox#(1, 2, Complex#(Signal)) gb <- mk1toNGearbox(clk, rst, clk, rst);
   ChannelSelect cs <- mkChannelSelect(64);

   rule processRF;
      let data = gb.first();
      gb.deq();
      cs.rfreq.enq(data);
   endrule

   rule processIF;
      let data = cs.ifreq.first();
      cs.ifreq.deq();
      indication.ifreqData(zeroExtend(pack(data.rel)), zeroExtend(pack(data.img)));
   endrule

   method Action rfreqDataWrite(Bit#(32) dataRe, Bit#(32) dataIm);
      Signal re = unpack(truncate(dataRe));
      Signal im = unpack(truncate(dataIm));
      Vector#(1, Complex#(Signal)) x = newVector();
      x[0] = Complex{rel: re, img: im};
      gb.enq(x);
   endmethod

   method Action setCoeff(Bit#(11) addr, Bit#(32) valueRe, Bit#(32) valueIm);
    FixedPoint#(2, 23) re = unpack(pack(truncate(valueRe)));
    FixedPoint#(2, 23) im = unpack(pack(truncate(valueIm)));
      cs.setCoeff(addr, Complex{rel: re, img:im});
   endmethod
endmodule


do not include Paxos.bsv in RxChannel.bsv

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

import Connectable::*;
import ClientServer::*;
import DbgTypes::*;
import DbgDefs::*;
import Ethernet::*;
import EthMac::*;
import GetPut::*;
import FIFO::*;
import MemMgmt::*;
import MemTypes::*;
import PacketBuffer::*;
import PaxosTypes::*;
import Pipe::*;
import StoreAndForward::*;
import SharedBuff::*;
import Tap::*;
import HostChannel::*;

interface RxChannel;
   interface Put#(PacketDataT#(64)) macRx;
   interface MemWriteClient#(`DataBusWidth) writeClient;
   interface MemAllocClient mallocClient;
   interface Client#(MetadataRequest, MetadataResponse) next;
   method HostChannelDbgRec read_debug_info;
   method ParserPerfRec read_parser_perf_info;
endinterface

module mkRxChannel#(Clock rxClock, Reset rxReset)(RxChannel);
   let verbose = True;
   HostChannel host <- mkHostChannel();
   StoreAndFwdFromMacToRing macToRing <- mkStoreAndFwdFromMacToRing(rxClock, rxReset);
   mkConnection(macToRing.writeClient, host.writeServer);
   interface macRx = macToRing.macRx;
   interface writeClient = host.writeClient;
   interface next = host.next;
   interface mallocClient = host.mallocClient;
   method read_debug_info = host.read_debug_info;
   method read_parser_perf_info = host.read_parser_perf_info;
endmodule

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

import Connectable::*;
import ClientServer::*;
import DbgTypes::*;
import DbgDefs::*;
import Ethernet::*;
import EthMac::*;
import GetPut::*;
import FIFO::*;
import MemMgmt::*;
import MemTypes::*;
import PacketBuffer::*;
import PaxosTypes::*;
import Paxos::*;
import Pipe::*;
import StoreAndForward::*;
import SharedBuff::*;
import Tap::*;
import HostChannel::*;

interface RxChannel;
   interface Put#(PacketDataT#(64)) macRx;
   interface MemWriteClient#(`DataBusWidth) writeClient;
   interface MemAllocClient mallocClient;
   interface Client#(MetadataRequest, MetadataResponse) next;
   method HostChannelDbgRec read_debug_info;
   method ParserPerfRec read_parser_perf_info;
endinterface

module mkRxChannel#(Clock rxClock, Reset rxReset)(RxChannel);
   let verbose = True;
   HostChannel host <- mkHostChannel();
   StoreAndFwdFromMacToRing macToRing <- mkStoreAndFwdFromMacToRing(rxClock, rxReset);
   mkConnection(macToRing.writeClient, host.writeServer);
   interface macRx = macToRing.macRx;
   interface writeClient = host.writeClient;
   interface next = host.next;
   interface mallocClient = host.mallocClient;
   method read_debug_info = host.read_debug_info;
   method read_parser_perf_info = host.read_parser_perf_info;
endmodule


fix name of stmt

fix name of stmt

// 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 StmtFSM::*;
import BRAM::*;

module mkHirschA#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL)(FSM);

    Reg#(Bit#(7)) aLenReg <- mkReg(0);
  Reg#(Bit#(7)) bLenReg <- mkReg(0);
  Reg#(Bit#(14)) rLenReg <- mkReg(0);
  Reg#(Bit#(7)) ii <- mkReg(0);
  Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) lim1jm1 <- mkReg(0);
   Reg#(Bit#(16)) lim1j <- mkReg(0);
   Reg#(Bit#(16)) lijm1 <- mkReg(0);

   Stmt hirschA =
   seq
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,0}, datain: 0});
	    endseq
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {0,ii}, datain: 0});
	 endseq
      for (ii<= 1; ii <= aLenReg; ii <= ii + 1)
	 for (jj<= 1; jj <= bLenReg; jj <= jj + 1)
	    seq
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: ii-1, datain: 0});
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: jj-1, datain: 0});
	       action
		  let ta <- strA.response.get();
		  let tb <- strB.response.get();
		  aData <= ta;
		  bData <= tb;
	       endaction
	       if (aData == bData)
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii-1,jj-1}, datain: 0});
		     action
			let temp <- matL.response.get();
			lim1jm1 <= temp;
		     endaction
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,jj}, datain: lim1jm1+1});

		  endseq
	       else
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii,jj-1}, datain: 0});
		     action
			let tlijm1 <- matL.response.get();
			lijm1 <= tlijm1;
		     endaction
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii-1,jj}, datain: 0});
		     action
			let tlim1j <- matL.response.get();
			lim1j <= tlim1j;
		     endaction
			matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,jj}, datain: max(lijm1,lim1j)});
		  endseq
	    endseq
   endseq;
   mkFSM(hirschA);

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 StmtFSM::*;
import BRAM::*;

module mkHirschA#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL)(FSM);

    Reg#(Bit#(7)) aLenReg <- mkReg(0);
  Reg#(Bit#(7)) bLenReg <- mkReg(0);
  Reg#(Bit#(14)) rLenReg <- mkReg(0);
  Reg#(Bit#(7)) ii <- mkReg(0);
  Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) lim1jm1 <- mkReg(0);
   Reg#(Bit#(16)) lim1j <- mkReg(0);
   Reg#(Bit#(16)) lijm1 <- mkReg(0);

   Stmt hirschA =
   seq
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,0}, datain: 0});
	    endseq
      for (ii<= 0; ii < aLenReg; ii <= ii + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {0,ii}, datain: 0});
	 endseq
      for (ii<= 1; ii <= aLenReg; ii <= ii + 1)
	 for (jj<= 1; jj <= bLenReg; jj <= jj + 1)
	    seq
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: ii-1, datain: 0});
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: jj-1, datain: 0});
	       action
		  let ta <- strA.response.get();
		  let tb <- strB.response.get();
		  aData <= ta;
		  bData <= tb;
	       endaction
	       if (aData == bData)
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii-1,jj-1}, datain: 0});
		     action
			let temp <- matL.response.get();
			lim1jm1 <= temp;
		     endaction
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,jj}, datain: lim1jm1+1});

		  endseq
	       else
		  seq
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii,jj-1}, datain: 0});
		     action
			let tlijm1 <- matL.response.get();
			lijm1 <= tlijm1;
		     endaction
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: {ii-1,jj}, datain: 0});
		     action
			let tlim1j <- matL.response.get();
			lim1j <= tlim1j;
		     endaction
			matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: {ii,jj}, datain: max(lijm1,lim1j)});
		  endseq
	    endseq
   endseq;
   mkFSM(HirschA);

endmodule


added comments descibing original algorithm

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

/*
 * Implementation of:
 *    MP algorithm on pages 7-11 from "Pattern Matching Algorithms" by
 *       Alberto Apostolico, Zvi Galil, 1997
 *
 *    procedure MP(x, t: string; m, n: integer);
 *    begin
 *        i := 1; j := 1;
 *        while j <= n do begin
 *            while (i = m + 1) or (i > 0 and x[i] != t[j]) do j := MP_next[i];
 *            i := i + 1; j := j + 1;
 *            if i = m + 1 then writeln('x occurs in t at position ', j - i + 1);
 *        end;
 *    end;
 *
 *    procedure Compute_borders(x: string; m: integer);
 *    begin
 *        Border[0] := -1;
 *        for i := 1 to m do begin
 *            j := Boarder[i - 1];
 *            while j >= 0 and x[i] != x[j + 1] do j := Boarder[j];
 *            Border[i] := j + 1;
 *        end;
 *    end;
 *
 *    procedure Compute_mp_next(x: string; m: integer);
 *    begin
 *        MP_next[i] := 0; j := 0;
 *        for i := 1 to m do begin
 *            { at this point, we have j = MP_next[i] }
 *            while j > 0 and x[i] != x[j] do j := MP_next[j];
 *            j := j + 1;
 *            MP_next[i + 1] := j;
 *        end;
 *    end;
 *
 */

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

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


pipeline mkMemWriteInternal writeData

pipeline mkMemWriteInternal writeData

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

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

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

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

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

// XBSV Libraries
import MemTypes::*;
import PortalMemory::*;
import SGList::*;

typedef 9 SGL_PIPELINE_DEPTH;
typedef 32 TAG_DEPTH;

interface MemWriteInternal#(numeric type addrWidth, numeric type dataWidth);
   interface DmaDbg dbg;
   interface MemWriteClient#(addrWidth,dataWidth) write_client;
endinterface

interface MemReadInternal#(numeric type addrWidth, numeric type dataWidth);
   interface DmaDbg dbg;
   interface MemReadClient#(addrWidth,dataWidth) read_client;
endinterface

function Bool bad_pointer(ObjectPointer p);
   return ((p >>8) > fromInteger(valueOf(MaxNumSGLists)));
endfunction

typedef struct {ObjectRequest req;
		Bit#(TLog#(numClients)) client; } LRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {ObjectRequest req;
		Bit#(addrWidth) pa;
		Bit#(6) rename_tag;
		Bit#(TLog#(numClients)) client; } RRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {ObjectRequest req;
		Bit#(6) rename_tag;
		Bit#(TLog#(numClients)) client;
		Bool last; } DRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {Bit#(6) orig_tag;
		Bit#(TLog#(numClients)) client; } RResp#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {DmaErrorType errorType;
		Bit#(32) pref; } DmaError deriving (Bits);

module mkMemReadInternal#(Integer id,
			  Vector#(numClients, ObjectReadClient#(dataWidth)) readClients,
			  DmaIndication dmaIndication,
			  Server#(ReqTup,Bit#(addrWidth)) sgl)
   (MemReadInternal#(addrWidth, dataWidth))

   provisos(Add#(b__, addrWidth, 64),
	    Add#(c__, 12, addrWidth),
	    Add#(1, c__, d__),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(a__, TLog#(numClients), 6)
      );

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: read commands (maximum buffering to handle high latency read response times)
   Vector#(numClients, FIFOF#(DRec#(numClients,addrWidth))) dreqFifos <- replicateM(mkSizedBRAMFIFOF(valueOf(TAG_DEPTH)));
   // stage 3: read data (minimal buffering required)
   Vector#(numClients, FIFO#(MemData#(dataWidth))) readDataPipelineFifo <- replicateM(mkFIFO);
   FIFO#(MemData#(dataWidth)) responseFifo <- mkFIFO;
   Vector#(numClients, Reg#(Bit#(8)))           burstRegs <- replicateM(mkReg(0));
   Vector#(numClients, Reg#(Bool))              firstRegs <- replicateM(mkReg(True));
   Vector#(numClients, Reg#(Bool))               lastRegs <- replicateM(mkReg(False));
   Reg#(Bit#(64))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   // performance analytics
   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_sglResp <- mkReg(0);
   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   for (Integer selectReg = 0; selectReg < valueOf(numClients); selectReg = selectReg + 1)
      rule loadClient;
      	 //$display("mkMemReadInternal::loadClient %d %d", selectReg, cycle_cnt-last_loadClient);
	 //last_loadClient <= cycle_cnt;
   	 ObjectRequest req <- readClients[selectReg].readReq.get();
   	 if (bad_pointer(req.pointer))
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer4, pref: req.pointer });
   	 else begin
   	    lreqFifo.enq(LRec{req:req, client:fromInteger(selectReg)});
   	    sgl.request.put(ReqTup{id:truncate(req.pointer),off:req.offset});
   	 end
      endrule

   rule checkSglResp;
      let physAddr <- sgl.response.get;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let rename_tag  = extend(client);
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:rename_tag});
      //$display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      //$display("mkMemReadInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      //last_sglResp <= cycle_cnt;
   endrule

   rule read_response;
      let response <- toGet(responseFifo).get();
      beatCount <= beatCount+1;
      Bit#(6) response_tag = response.tag;
      let dreqFifo = dreqFifos[response_tag];
      dynamicAssert(truncate(response_tag) == dreqFifo.first.rename_tag, "mkMemReadInternal");
      readDataPipelineFifo[response_tag].enq(response);
   endrule

   for (Integer client = 0; client < valueOf(numClients); client = client + 1)
       rule read_client_response;
	  Bit#(6) response_tag = fromInteger(client);
	  let response <- toGet(readDataPipelineFifo[client]).get();

	  let dreqFifo = dreqFifos[response_tag];
	  let drq = dreqFifo.first;
	  let req = drq.req;
	  let burstLen = burstRegs[response_tag];
	  let first =    firstRegs[response_tag];
	  let last  =    lastRegs[response_tag];
	  if (first) begin
	     burstLen = dreqFifo.first.req.burstLen >> beat_shift;
	     last = dreqFifo.first.last;
	     dynamicAssert(last == (burstLen==1), "Last incorrect");
	     //$display("burstLen=%d dreqFifo.first.last=%d last=%d\n", burstLen, dreqFifo.first.last, last);
	  end

	  readClients[client].readData.put(ObjectData { data: response.data, tag: req.tag, last: last});
	  if (last) begin
	     dreqFifo.deq();
	  end
	  burstRegs[response_tag] <= burstLen-1;
	  firstRegs[response_tag] <= (burstLen-1 == 0);
	  lastRegs[response_tag] <= (burstLen-1 == 1);
       endrule

   interface MemReadClient read_client;
      interface Get readReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    reqFifo.deq;
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    if (False && physAddr[31:24] != 0)
	       $display("req_ar: funny physAddr req.pointer=%d req.offset=%h physAddr=%h", req.pointer, req.offset, physAddr);
	    dreqFifos[rename_tag].enq(DRec{req:req, client:client, rename_tag:rename_tag, last:(req.burstLen == fromInteger(valueOf(dataWidthBytes)))});
	    //$display("readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", client,rename_tag,physAddr, req.burstLen, beat_shift, req.burstLen == beat_shift);
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:rename_tag};
	 endmethod
      endinterface
      interface Put readData = toPut(responseFifo);
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 // Bit#(1) ne0 = pack(dreqFifos[0].notEmpty);
	 // Bit#(1) ne1 = pack(dreqFifos[1].notEmpty);
	 // return DmaDbgRec{x:extend(burstRegs[0]), y:extend(burstRegs[1]), z:extend(ne0), w:extend(ne1)};
	 return DmaDbgRec{x:0, y:0, z:0, w:0};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return beatCount;
      endmethod
   endinterface
endmodule

module mkMemWriteInternal#(Integer iid,
			   Vector#(numClients, ObjectWriteClient#(dataWidth)) writeClients,
			   DmaIndication dmaIndication,
			   Server#(ReqTup,Bit#(addrWidth)) sgl)
   (MemWriteInternal#(addrWidth, dataWidth))

   provisos(Add#(b__, addrWidth, 64),
	    Add#(c__, 12, addrWidth),
	    Add#(1, c__, d__),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(a__, TLog#(numClients), 6));

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: write commands (maximum buffering to handle high latency writes)
   FIFO#(DRec#(numClients, addrWidth)) mwDreqFifo <- mkSizedBRAMFIFO(valueOf(TMul#(TAG_DEPTH,numClients)));
   // stage 3: write data (maximum buffering, though I have no idea if any hosts will begin the next data transfer before sending the write ack)
   Vector#(numClients, FIFO#(RResp#(numClients,addrWidth))) respFifos <- replicateM(mkSizedBRAMFIFO(valueOf(TAG_DEPTH)));
   // stage 4: write done (minimal buffering required)
   FIFO#(Tuple2#(RResp#(numClients,addrWidth),Bit#(6))) writeDonePipelineFifo <- mkFIFO;

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

   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_sglResp <- mkReg(0);
   Reg#(Bit#(64)) last_eob <- mkReg(0);
   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   for (Integer selectReg = 0; selectReg < valueOf(numClients); selectReg = selectReg + 1)
       rule loadClient;
      	  //$display("mkMemWriteInternal::loadClient %d %d", selectReg, cycle_cnt-last_loadClient);
	  //last_loadClient <= cycle_cnt;
   	  ObjectRequest req <- writeClients[selectReg].writeReq.get();
   	  if (bad_pointer(req.pointer))
	     dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer5, pref: req.pointer });
   	  else begin
   	     lreqFifo.enq(LRec{req:req, client:fromInteger(selectReg)});
   	     sgl.request.put(ReqTup{id:truncate(req.pointer),off:req.offset});
   	  end
       endrule

   rule checkSglResp;
      let physAddr <- sgl.response.get;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let rename_tag  = client;
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //$display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      //$display("mkMemWriteInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      //last_sglResp <= cycle_cnt;
   endrule

   rule writeDoneComp;
      writeDonePipelineFifo.deq;
      let client = tpl_1(writeDonePipelineFifo.first).client;
      let orig_tag = tpl_1(writeDonePipelineFifo.first).orig_tag;
      let response_tag = tpl_2(writeDonePipelineFifo.first);
      writeClients[client].writeDone.put(orig_tag);
   endrule

   FIFOF#(MemData#(dataWidth)) memDataFifo <- mkFIFOF();
   rule memdata;
      let client = mwDreqFifo.first.client;
      let req = mwDreqFifo.first.req;
      let rename_tag = mwDreqFifo.first.rename_tag;
      ObjectData#(dataWidth) tagdata <- writeClients[client].writeData.get();
      let burstLen = burstReg;
      if (burstLen == 0) begin
	 burstLen = req.burstLen >> beat_shift;
	 respFifos[rename_tag].enq(RResp{orig_tag:req.tag, client:client});
      end
      burstReg <= burstLen-1;
      beatCount <= beatCount+1;
      if (burstLen == 1)
	 mwDreqFifo.deq();
      //$display("writeData: client=%d, rename_tag=%d", client, rename_tag);
      memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: False });
   endrule

   interface MemWriteClient write_client;
      interface Get writeReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    reqFifo.deq;
	    mwDreqFifo.enq(DRec{req:req, client:client, rename_tag:rename_tag, last: False });
	    //$display("writeReq: client=%d, rename_tag=%d", client,rename_tag);
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)};
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(MemData#(dataWidth)) get();
            let d <- toGet(memDataFifo).get();
            return d;
	 endmethod
      endinterface
      interface Put writeDone;
	 method Action put(Bit#(6) resp);
	    let response_tag = resp;
	    let respFifo = respFifos[response_tag];
	    writeDonePipelineFifo.enq(tuple2(respFifo.first,resp));
	    respFifo.deq;
	 endmethod
      endinterface
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:fromInteger(valueOf(numClients)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return beatCount;
      endmethod
   endinterface
endmodule

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

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

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

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

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

// XBSV Libraries
import MemTypes::*;
import PortalMemory::*;
import SGList::*;

typedef 9 SGL_PIPELINE_DEPTH;
typedef 32 TAG_DEPTH;

interface MemWriteInternal#(numeric type addrWidth, numeric type dataWidth);
   interface DmaDbg dbg;
   interface MemWriteClient#(addrWidth,dataWidth) write_client;
endinterface

interface MemReadInternal#(numeric type addrWidth, numeric type dataWidth);
   interface DmaDbg dbg;
   interface MemReadClient#(addrWidth,dataWidth) read_client;
endinterface

function Bool bad_pointer(ObjectPointer p);
   return ((p >>8) > fromInteger(valueOf(MaxNumSGLists)));
endfunction

typedef struct {ObjectRequest req;
		Bit#(TLog#(numClients)) client; } LRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {ObjectRequest req;
		Bit#(addrWidth) pa;
		Bit#(6) rename_tag;
		Bit#(TLog#(numClients)) client; } RRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {ObjectRequest req;
		Bit#(6) rename_tag;
		Bit#(TLog#(numClients)) client;
		Bool last; } DRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {Bit#(6) orig_tag;
		Bit#(TLog#(numClients)) client; } RResp#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {DmaErrorType errorType;
		Bit#(32) pref; } DmaError deriving (Bits);

module mkMemReadInternal#(Integer id,
			  Vector#(numClients, ObjectReadClient#(dataWidth)) readClients,
			  DmaIndication dmaIndication,
			  Server#(ReqTup,Bit#(addrWidth)) sgl)
   (MemReadInternal#(addrWidth, dataWidth))

   provisos(Add#(b__, addrWidth, 64),
	    Add#(c__, 12, addrWidth),
	    Add#(1, c__, d__),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(a__, TLog#(numClients), 6)
      );

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: read commands (maximum buffering to handle high latency read response times)
   Vector#(numClients, FIFOF#(DRec#(numClients,addrWidth))) dreqFifos <- replicateM(mkSizedBRAMFIFOF(valueOf(TAG_DEPTH)));
   // stage 3: read data (minimal buffering required)
   Vector#(numClients, FIFO#(MemData#(dataWidth))) readDataPipelineFifo <- replicateM(mkFIFO);
   FIFO#(MemData#(dataWidth)) responseFifo <- mkFIFO;
   Vector#(numClients, Reg#(Bit#(8)))           burstRegs <- replicateM(mkReg(0));
   Vector#(numClients, Reg#(Bool))              firstRegs <- replicateM(mkReg(True));
   Vector#(numClients, Reg#(Bool))               lastRegs <- replicateM(mkReg(False));
   Reg#(Bit#(64))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   // performance analytics
   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_sglResp <- mkReg(0);
   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   for (Integer selectReg = 0; selectReg < valueOf(numClients); selectReg = selectReg + 1)
      rule loadClient;
      	 //$display("mkMemReadInternal::loadClient %d %d", selectReg, cycle_cnt-last_loadClient);
	 //last_loadClient <= cycle_cnt;
   	 ObjectRequest req <- readClients[selectReg].readReq.get();
   	 if (bad_pointer(req.pointer))
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer4, pref: req.pointer });
   	 else begin
   	    lreqFifo.enq(LRec{req:req, client:fromInteger(selectReg)});
   	    sgl.request.put(ReqTup{id:truncate(req.pointer),off:req.offset});
   	 end
      endrule

   rule checkSglResp;
      let physAddr <- sgl.response.get;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let rename_tag  = extend(client);
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:rename_tag});
      //$display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      //$display("mkMemReadInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      //last_sglResp <= cycle_cnt;
   endrule

   rule read_response;
      let response <- toGet(responseFifo).get();
      beatCount <= beatCount+1;
      Bit#(6) response_tag = response.tag;
      let dreqFifo = dreqFifos[response_tag];
      dynamicAssert(truncate(response_tag) == dreqFifo.first.rename_tag, "mkMemReadInternal");
      readDataPipelineFifo[response_tag].enq(response);
   endrule

   for (Integer client = 0; client < valueOf(numClients); client = client + 1)
       rule read_client_response;
	  Bit#(6) response_tag = fromInteger(client);
	  let response <- toGet(readDataPipelineFifo[client]).get();

	  let dreqFifo = dreqFifos[response_tag];
	  let drq = dreqFifo.first;
	  let req = drq.req;
	  let burstLen = burstRegs[response_tag];
	  let first =    firstRegs[response_tag];
	  let last  =    lastRegs[response_tag];
	  if (first) begin
	     burstLen = dreqFifo.first.req.burstLen >> beat_shift;
	     last = dreqFifo.first.last;
	     dynamicAssert(last == (burstLen==1), "Last incorrect");
	     //$display("burstLen=%d dreqFifo.first.last=%d last=%d\n", burstLen, dreqFifo.first.last, last);
	  end

	  readClients[client].readData.put(ObjectData { data: response.data, tag: req.tag, last: last});
	  if (last) begin
	     dreqFifo.deq();
	  end
	  burstRegs[response_tag] <= burstLen-1;
	  firstRegs[response_tag] <= (burstLen-1 == 0);
	  lastRegs[response_tag] <= (burstLen-1 == 1);
       endrule

   interface MemReadClient read_client;
      interface Get readReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    reqFifo.deq;
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    if (False && physAddr[31:24] != 0)
	       $display("req_ar: funny physAddr req.pointer=%d req.offset=%h physAddr=%h", req.pointer, req.offset, physAddr);
	    dreqFifos[rename_tag].enq(DRec{req:req, client:client, rename_tag:rename_tag, last:(req.burstLen == fromInteger(valueOf(dataWidthBytes)))});
	    //$display("readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", client,rename_tag,physAddr, req.burstLen, beat_shift, req.burstLen == beat_shift);
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:rename_tag};
	 endmethod
      endinterface
      interface Put readData = toPut(responseFifo);
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 // Bit#(1) ne0 = pack(dreqFifos[0].notEmpty);
	 // Bit#(1) ne1 = pack(dreqFifos[1].notEmpty);
	 // return DmaDbgRec{x:extend(burstRegs[0]), y:extend(burstRegs[1]), z:extend(ne0), w:extend(ne1)};
	 return DmaDbgRec{x:0, y:0, z:0, w:0};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return beatCount;
      endmethod
   endinterface
endmodule

module mkMemWriteInternal#(Integer iid,
			   Vector#(numClients, ObjectWriteClient#(dataWidth)) writeClients,
			   DmaIndication dmaIndication,
			   Server#(ReqTup,Bit#(addrWidth)) sgl)
   (MemWriteInternal#(addrWidth, dataWidth))

   provisos(Add#(b__, addrWidth, 64),
	    Add#(c__, 12, addrWidth),
	    Add#(1, c__, d__),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(a__, TLog#(numClients), 6));

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: write commands (maximum buffering to handle high latency writes)
   FIFO#(DRec#(numClients, addrWidth)) dreqFifo <- mkSizedBRAMFIFO(valueOf(TMul#(TAG_DEPTH,numClients)));
   // stage 3: write data (maximum buffering, though I have no idea if any hosts will begin the next data transfer before sending the write ack)
   Vector#(numClients, FIFO#(RResp#(numClients,addrWidth))) respFifos <- replicateM(mkSizedBRAMFIFO(valueOf(TAG_DEPTH)));
   // stage 4: write done (minimal buffering required)
   FIFO#(Tuple2#(RResp#(numClients,addrWidth),Bit#(6))) writeDonePipelineFifo <- mkFIFO;

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

   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_sglResp <- mkReg(0);
   Reg#(Bit#(64)) last_eob <- mkReg(0);
   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

   for (Integer selectReg = 0; selectReg < valueOf(numClients); selectReg = selectReg + 1)
       rule loadClient;
      	  //$display("mkMemWriteInternal::loadClient %d %d", selectReg, cycle_cnt-last_loadClient);
	  //last_loadClient <= cycle_cnt;
   	  ObjectRequest req <- writeClients[selectReg].writeReq.get();
   	  if (bad_pointer(req.pointer))
	     dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadPointer5, pref: req.pointer });
   	  else begin
   	     lreqFifo.enq(LRec{req:req, client:fromInteger(selectReg)});
   	     sgl.request.put(ReqTup{id:truncate(req.pointer),off:req.offset});
   	  end
       endrule

   rule checkSglResp;
      let physAddr <- sgl.response.get;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let rename_tag  = client;
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //$display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      //$display("mkMemWriteInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      //last_sglResp <= cycle_cnt;
   endrule

   rule writeDoneComp;
      writeDonePipelineFifo.deq;
      let client = tpl_1(writeDonePipelineFifo.first).client;
      let orig_tag = tpl_1(writeDonePipelineFifo.first).orig_tag;
      let response_tag = tpl_2(writeDonePipelineFifo.first);
      writeClients[client].writeDone.put(orig_tag);
   endrule

   interface MemWriteClient write_client;
      interface Get writeReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    reqFifo.deq;
	    dreqFifo.enq(DRec{req:req, client:client, rename_tag:rename_tag, last: False });
	    //$display("writeReq: client=%d, rename_tag=%d", client,rename_tag);
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)};
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let client = dreqFifo.first.client;
	    let req = dreqFifo.first.req;
	    let rename_tag =dreqFifo.first.rename_tag;
	    ObjectData#(dataWidth) tagdata <- writeClients[client].writeData.get();
	    let burstLen = burstReg;
	    if (burstLen == 0) begin
	       burstLen = req.burstLen >> beat_shift;
	       respFifos[rename_tag].enq(RResp{orig_tag:req.tag, client:client});
	    end
	    burstReg <= burstLen-1;
	    beatCount <= beatCount+1;
	    if (burstLen == 1)
	       dreqFifo.deq();
	    //$display("writeData: client=%d, rename_tag=%d", client, rename_tag);
	    return MemData { data: tagdata.data,  tag:extend(rename_tag), last: False };
	 endmethod
      endinterface
      interface Put writeDone;
	 method Action put(Bit#(6) resp);
	    let response_tag = resp;
	    let respFifo = respFifos[response_tag];
	    writeDonePipelineFifo.enq(tuple2(respFifo.first,resp));
	    respFifo.deq;
	 endmethod
      endinterface
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:fromInteger(valueOf(numClients)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return beatCount;
      endmethod
   endinterface
endmodule


cannot put to write_server.writeReq and write_server.writeData in the same cycle, due to mux?

import BuildVector::*;
import Connectable::*;
import GetPut::*;
import FIFOF::*;
import BRAM::*;
import Probe::*;
import StmtFSM::*;
import TriState::*;
import Vector::*;

import ConnectalXilinxCells::*;
import ConnectalConfig::*;
import CtrlMux::*;
import HostInterface::*;
import MemTypes::*;
import AxiBits::*;

import AxiEthBvi::*;
import AxiDmaBvi::*;
import EthPins::*;

interface AxiEthTestRequest;
   method Action reset();
   method Action read(Bit#(32) addr);
   method Action write(Bit#(32) addr, Bit#(32) value);
endinterface

interface AxiEthTestIndication;
   method Action readDone(Bit#(32) value);
   method Action writeDone();
   method Action resetDone();
endinterface

interface AxiEth;
   interface AxiEthTestRequest request;
   interface Vector#(2, MemReadClient#(DataBusWidth)) dmaReadClient;
   interface Vector#(2, MemWriteClient#(DataBusWidth)) dmaWriteClient;
   interface AxiEthPins pins;
endinterface

module mkAxiEth#(HostInterface host, AxiEthTestIndication ind)(AxiEth);

   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();

   let axiDmaBvi <- mkAxiDmaBvi(clock,clock,clock,clock,reset);
   let axiEthBvi <- mkAxiEthBvi(host.tsys_clk_200mhz_buf,
				clock, reset, clock,
				reset, reset, reset, reset);

   FIFOF#(BRAMRequest#(Bit#(32),Bit#(32))) reqFifo <- mkFIFOF();
   FIFOF#(Bit#(32))                       dataFifo <- mkFIFOF();
   // packet data and status from the ethernet
   mkConnection(axiEthBvi.m_axis_rxd, axiDmaBvi.s_axis_s2mm);
   mkConnection(axiEthBvi.m_axis_rxs, axiDmaBvi.s_axis_s2mm_sts);

   // packet data and control to the ethernet
   mkConnection(axiDmaBvi.m_axis_mm2s,       axiEthBvi.s_axis_txd);
   mkConnection(axiDmaBvi.m_axis_mm2s_cntrl, axiEthBvi.s_axis_txc);

   Axi4MasterBits#(32,32,MemTagSize,Empty) m_axi_mm2s = toAxi4MasterBits(axiDmaBvi.m_axi_mm2s);
   Axi4MasterBits#(32,32,MemTagSize,Empty) m_axi_s2mm = toAxi4MasterBits(axiDmaBvi.m_axi_s2mm);
   Axi4MasterBits#(32,32,MemTagSize,Empty) m_axi_sg = toAxi4MasterBits(axiDmaBvi.m_axi_sg);

   PhysMemSlave#(18,32) axiDmaMemSlave <- mkPhysMemSlave(axiDmaBvi.s_axi_lite);
   Axi4SlaveLiteBits#(18,32) axiEthSlaveLite = toAxi4SlaveBits(axiEthBvi.s_axi);
   PhysMemSlave#(18,32) axiEthMemSlave <- mkPhysMemSlave(axiEthSlaveLite);
   PhysMemSlave#(19,32) memSlaveMux    <- mkPhysMemSlaveMux(vec(axiDmaMemSlave, axiEthMemSlave));

   FIFOF#(Bit#(32)) dfifo <- mkFIFOF();

   rule rl_axieth;
      axiEthBvi.signal.detect(1); // drive to 1 if not using optical transceiver, else use signal from transceiver
   endrule

   rule rl_rdata;
      let rdata <- memSlaveMux.read_server.readData.get();
      ind.readDone(rdata.data);
   endrule

   rule rl_wdata;
      let wdata <- toGet(dfifo).get();
       memSlaveMux.write_server.writeData.put(MemData {data: wdata, tag: 0});
   endrule

   rule rl_writeDone;
      let tag <- memSlaveMux.write_server.writeDone.get();
      ind.writeDone();
   endrule

   interface AxiEthTestRequest request;
      method Action reset();
      endmethod
      method Action read(Bit#(32) addr);
	 memSlaveMux.read_server.readReq.put(PhysMemRequest { addr: truncate(addr), burstLen: 4, tag: 0 });
      endmethod
      method Action write(Bit#(32) addr, Bit#(32) value);
	 memSlaveMux.write_server.writeReq.put(PhysMemRequest { addr: truncate(addr), burstLen: 4, tag: 0 });
	 dfifo.enq(value);
      endmethod
   endinterface
   interface AxiEthPins pins;
      interface EthPins eth;
	 interface AxiethbviMgt mgt   = axiEthBvi.mgt;
	 interface AxiethbviMdio sfp = axiEthBvi.sfp;
	 interface Clock deleteme_unused_clock = clock;
	 interface Reset deleteme_unused_reset = reset;
      endinterface
   endinterface
   interface Vector dmaReadClient = map(toMemReadClient, vec(m_axi_mm2s, m_axi_sg));
   //interface Vector dmaWriteClient = map(toMemWriteClient, vec(m_axi_s2mm, m_axi_sg));
endmodule

import BuildVector::*;
import Connectable::*;
import GetPut::*;
import FIFOF::*;
import BRAM::*;
import Probe::*;
import StmtFSM::*;
import TriState::*;
import Vector::*;

import ConnectalXilinxCells::*;
import ConnectalConfig::*;
import CtrlMux::*;
import HostInterface::*;
import MemTypes::*;
import AxiBits::*;

import AxiEthBvi::*;
import AxiDmaBvi::*;
import EthPins::*;

interface AxiEthTestRequest;
   method Action reset();
   method Action read(Bit#(32) addr);
   method Action write(Bit#(32) addr, Bit#(32) value);
endinterface

interface AxiEthTestIndication;
   method Action readDone(Bit#(32) value);
   method Action writeDone();
   method Action resetDone();
endinterface

interface AxiEth;
   interface AxiEthTestRequest request;
   interface Vector#(2, MemReadClient#(DataBusWidth)) dmaReadClient;
   interface Vector#(2, MemWriteClient#(DataBusWidth)) dmaWriteClient;
   interface AxiEthPins pins;
endinterface

module mkAxiEth#(HostInterface host, AxiEthTestIndication ind)(AxiEth);

   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();

   let axiDmaBvi <- mkAxiDmaBvi(clock,clock,clock,clock,reset);
   let axiEthBvi <- mkAxiEthBvi(host.tsys_clk_200mhz_buf,
				clock, reset, clock,
				reset, reset, reset, reset);

   FIFOF#(BRAMRequest#(Bit#(32),Bit#(32))) reqFifo <- mkFIFOF();
   FIFOF#(Bit#(32))                       dataFifo <- mkFIFOF();
   // packet data and status from the ethernet
   mkConnection(axiEthBvi.m_axis_rxd, axiDmaBvi.s_axis_s2mm);
   mkConnection(axiEthBvi.m_axis_rxs, axiDmaBvi.s_axis_s2mm_sts);

   // packet data and control to the ethernet
   mkConnection(axiDmaBvi.m_axis_mm2s,       axiEthBvi.s_axis_txd);
   mkConnection(axiDmaBvi.m_axis_mm2s_cntrl, axiEthBvi.s_axis_txc);

   Axi4MasterBits#(32,32,MemTagSize,Empty) m_axi_mm2s = toAxi4MasterBits(axiDmaBvi.m_axi_mm2s);
   Axi4MasterBits#(32,32,MemTagSize,Empty) m_axi_s2mm = toAxi4MasterBits(axiDmaBvi.m_axi_s2mm);
   Axi4MasterBits#(32,32,MemTagSize,Empty) m_axi_sg = toAxi4MasterBits(axiDmaBvi.m_axi_sg);

   PhysMemSlave#(18,32) axiDmaMemSlave <- mkPhysMemSlave(axiDmaBvi.s_axi_lite);
   Axi4SlaveLiteBits#(18,32) axiEthSlaveLite = toAxi4SlaveBits(axiEthBvi.s_axi);
   PhysMemSlave#(18,32) axiEthMemSlave <- mkPhysMemSlave(axiEthSlaveLite);
   PhysMemSlave#(19,32) memSlaveMux    <- mkPhysMemSlaveMux(vec(axiDmaMemSlave, axiEthMemSlave));

   rule rl_axieth;
      axiEthBvi.signal.detect(1); // drive to 1 if not using optical transceiver, else use signal from transceiver
   endrule

   rule rl_rdata;
      let rdata <- memSlaveMux.read_server.readData.get();
      ind.readDone(rdata.data);
   endrule

   rule rl_writeDone;
      let tag <- memSlaveMux.write_server.writeDone.get();
      ind.writeDone();
   endrule

   interface AxiEthTestRequest request;
      method Action reset();
      endmethod
      method Action read(Bit#(32) addr);
	 memSlaveMux.read_server.readReq.put(PhysMemRequest { addr: truncate(addr), burstLen: 4, tag: 0 });
      endmethod
      method Action write(Bit#(32) addr, Bit#(32) value);
	 memSlaveMux.write_server.writeReq.put(PhysMemRequest { addr: truncate(addr), burstLen: 4, tag: 0 });
	 memSlaveMux.write_server.writeData.put(MemData {data: value, tag: 0});
      endmethod
   endinterface
   interface AxiEthPins pins;
      interface EthPins eth;
	 interface AxiethbviMgt mgt   = axiEthBvi.mgt;
	 interface AxiethbviMdio sfp = axiEthBvi.sfp;
	 interface Clock deleteme_unused_clock = clock;
	 interface Reset deleteme_unused_reset = reset;
      endinterface
   endinterface
   interface Vector dmaReadClient = map(toMemReadClient, vec(m_axi_mm2s, m_axi_sg));
   //interface Vector dmaWriteClient = map(toMemWriteClient, vec(m_axi_s2mm, m_axi_sg));
endmodule


fixed copy-paste error

fixed copy-paste error

Change-Id: Id9afcda1d123bc4c8616331cfd9daa378e81fa06

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

import Pipe::*;
import PortalMemory::*;
import MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;

interface MemlatencyRequest;
   method Action start(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) burstLen);
endinterface

interface MemlatencyIndication;
   method Action started;
   method Action readDone;
   method Action writeDone;
   method Action readLatency(Bit#(32) l);
   method Action writeLatency(Bit#(32) l);
endinterface

interface Memlatency;
   interface MemlatencyRequest request;
   interface ObjectReadClient#(64) dmaReadClient;
   interface ObjectWriteClient#(64) dmaWriteClient;
endinterface

module mkMemlatency#(MemlatencyIndication indication)(Memlatency);

   MemreadEngine#(64,1)  re <- mkMemreadEngine;
   MemwriteEngine#(64,1) we <- mkMemwriteEngine;

   Reg#(Bit#(32))        rdIterCnt <- mkReg(0);
   Reg#(Bit#(32))        wrIterCnt <- mkReg(0);
   Reg#(ObjectPointer)   rdPointer <- mkReg(0);
   Reg#(ObjectPointer)   wrPointer <- mkReg(0);
   Reg#(Bit#(32))         burstLen <- mkReg(0);

   Reg#(Bit#(32))           cycles <- mkReg(0);
   FIFO#(Bit#(32))     rdStartFifo <- mkSizedBRAMFIFO(16);
   FIFO#(Bit#(32))     wrStartFifo <- mkSizedBRAMFIFO(16);
   FIFO#(Bit#(32))       rdLatFifo <- mkSizedBRAMFIFO(16);
   FIFO#(Bit#(32))       wrLatFifo <- mkSizedBRAMFIFO(16);

   rule cycle;
      cycles <= cycles+1;
   endrule

   rule startRead(rdIterCnt > 0);
      re.readServers[0].request.put(MemengineCmd{pointer:rdPointer, base:0, len:burstLen*4, burstLen:truncate(burstLen*4)});
      rdIterCnt <= rdIterCnt-1;
      rdStartFifo.enq(cycles);
   endrule

   rule finishRead;
      let rv0 <- re.readServers[0].response.get;
      let rdStart <- toGet(rdStartFifo).get();
      rdLatFifo.enq(cycles-rdStart);
   endrule

   rule readConsume;
      re.dataPipes[0].deq;
   endrule

   rule startWrite(wrIterCnt > 0);
      we.writeServers[0].request.put(MemengineCmd{pointer:wrPointer, base:0, len:burstLen*4, burstLen:truncate(burstLen*4)});
      wrIterCnt <= wrIterCnt-1;
      wrStartFifo.enq(cycles);
   endrule

   rule finishWrite;
      let rv0 <- we.writeServers[0].response.get;
      let wrStart <- toGet(wrStartFifo).get();
      wrLatFifo.enq(cycles-wrStart);
   endrule

   rule writeProduce;
      we.dataPipes[0].enq(1);
   endrule

   rule report;
      let wl <- toGet(wrLatFifo).get;
      let rl <- toGet(rdLatFifo).get;
      indication.readLatency(rl);
      indication.writeLatency(wl);
      if(wrIterCnt==0)
	 indication.writeDone;
      if(rdIterCnt==0)
	 indication.readDone;
   endrule

   interface MemlatencyRequest request;
   method Action start(Bit#(32) wp, Bit#(32) rp, Bit#(32) bl) if (rdIterCnt == 0 && wrIterCnt == 0);
      $display("start wrPointer=%d rdPointer=%d burstLen=%d", wp, rp, bl);
      indication.started;
      // initialized
      wrPointer <= wp;
      rdPointer <= rp;
      rdIterCnt <= 16;
      wrIterCnt <= 16;
      burstLen  <= bl;
   endmethod
   endinterface
   interface ObjectReadClient dmaReadClient = re.dmaClient;
   interface ObjectWriteClient dmaWriteClient = we.dmaClient;

endmodule

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

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

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

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

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

import Pipe::*;
import PortalMemory::*;
import MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;

interface MemlatencyRequest;
   method Action start(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) burstLen);
endinterface

interface MemlatencyIndication;
   method Action started;
   method Action readDone;
   method Action writeDone;
   method Action readLatency(Bit#(32) l);
   method Action writeLatency(Bit#(32) l);
endinterface

interface Memlatency;
   interface MemlatencyRequest request;
   interface ObjectReadClient#(64) dmaReadClient;
   interface ObjectWriteClient#(64) dmaWriteClient;
endinterface

module mkMemlatency#(MemlatencyIndication indication)(Memlatency);

   MemreadEngine#(64,1)  re <- mkMemreadEngine;
   MemwriteEngine#(64,1) we <- mkMemwriteEngine;

   Reg#(Bit#(32))        rdIterCnt <- mkReg(0);
   Reg#(Bit#(32))        wrIterCnt <- mkReg(0);
   Reg#(ObjectPointer)   rdPointer <- mkReg(0);
   Reg#(ObjectPointer)   wrPointer <- mkReg(0);
   Reg#(Bit#(32))         burstLen <- mkReg(0);

   Reg#(Bit#(32))           cycles <- mkReg(0);
   FIFO#(Bit#(32))     rdStartFifo <- mkSizedBRAMFIFO(16);
   FIFO#(Bit#(32))     wrStartFifo <- mkSizedBRAMFIFO(16);
   FIFO#(Bit#(32))       rdLatFifo <- mkSizedBRAMFIFO(16);
   FIFO#(Bit#(32))       wrLatFifo <- mkSizedBRAMFIFO(16);

   rule cycle;
      cycles <= cycles+1;
   endrule

   rule startRead(rdIterCnt > 0);
      re.readServers[0].request.put(MemengineCmd{pointer:rdPointer, base:0, len:burstLen*4, burstLen:truncate(burstLen*4)});
      rdIterCnt <= rdIterCnt-1;
      wrStartFifo.enq(cycles);
   endrule

   rule finishRead;
      let rv0 <- re.readServers[0].response.get;
      let rdStart <- toGet(rdStartFifo).get();
      rdLatFifo.enq(cycles-rdStart);
   endrule

   rule readConsume;
      re.dataPipes[0].deq;
   endrule

   rule startWrite(wrIterCnt > 0);
      we.writeServers[0].request.put(MemengineCmd{pointer:wrPointer, base:0, len:burstLen*4, burstLen:truncate(burstLen*4)});
      wrIterCnt <= wrIterCnt-1;
      wrStartFifo.enq(cycles);
   endrule

   rule finishWrite;
      let rv0 <- we.writeServers[0].response.get;
      let wrStart <- toGet(wrStartFifo).get();
      wrLatFifo.enq(cycles-wrStart);
   endrule

   rule writeProduce;
      we.dataPipes[0].enq(1);
   endrule

   rule report;
      let wl <- toGet(wrLatFifo).get;
      let rl <- toGet(rdLatFifo).get;
      indication.readLatency(rl);
      indication.writeLatency(wl);
      if(wrIterCnt==0)
	 indication.writeDone;
      if(rdIterCnt==0)
	 indication.readDone;
   endrule

   interface MemlatencyRequest request;
   method Action start(Bit#(32) wp, Bit#(32) rp, Bit#(32) bl) if (rdIterCnt == 0 && wrIterCnt == 0);
      $display("start wrPointer=%d rdPointer=%d burstLen=%d", wp, rp, bl);
      indication.started;
      // initialized
      wrPointer <= wp;
      rdPointer <= rp;
      rdIterCnt <= 16;
      wrIterCnt <= 16;
      burstLen  <= bl;
   endmethod
   endinterface
   interface ObjectReadClient dmaReadClient = re.dmaClient;
   interface ObjectWriteClient dmaWriteClient = we.dmaClient;

endmodule


various register sizes

various register sizes

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

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

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

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

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

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

module mkSerialconfigRequest#(SerialconfigIndication indication)(SerialconfigRequest);

   SpiReg#(Bit#(32)) tap1 <- mkSpiReg('h11110000);
   SpiReg#(Bit#(24)) tap2 <- mkSpiReg('h22220000);
   SpiReg#(Bit#(16)) tap3 <- mkSpiReg('h33330000);
   SpiReg#(Bit#(8)) tap4 <- mkSpiReg('h44440000);

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

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

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

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

endmodule

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

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

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

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

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

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

module mkSerialconfigRequest#(SerialconfigIndication indication)(SerialconfigRequest);

   SpiReg#(Bit#(32)) tap1 <- mkSpiReg('h11110000);
   SpiReg#(Bit#(32)) tap2 <- mkSpiReg('h22220000);
   SpiReg#(Bit#(32)) tap3 <- mkSpiReg('h33330000);
   SpiReg#(Bit#(32)) tap4 <- mkSpiReg('h44440000);

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

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

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

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

endmodule