another mkProbe pair

another mkProbe pair

// Copyright (c) 2013,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 GetPut :: *;
import Connectable :: *;
import ClientServer :: *;
import Clocks :: *;
import MemTypes :: *;
import FIFOF :: *;
import ConnectalBramFifo::*;
import Pipe :: *;
import Probe::*;
import SyncAxisFifo32x8::*;
import AxiStream :: *;
`include "ConnectalProjectConfig.bsv"

////////////////////////////////////////////////////////////////////////////////
/// Typeclass Definition
////////////////////////////////////////////////////////////////////////////////
typeclass ConnectableWithClocks#(type a, type b);
   module mkConnectionWithClocks2#(a x1, b x2)(Empty);
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, a x1, b x2)(Empty);
endtypeclass

instance ConnectableWithClocks#(Get#(a), Put#(a)) provisos (
							    Bits#(a, awidth),
							    Add#(1, a__, awidth),
    Add#(b__, awidth, TMul#(TDiv#(awidth, 32), 32)),
    Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
    Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8))
   );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, Get#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
`ifndef GET_PUT_WITH_CLOCKS_USE_XILINX_FIFO
      SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(8, inClock, inReset, outClock);
      //FIFOF#(a) synchronizer <- mkDualClockBramFIFOF(inClock, inReset, outClock, outReset);
      let getProbe <= mkProbe();
      let putProbe <= mkProbe();
       rule mcwc_doGet;
           let v <- in.get();
	   getProbe <= v;
	   synchronizer.enq(v);
       endrule
       rule mcwc_doPut;
	  let v = synchronizer.first;
	  putProbe <= v;
	  synchronizer.deq;
	  out.put(v);
       endrule
`else
      SyncAxisFifo8#(awidth) fifo <- mkSyncAxisFifo8(inClock, inReset, outClock, outReset);
      mkConnection(in, fifo.s_axis, clocked_by inClock, reset_by inReset);
      mkConnection(fifo.m_axis, out, clocked_by outClock, reset_by outReset);
`endif
   endmodule

   module mkConnectionWithClocks2#(Get#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
      Clock inClock = clockOf(in);
      Reset inReset = resetOf(in);
      Clock outClock = clockOf(out);
      Reset outReset = resetOf(out);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, in, out);
   endmodule: mkConnectionWithClocks2
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(PipeOut#(a), Put#(a)) provisos (
							    Bits#(a, awidth),
							    Add#(1, a__, awidth),
    Add#(b__, awidth, TMul#(TDiv#(awidth, 32), 32)),
    Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
    Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8))
   );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, PipeOut#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
`ifndef GET_PUT_WITH_CLOCKS_USE_XILINX_FIFO
      SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(8, inClock, inReset, outClock);
      //FIFOF#(a) synchronizer <- mkDualClockBramFIFOF(inClock, inReset, outClock, outReset);
      let deqProbe <- mkProbe();
      let enqProbe <- mkProbe();
       rule mcwc_doGet;
          let v = in.first;
	  in.deq();
	  deqProbe <= v;
	   synchronizer.enq(v);
       endrule
       rule mcwc_doPut;
	  let v = synchronizer.first;
	  enqProbe <= v;
	  synchronizer.deq;
	  out.put(v);
       endrule
`else
      SyncAxisFifo8#(awidth) fifo <- mkSyncAxisFifo8(inClock, inReset, outClock, outReset);
      mkConnection(in, fifo.s_axis, clocked_by inClock, reset_by inReset);
      mkConnection(fifo.m_axis, out, clocked_by outClock, reset_by outReset);
`endif
   endmodule

   module mkConnectionWithClocks2#(PipeOut#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
      Clock inClock = clockOf(in);
      Reset inReset = resetOf(in);
      Clock outClock = clockOf(out);
      Reset outReset = resetOf(out);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, in, out);
   endmodule: mkConnectionWithClocks2
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(Get#(a), PipeIn#(a)) provisos (
							    Bits#(a, awidth),
							    Add#(1, a__, awidth),
    Add#(b__, awidth, TMul#(TDiv#(awidth, 32), 32)),
    Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
    Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8))
   );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, Get#(a) in, PipeIn#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
`ifndef GET_PUT_WITH_CLOCKS_USE_XILINX_FIFO
      SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(8, inClock, inReset, outClock);
      //FIFOF#(a) synchronizer <- mkDualClockBramFIFOF(inClock, inReset, outClock, outReset);
       rule mcwc_doGet;
           let v <- in.get();
	   synchronizer.enq(v);
       endrule
       rule mcwc_doEnq;
	  let v = synchronizer.first;
	  synchronizer.deq;
	  out.enq(v);
       endrule
`else
      SyncAxisFifo8#(awidth) fifo <- mkSyncAxisFifo8(inClock, inReset, outClock, outReset);
      mkConnection(in, fifo.s_axis, clocked_by inClock, reset_by inReset);
      mkConnection(fifo.m_axis, out, clocked_by outClock, reset_by outReset);
`endif
   endmodule

   module mkConnectionWithClocks2#(Get#(a) in, PipeIn#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
      Clock inClock = clockOf(in);
      Reset inReset = resetOf(in);
      Clock outClock = clockOf(out);
      Reset outReset = resetOf(out);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, in, out);
   endmodule: mkConnectionWithClocks2
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(Client#(a,b), Server#(a,b))
   provisos (Bits#(a, awidth),
      Bits#(b, bwidth),
      Add#(1, a__, awidth),
      Add#(1, b__, bwidth),

      Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
      Add#(d__, TDiv#(bwidth, 8), TDiv#(TMul#(TDiv#(bwidth, 32), 32), 8)),
      Add#(e__, awidth, TMul#(TDiv#(awidth, 32), 32)),
      Add#(f__, bwidth, TMul#(TDiv#(bwidth, 32), 32)),
      Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
      Mul#(TDiv#(bwidth, 32), 4, TDiv#(TMul#(TDiv#(bwidth, 32), 32), 8))
      );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, Client#(a,b) client, Server#(a,b) server)(Empty)
      provisos (ConnectableWithClocks#(Get#(a), Put#(a)),
		ConnectableWithClocks#(Get#(b), Put#(b)),
		Bits#(a, awidth),
		Bits#(b, bwidth));
      let reqCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.request, server.request);
      let respCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, server.response, client.response);
   endmodule
   module mkConnectionWithClocks2#(Client#(a,b) client, Server#(a,b) server)(Empty)
      provisos (ConnectableWithClocks#(Get#(a), Put#(a)),
		ConnectableWithClocks#(Get#(b), Put#(b)),
		Bits#(a, awidth),
		Bits#(b, bwidth));
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

instance ConnectableWithClocks#(PhysMemReadClient#(addrWidth, dataWidth),
				PhysMemReadServer#(addrWidth, dataWidth))
   provisos (
      ConnectableWithClocks#(Get#(PhysMemRequest#(addrWidth,dataWidth)),Put#(PhysMemRequest#(addrWidth,dataWidth))),
      ConnectableWithClocks#(Get#(MemData#(dataWidth)),Put#(MemData#(dataWidth)))
      );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset,
				   PhysMemReadClient#(addrWidth, dataWidth) client,
				   PhysMemReadServer#(addrWidth, dataWidth) server)(Empty);
      let reqCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.readReq, server.readReq);
      let dataCnx <- mkConnectionWithClocks(outClock, outReset, inClock, inReset, server.readData, client.readData);
   endmodule
   module mkConnectionWithClocks2#(PhysMemReadClient#(addrWidth, dataWidth) client,
				  PhysMemReadServer#(addrWidth, dataWidth) server)(Empty);
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);
      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

instance ConnectableWithClocks#(PhysMemWriteClient#(addrWidth, dataWidth),
				PhysMemWriteServer#(addrWidth, dataWidth))
   provisos (
    ConnectableWithClocks#(Get#(PhysMemRequest#(addrWidth, dataWidth)), Put#(PhysMemRequest#(addrWidth, dataWidth))),
    ConnectableWithClocks#(Get#(MemData#(dataWidth)),Put#(MemData#(dataWidth)))
      );

   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset,
				   PhysMemWriteClient#(addrWidth, dataWidth) client,
				   PhysMemWriteServer#(addrWidth, dataWidth) server)(Empty);
      let reqCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.writeReq, server.writeReq);
      let dataCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.writeData, server.writeData);
      let doneCnx <- mkConnectionWithClocks(outClock, outReset, inClock, inReset, server.writeDone, client.writeDone);
   endmodule
   module mkConnectionWithClocks2#(PhysMemWriteClient#(addrWidth, dataWidth) client,
				  PhysMemWriteServer#(addrWidth, dataWidth) server)(Empty);
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);
      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

instance ConnectableWithClocks#(PhysMemMaster#(addrWidth, dataWidth), PhysMemSlave#(addrWidth, dataWidth))
   provisos (
    ConnectableWithClocks#(PhysMemWriteClient#(addrWidth,dataWidth),PhysMemWriteServer#(addrWidth,dataWidth))
      );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset,
				   PhysMemMaster#(addrWidth, dataWidth) client,
				   PhysMemSlave#(addrWidth, dataWidth) server)(Empty);
      let readCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.read_client, server.read_server);
      let writeCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.write_client, server.write_server);
   endmodule
   module mkConnectionWithClocks2#(PhysMemMaster#(addrWidth, dataWidth) client,
				  PhysMemSlave#(addrWidth, dataWidth) server)(Empty);
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);
      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

module mkClockBinder#(a ifc) (a);
   return ifc;
endmodule

// Copyright (c) 2013,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 GetPut :: *;
import Connectable :: *;
import ClientServer :: *;
import Clocks :: *;
import MemTypes :: *;
import FIFOF :: *;
import ConnectalBramFifo::*;
import Pipe :: *;
import Probe::*;
import SyncAxisFifo32x8::*;
import AxiStream :: *;
`include "ConnectalProjectConfig.bsv"

////////////////////////////////////////////////////////////////////////////////
/// Typeclass Definition
////////////////////////////////////////////////////////////////////////////////
typeclass ConnectableWithClocks#(type a, type b);
   module mkConnectionWithClocks2#(a x1, b x2)(Empty);
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, a x1, b x2)(Empty);
endtypeclass

instance ConnectableWithClocks#(Get#(a), Put#(a)) provisos (
							    Bits#(a, awidth),
							    Add#(1, a__, awidth),
    Add#(b__, awidth, TMul#(TDiv#(awidth, 32), 32)),
    Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
    Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8))
   );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, Get#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
`ifndef GET_PUT_WITH_CLOCKS_USE_XILINX_FIFO
      SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(8, inClock, inReset, outClock);
      //FIFOF#(a) synchronizer <- mkDualClockBramFIFOF(inClock, inReset, outClock, outReset);
      let getProbe <= mkProbe();
      let putProbe <= mkProbe();
       rule mcwc_doGet;
           let v <- in.get();
	   getProbe <= v;
	   synchronizer.enq(v);
       endrule
       rule mcwc_doPut;
	  let v = synchronizer.first;
	  putProbe <= v;
	  synchronizer.deq;
	  out.put(v);
       endrule
`else
      SyncAxisFifo8#(awidth) fifo <- mkSyncAxisFifo8(inClock, inReset, outClock, outReset);
      mkConnection(in, fifo.s_axis, clocked_by inClock, reset_by inReset);
      mkConnection(fifo.m_axis, out, clocked_by outClock, reset_by outReset);
`endif
   endmodule

   module mkConnectionWithClocks2#(Get#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
      Clock inClock = clockOf(in);
      Reset inReset = resetOf(in);
      Clock outClock = clockOf(out);
      Reset outReset = resetOf(out);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, in, out);
   endmodule: mkConnectionWithClocks2
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(PipeOut#(a), Put#(a)) provisos (
							    Bits#(a, awidth),
							    Add#(1, a__, awidth),
    Add#(b__, awidth, TMul#(TDiv#(awidth, 32), 32)),
    Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
    Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8))
   );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, PipeOut#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
`ifndef GET_PUT_WITH_CLOCKS_USE_XILINX_FIFO
      SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(8, inClock, inReset, outClock);
      //FIFOF#(a) synchronizer <- mkDualClockBramFIFOF(inClock, inReset, outClock, outReset);
       rule mcwc_doGet;
          let v = in.first;
	  in.deq();
	   synchronizer.enq(v);
       endrule
       rule mcwc_doPut;
	  let v = synchronizer.first;
	  synchronizer.deq;
	  out.put(v);
       endrule
`else
      SyncAxisFifo8#(awidth) fifo <- mkSyncAxisFifo8(inClock, inReset, outClock, outReset);
      mkConnection(in, fifo.s_axis, clocked_by inClock, reset_by inReset);
      mkConnection(fifo.m_axis, out, clocked_by outClock, reset_by outReset);
`endif
   endmodule

   module mkConnectionWithClocks2#(PipeOut#(a) in, Put#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
      Clock inClock = clockOf(in);
      Reset inReset = resetOf(in);
      Clock outClock = clockOf(out);
      Reset outReset = resetOf(out);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, in, out);
   endmodule: mkConnectionWithClocks2
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(Get#(a), PipeIn#(a)) provisos (
							    Bits#(a, awidth),
							    Add#(1, a__, awidth),
    Add#(b__, awidth, TMul#(TDiv#(awidth, 32), 32)),
    Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
    Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8))
   );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, Get#(a) in, PipeIn#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
`ifndef GET_PUT_WITH_CLOCKS_USE_XILINX_FIFO
      SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(8, inClock, inReset, outClock);
      //FIFOF#(a) synchronizer <- mkDualClockBramFIFOF(inClock, inReset, outClock, outReset);
       rule mcwc_doGet;
           let v <- in.get();
	   synchronizer.enq(v);
       endrule
       rule mcwc_doEnq;
	  let v = synchronizer.first;
	  synchronizer.deq;
	  out.enq(v);
       endrule
`else
      SyncAxisFifo8#(awidth) fifo <- mkSyncAxisFifo8(inClock, inReset, outClock, outReset);
      mkConnection(in, fifo.s_axis, clocked_by inClock, reset_by inReset);
      mkConnection(fifo.m_axis, out, clocked_by outClock, reset_by outReset);
`endif
   endmodule

   module mkConnectionWithClocks2#(Get#(a) in, PipeIn#(a) out)(Empty) provisos (Bits#(a, awidth), Add#(1, a__, awidth));
      Clock inClock = clockOf(in);
      Reset inReset = resetOf(in);
      Clock outClock = clockOf(out);
      Reset outReset = resetOf(out);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, in, out);
   endmodule: mkConnectionWithClocks2
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(Client#(a,b), Server#(a,b))
   provisos (Bits#(a, awidth),
      Bits#(b, bwidth),
      Add#(1, a__, awidth),
      Add#(1, b__, bwidth),

      Add#(c__, TDiv#(awidth, 8), TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
      Add#(d__, TDiv#(bwidth, 8), TDiv#(TMul#(TDiv#(bwidth, 32), 32), 8)),
      Add#(e__, awidth, TMul#(TDiv#(awidth, 32), 32)),
      Add#(f__, bwidth, TMul#(TDiv#(bwidth, 32), 32)),
      Mul#(TDiv#(awidth, 32), 4, TDiv#(TMul#(TDiv#(awidth, 32), 32), 8)),
      Mul#(TDiv#(bwidth, 32), 4, TDiv#(TMul#(TDiv#(bwidth, 32), 32), 8))
      );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset, Client#(a,b) client, Server#(a,b) server)(Empty)
      provisos (ConnectableWithClocks#(Get#(a), Put#(a)),
		ConnectableWithClocks#(Get#(b), Put#(b)),
		Bits#(a, awidth),
		Bits#(b, bwidth));
      let reqCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.request, server.request);
      let respCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, server.response, client.response);
   endmodule
   module mkConnectionWithClocks2#(Client#(a,b) client, Server#(a,b) server)(Empty)
      provisos (ConnectableWithClocks#(Get#(a), Put#(a)),
		ConnectableWithClocks#(Get#(b), Put#(b)),
		Bits#(a, awidth),
		Bits#(b, bwidth));
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);

      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

instance ConnectableWithClocks#(PhysMemReadClient#(addrWidth, dataWidth),
				PhysMemReadServer#(addrWidth, dataWidth))
   provisos (
      ConnectableWithClocks#(Get#(PhysMemRequest#(addrWidth,dataWidth)),Put#(PhysMemRequest#(addrWidth,dataWidth))),
      ConnectableWithClocks#(Get#(MemData#(dataWidth)),Put#(MemData#(dataWidth)))
      );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset,
				   PhysMemReadClient#(addrWidth, dataWidth) client,
				   PhysMemReadServer#(addrWidth, dataWidth) server)(Empty);
      let reqCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.readReq, server.readReq);
      let dataCnx <- mkConnectionWithClocks(outClock, outReset, inClock, inReset, server.readData, client.readData);
   endmodule
   module mkConnectionWithClocks2#(PhysMemReadClient#(addrWidth, dataWidth) client,
				  PhysMemReadServer#(addrWidth, dataWidth) server)(Empty);
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);
      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

instance ConnectableWithClocks#(PhysMemWriteClient#(addrWidth, dataWidth),
				PhysMemWriteServer#(addrWidth, dataWidth))
   provisos (
    ConnectableWithClocks#(Get#(PhysMemRequest#(addrWidth, dataWidth)), Put#(PhysMemRequest#(addrWidth, dataWidth))),
    ConnectableWithClocks#(Get#(MemData#(dataWidth)),Put#(MemData#(dataWidth)))
      );

   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset,
				   PhysMemWriteClient#(addrWidth, dataWidth) client,
				   PhysMemWriteServer#(addrWidth, dataWidth) server)(Empty);
      let reqCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.writeReq, server.writeReq);
      let dataCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.writeData, server.writeData);
      let doneCnx <- mkConnectionWithClocks(outClock, outReset, inClock, inReset, server.writeDone, client.writeDone);
   endmodule
   module mkConnectionWithClocks2#(PhysMemWriteClient#(addrWidth, dataWidth) client,
				  PhysMemWriteServer#(addrWidth, dataWidth) server)(Empty);
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);
      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

instance ConnectableWithClocks#(PhysMemMaster#(addrWidth, dataWidth), PhysMemSlave#(addrWidth, dataWidth))
   provisos (
    ConnectableWithClocks#(PhysMemWriteClient#(addrWidth,dataWidth),PhysMemWriteServer#(addrWidth,dataWidth))
      );
   module mkConnectionWithClocks#(Clock inClock, Reset inReset, Clock outClock, Reset outReset,
				   PhysMemMaster#(addrWidth, dataWidth) client,
				   PhysMemSlave#(addrWidth, dataWidth) server)(Empty);
      let readCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.read_client, server.read_server);
      let writeCnx <- mkConnectionWithClocks(inClock, inReset, outClock, outReset, client.write_client, server.write_server);
   endmodule
   module mkConnectionWithClocks2#(PhysMemMaster#(addrWidth, dataWidth) client,
				  PhysMemSlave#(addrWidth, dataWidth) server)(Empty);
      Clock inClock = clockOf(client);
      Reset inReset = resetOf(client);
      Clock outClock = clockOf(server);
      Reset outReset = resetOf(server);
      mkConnectionWithClocks(inClock, inReset, outClock, outReset, client, server);
   endmodule
endinstance

module mkClockBinder#(a ifc) (a);
   return ifc;
endmodule


minor cleanup of pcs

minor cleanup of pcs

/*
   /home/jamey/connectal.clean/generated/scripts/importbvi.py
   -o
   GigEthPcsPma.bsv
   -P
   GigEthPcsPmaBvi
   -I
   GigEthPcsPmaBvi
   -c
   gtrefclk_out
   -c
   userclk_out
   -c
   userclk2_out
   -c
   rxuserclk_out
   -c
   rxuserclk2_out
   -c
   independent_clock_bufg
   -r
   pma_reset_out
   -r
   reset
   -c
   gt0_qplloutclk_out
   -c
   gt0_qplloutrefclk_out
   ../FPGA/rtl/vc709/gig_ethernet_pcs_pma_0/gig_ethernet_pcs_pma_0_stub.v
*/

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;

(* always_ready, always_enabled *)
interface GigethpcspmabviAn;
    method Action      adv_config_val(Bit#(1) v);
    method Action      adv_config_vector(Bit#(16) v);
    method Bit#(1)     interrupt();
    method Action      restart_config(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviConfiguration;
    method Action      valid(Bit#(1) v);
    method Action      vector(Bit#(5) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviGmii;
    method Bit#(1)     isolate();
    method Bit#(1)     rx_dv();
    method Bit#(1)     rx_er();
    method Bit#(8)     rxd();
    method Action      tx_en(Bit#(1) v);
    method Action      tx_er(Bit#(1) v);
    method Action      txd(Bit#(8) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviGt;
    interface Clock     qplloutclk_out;
    interface Clock     qplloutrefclk_out;
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviGtrefclk;
    method Action      n(Bit#(1) v);
    interface Clock     out;
    method Action      p(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
(* always_ready, always_enabled *)
interface GigethpcspmabviMdio;
    method Action      i(Bit#(1) v);
    method Bit#(1)     o();
    method Bit#(1)     t();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviMmcm;
    method Bit#(1)     locked_out();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviPma;
    method Reset     reset_out();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviRxuserclk;
    interface Clock     out;
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviSignal;
    method Action      detect(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviStatus;
    method Bit#(16)     vector();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviUserclk;
    interface Clock     out;
endinterface
(* always_ready, always_enabled *)
interface GigEthPcsPmaBvi;
    interface GigethpcspmabviAn     an;
    interface GigethpcspmabviConfiguration     configuration;
    interface GigethpcspmabviGmii     gmii;
    interface GigethpcspmabviGt     gt0;
    interface GigethpcspmabviGtrefclk     gtrefclk;
    method Action      mdc(Bit#(1) v);
    interface GigethpcspmabviMdio     mdio;
    interface GigethpcspmabviMmcm     mmcm;
    interface GigethpcspmabviPma     pma;
    method Bit#(1)     resetdone();
    method Action      rxn(Bit#(1) v);
    method Action      rxp(Bit#(1) v);
    interface GigethpcspmabviRxuserclk     rxuserclk2;
    interface GigethpcspmabviRxuserclk     rxuserclk;
    interface GigethpcspmabviSignal     signal;
    interface GigethpcspmabviStatus     status;
    method Bit#(1)     txn();
    method Bit#(1)     txp();
    interface GigethpcspmabviUserclk     userclk2;
    interface GigethpcspmabviUserclk     userclk;
endinterface
import "BVI" gig_ethernet_pcs_pma_0 =
module mkGigEthPcsPmaBvi#(Clock independent_clock_bufg, Reset reset_n)(GigEthPcsPmaBvi);
   let invertedReset <- mkResetInverter(reset_n, clocked_by independent_clock_bufg);
   default_clock clk();
   default_reset rst_n();
   input_clock independent_clock_bufg(independent_clock_bufg) = independent_clock_bufg;
   input_reset reset(reset) clocked_by (independent_clock_bufg) = invertedReset;
    interface GigethpcspmabviAn     an;
        method adv_config_val(an_adv_config_val) enable((*inhigh*) EN_an_adv_config_val);
        method adv_config_vector(an_adv_config_vector) enable((*inhigh*) EN_an_adv_config_vector);
        method an_interrupt interrupt();
        method restart_config(an_restart_config) enable((*inhigh*) EN_an_restart_config);
    endinterface
    interface GigethpcspmabviConfiguration     configuration;
        method valid(configuration_valid) enable((*inhigh*) EN_configuration_valid);
        method vector(configuration_vector) enable((*inhigh*) EN_configuration_vector);
    endinterface
    interface GigethpcspmabviGmii     gmii;
        method gmii_isolate isolate();
        method gmii_rx_dv rx_dv();
        method gmii_rx_er rx_er();
        method gmii_rxd rxd();
        method tx_en(gmii_tx_en) enable((*inhigh*) EN_gmii_tx_en);
        method tx_er(gmii_tx_er) enable((*inhigh*) EN_gmii_tx_er);
        method txd(gmii_txd) enable((*inhigh*) EN_gmii_txd);
    endinterface
    interface GigethpcspmabviGt     gt0;
        output_clock qplloutclk_out(gt0_qplloutclk_out);
        output_clock qplloutrefclk_out(gt0_qplloutrefclk_out);
    endinterface
    interface GigethpcspmabviGtrefclk     gtrefclk;
        method n(gtrefclk_n) enable((*inhigh*) EN_gtrefclk_n);
        output_clock out(gtrefclk_out);
        method p(gtrefclk_p) enable((*inhigh*) EN_gtrefclk_p);
    endinterface
    method mdc(mdc) enable((*inhigh*) EN_mdc);
    interface GigethpcspmabviMdio     mdio;
        method i(mdio_i) enable((*inhigh*) EN_mdio_i);
        method mdio_o o();
        method mdio_t t();
    endinterface
    interface GigethpcspmabviMmcm     mmcm;
        method mmcm_locked_out locked_out();
    endinterface
    interface GigethpcspmabviPma     pma;
        output_reset reset_out(pma_reset_out);
    endinterface
    method resetdone resetdone();
    method rxn(rxn) enable((*inhigh*) EN_rxn);
    method rxp(rxp) enable((*inhigh*) EN_rxp);
    interface GigethpcspmabviRxuserclk     rxuserclk2;
        output_clock out(rxuserclk2_out);
    endinterface
    interface GigethpcspmabviRxuserclk     rxuserclk;
        output_clock out(rxuserclk_out);
    endinterface
    interface GigethpcspmabviSignal     signal;
        method detect(signal_detect) enable((*inhigh*) EN_signal_detect);
    endinterface
    interface GigethpcspmabviStatus     status;
        method status_vector vector();
    endinterface
    method txn txn();
    method txp txp();
    interface GigethpcspmabviUserclk     userclk2;
        output_clock out(userclk2_out);
    endinterface
    interface GigethpcspmabviUserclk     userclk;
        output_clock out(userclk_out);
    endinterface
    schedule (an.adv_config_val, an.adv_config_vector, an.interrupt, an.restart_config, configuration.valid, configuration.vector, gmii.isolate, gmii.rx_dv, gmii.rx_er, gmii.rxd, gmii.tx_en, gmii.tx_er, gmii.txd, gtrefclk.n, gtrefclk.p, mdc, mdio.i, mdio.o, mdio.t, mmcm.locked_out, resetdone, rxn, rxp, signal.detect, status.vector, txn, txp) CF (an.adv_config_val, an.adv_config_vector, an.interrupt, an.restart_config, configuration.valid, configuration.vector, gmii.isolate, gmii.rx_dv, gmii.rx_er, gmii.rxd, gmii.tx_en, gmii.tx_er, gmii.txd, gtrefclk.n, gtrefclk.p, mdc, mdio.i, mdio.o, mdio.t, mmcm.locked_out, resetdone, rxn, rxp, signal.detect, status.vector, txn, txp);
endmodule

(* always_ready, always_enabled *)
interface GigEthPcsPmaPins;
    method Action      rxn(Bit#(1) v);
    method Action      rxp(Bit#(1) v);
    method Bit#(1)     txn();
    method Bit#(1)     txp();
    method Action      gtrefclkp(Bit#(1) v);
    method Action      gtrefclkn(Bit#(1) v);
endinterface

(* always_ready, always_enabled *)
interface GigEthPcsPmaTxPins;
    method Bit#(1)     txn();
    method Bit#(1)     txp();
endinterface

interface GigEthPcsPmaDebug;
    method Bit#(1)     locked_out();
    method Bit#(16)    status();
    method Bit#(1)     resetdone();
endinterface

interface GigEthPcsPma;
   method Action      mdc(Bit#(1) v);
   interface GigethpcspmabviMdio     mdio;
   interface GigethpcspmabviGmii     gmii;
   interface GigEthPcsPmaPins        pins;
   interface GigEthPcsPmaDebug       debug;
   interface Clock                   gtrefclk;
   method Bit#(1) interrupt();
endinterface

module mkGigEthPcsPma#(Clock independent_clock_bufg, Reset reset)(GigEthPcsPma);
   GigEthPcsPmaBvi bvi <- mkGigEthPcsPmaBvi(independent_clock_bufg, reset);

   rule rl_detect;
      bvi.signal.detect(1);
   endrule

   method      mdc = bvi.mdc;
   interface mdio = bvi.mdio;
   interface gmii = bvi.gmii;
   interface gtrefclk = bvi.gtrefclk.out;
   interface GigEthPcsPmaPins pins;
      method rxn = bvi.rxn;
      method rxp = bvi.rxp;
      method txn = bvi.txn;
      method txp = bvi.txp;
      method gtrefclkp = bvi.gtrefclk.p;
      method gtrefclkn = bvi.gtrefclk.n;
   endinterface
   method interrupt = bvi.an.interrupt;
   interface GigEthPcsPmaDebug debug;
      method locked_out = bvi.mmcm.locked_out;
      method status = bvi.status.vector();
      method resetdone  = bvi.resetdone;
   endinterface

endmodule

/*
   /home/jamey/connectal.clean/generated/scripts/importbvi.py
   -o
   GigEthPcsPma.bsv
   -P
   GigEthPcsPmaBvi
   -I
   GigEthPcsPmaBvi
   -c
   gtrefclk_out
   -c
   userclk_out
   -c
   userclk2_out
   -c
   rxuserclk_out
   -c
   rxuserclk2_out
   -c
   independent_clock_bufg
   -r
   pma_reset_out
   -r
   reset
   -c
   gt0_qplloutclk_out
   -c
   gt0_qplloutrefclk_out
   ../FPGA/rtl/vc709/gig_ethernet_pcs_pma_0/gig_ethernet_pcs_pma_0_stub.v
*/

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;

(* always_ready, always_enabled *)
interface GigethpcspmabviAn;
    method Action      adv_config_val(Bit#(1) v);
    method Action      adv_config_vector(Bit#(16) v);
    method Bit#(1)     interrupt();
    method Action      restart_config(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviConfiguration;
    method Action      valid(Bit#(1) v);
    method Action      vector(Bit#(5) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviGmii;
    method Bit#(1)     isolate();
    method Bit#(1)     rx_dv();
    method Bit#(1)     rx_er();
    method Bit#(8)     rxd();
    method Action      tx_en(Bit#(1) v);
    method Action      tx_er(Bit#(1) v);
    method Action      txd(Bit#(8) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviGt;
    interface Clock     qplloutclk_out;
    interface Clock     qplloutrefclk_out;
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviGtrefclk;
    method Action      n(Bit#(1) v);
    interface Clock     out;
    method Action      p(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
(* always_ready, always_enabled *)
interface GigethpcspmabviMdio;
    method Action      i(Bit#(1) v);
    method Bit#(1)     o();
    method Bit#(1)     t();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviMmcm;
    method Bit#(1)     locked_out();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviPma;
    method Reset     reset_out();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviRxuserclk;
    interface Clock     out;
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviSignal;
    method Action      detect(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviStatus;
    method Bit#(16)     vector();
endinterface
(* always_ready, always_enabled *)
interface GigethpcspmabviUserclk;
    interface Clock     out;
endinterface
(* always_ready, always_enabled *)
interface GigEthPcsPmaBvi;
    interface GigethpcspmabviAn     an;
    interface GigethpcspmabviConfiguration     configuration;
    interface GigethpcspmabviGmii     gmii;
    interface GigethpcspmabviGt     gt0;
    interface GigethpcspmabviGtrefclk     gtrefclk;
    method Action      mdc(Bit#(1) v);
    interface GigethpcspmabviMdio     mdio;
    interface GigethpcspmabviMmcm     mmcm;
    interface GigethpcspmabviPma     pma;
    method Bit#(1)     resetdone();
    method Action      rxn(Bit#(1) v);
    method Action      rxp(Bit#(1) v);
    interface GigethpcspmabviRxuserclk     rxuserclk2;
    interface GigethpcspmabviRxuserclk     rxuserclk;
    interface GigethpcspmabviSignal     signal;
    interface GigethpcspmabviStatus     status;
    method Bit#(1)     txn();
    method Bit#(1)     txp();
    interface GigethpcspmabviUserclk     userclk2;
    interface GigethpcspmabviUserclk     userclk;
endinterface
import "BVI" gig_ethernet_pcs_pma_0 =
module mkGigEthPcsPmaBvi#(Clock independent_clock_bufg, Reset reset)(GigEthPcsPmaBvi);
   let invertedReset <- mkResetInverter(reset);
    default_clock independent_clock_bufg(independent_clock_bufg) = independent_clock_bufg;
    default_reset reset(reset) = invertedReset;
    interface GigethpcspmabviAn     an;
        method adv_config_val(an_adv_config_val) enable((*inhigh*) EN_an_adv_config_val);
        method adv_config_vector(an_adv_config_vector) enable((*inhigh*) EN_an_adv_config_vector);
        method an_interrupt interrupt();
        method restart_config(an_restart_config) enable((*inhigh*) EN_an_restart_config);
    endinterface
    interface GigethpcspmabviConfiguration     configuration;
        method valid(configuration_valid) enable((*inhigh*) EN_configuration_valid);
        method vector(configuration_vector) enable((*inhigh*) EN_configuration_vector);
    endinterface
    interface GigethpcspmabviGmii     gmii;
        method gmii_isolate isolate();
        method gmii_rx_dv rx_dv();
        method gmii_rx_er rx_er();
        method gmii_rxd rxd();
        method tx_en(gmii_tx_en) enable((*inhigh*) EN_gmii_tx_en);
        method tx_er(gmii_tx_er) enable((*inhigh*) EN_gmii_tx_er);
        method txd(gmii_txd) enable((*inhigh*) EN_gmii_txd);
    endinterface
    interface GigethpcspmabviGt     gt0;
        output_clock qplloutclk_out(gt0_qplloutclk_out);
        output_clock qplloutrefclk_out(gt0_qplloutrefclk_out);
    endinterface
    interface GigethpcspmabviGtrefclk     gtrefclk;
        method n(gtrefclk_n) enable((*inhigh*) EN_gtrefclk_n);
        output_clock out(gtrefclk_out);
        method p(gtrefclk_p) enable((*inhigh*) EN_gtrefclk_p);
    endinterface
    method mdc(mdc) enable((*inhigh*) EN_mdc);
    interface GigethpcspmabviMdio     mdio;
        method i(mdio_i) enable((*inhigh*) EN_mdio_i);
        method mdio_o o();
        method mdio_t t();
    endinterface
    interface GigethpcspmabviMmcm     mmcm;
        method mmcm_locked_out locked_out();
    endinterface
    interface GigethpcspmabviPma     pma;
        output_reset reset_out(pma_reset_out);
    endinterface
    method resetdone resetdone();
    method rxn(rxn) enable((*inhigh*) EN_rxn);
    method rxp(rxp) enable((*inhigh*) EN_rxp);
    interface GigethpcspmabviRxuserclk     rxuserclk2;
        output_clock out(rxuserclk2_out);
    endinterface
    interface GigethpcspmabviRxuserclk     rxuserclk;
        output_clock out(rxuserclk_out);
    endinterface
    interface GigethpcspmabviSignal     signal;
        method detect(signal_detect) enable((*inhigh*) EN_signal_detect);
    endinterface
    interface GigethpcspmabviStatus     status;
        method status_vector vector();
    endinterface
    method txn txn();
    method txp txp();
    interface GigethpcspmabviUserclk     userclk2;
        output_clock out(userclk2_out);
    endinterface
    interface GigethpcspmabviUserclk     userclk;
        output_clock out(userclk_out);
    endinterface
    schedule (an.adv_config_val, an.adv_config_vector, an.interrupt, an.restart_config, configuration.valid, configuration.vector, gmii.isolate, gmii.rx_dv, gmii.rx_er, gmii.rxd, gmii.tx_en, gmii.tx_er, gmii.txd, gtrefclk.n, gtrefclk.p, mdc, mdio.i, mdio.o, mdio.t, mmcm.locked_out, resetdone, rxn, rxp, signal.detect, status.vector, txn, txp) CF (an.adv_config_val, an.adv_config_vector, an.interrupt, an.restart_config, configuration.valid, configuration.vector, gmii.isolate, gmii.rx_dv, gmii.rx_er, gmii.rxd, gmii.tx_en, gmii.tx_er, gmii.txd, gtrefclk.n, gtrefclk.p, mdc, mdio.i, mdio.o, mdio.t, mmcm.locked_out, resetdone, rxn, rxp, signal.detect, status.vector, txn, txp);
endmodule

(* always_ready, always_enabled *)
interface GigEthPcsPmaPins;
    method Action      rxn(Bit#(1) v);
    method Action      rxp(Bit#(1) v);
    method Bit#(1)     txn();
    method Bit#(1)     txp();
    method Action      gtrefclkp(Bit#(1) v);
    method Action      gtrefclkn(Bit#(1) v);
endinterface

(* always_ready, always_enabled *)
interface GigEthPcsPmaTxPins;
    method Bit#(1)     txn();
    method Bit#(1)     txp();
endinterface

interface GigEthPcsPmaDebug;
    method Bit#(1)     locked_out();
    method Action      detect(Bit#(1) v);
    method Bit#(16)    status();
    method Bit#(1)     resetdone();
endinterface

interface GigEthPcsPma;
   method Action      mdc(Bit#(1) v);
   interface GigethpcspmabviMdio     mdio;
   interface GigethpcspmabviGmii     gmii;
   interface GigEthPcsPmaPins        pins;
   interface GigEthPcsPmaDebug       debug;
   interface Clock                   gtrefclk;
   method Bit#(1) interrupt();
endinterface

module mkGigEthPcsPma#(Clock independent_clock_bufg, Reset reset)(GigEthPcsPma);
   GigEthPcsPmaBvi bvi <- mkGigEthPcsPmaBvi(independent_clock_bufg, reset);

   rule rl_detect;
      bvi.signal.detect(1);
   endrule

   method      mdc = bvi.mdc;
   interface mdio = bvi.mdio;
   interface gmii = bvi.gmii;
   interface gtrefclk = bvi.gtrefclk.out;
   interface GigEthPcsPmaPins pins;
      method rxn = bvi.rxn;
      method rxp = bvi.rxp;
      method txn = bvi.txn;
      method txp = bvi.txp;
      method gtrefclkp = bvi.gtrefclk.p;
      method gtrefclkn = bvi.gtrefclk.n;
   endinterface
   method interrupt = bvi.an.interrupt;
   interface GigEthPcsPmaDebug debug;
      method locked_out = bvi.mmcm.locked_out;
      method status = bvi.status.vector();
      method resetdone  = bvi.resetdone;
   endinterface

endmodule


rewrote MPStreamEngine from 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.

/*
 * Implementation of:
 *    MP algorithm on pages 7-11 from "Pattern Matching Algorithms" by
 *       Alberto Apostolico, Zvi Galil, 1997
 */

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import Gearbox::*;
import Connectable::*;
import ConfigReg::*;
import StmtFSM::*;

import MemUtils::*;
import MemTypes::*;
import Dma2BRAM::*;
import Pipe::*;
import EHR::*;

interface MPEngine#(numeric type haystackBusWidth, numeric type configBusWidth);
   interface PipeIn#(Triplet#(Bit#(32))) setsearch;
   interface PipeOut#(Int#(32)) locdone;
endinterface

interface MPStreamEngine#(numeric type haystackBusWidth, numeric type configBusWidth);
   interface PipeIn#(MemDataF#(configBusWidth)) needle;
   interface PipeIn#(MemDataF#(configBusWidth)) mpNext;
   interface PipeIn#(MemDataF#(haystackBusWidth)) haystack;
   interface PipeOut#(Int#(32)) locdone;
   method Action clear();
   method Action start(Bit#(32) needleLen);
endinterface

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

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

typedef enum {Config_needle, Config_mpNext, Initialized, Search} Stage deriving (Eq, Bits);

module mkMPEngine#(MemReadEngineServer#(haystackBusWidth) haystackReader,
		   MemReadEngineServer#(configBusWidth) configReader) (MPEngine#(haystackBusWidth,configBusWidth))

   provisos(Add#(a__, 8, haystackBusWidth),
	    Div#(haystackBusWidth,8,haystackBusBytes),
	    Mul#(haystackBusBytes,8,haystackBusWidth),
	    Add#(1, b__, haystackBusBytes),
	    Add#(c__, 32, haystackBusWidth),
	    Add#(1, d__, TDiv#(haystackBusWidth, 32)),
	    Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth),
	    Add#(e__, TLog#(haystackBusBytes), 32),
	    Add#(f__, TLog#(TDiv#(haystackBusWidth, 32)), 32)
	    ,Mul#(TDiv#(configBusWidth, 8), 8, configBusWidth)
	    ,Add#(1, g__, TDiv#(configBusWidth, 8))
	    ,Add#(h__, TLog#(TDiv#(configBusWidth, 8)), 32)
	    ,Add#(i__, TLog#(TDiv#(configBusWidth, 32)), 32)
	    ,Add#(1, j__, TDiv#(configBusWidth, 32))
	    ,Mul#(TDiv#(configBusWidth, 32), 32, configBusWidth)
	    );

   FIFOF#(Int#(32)) locf <- mkFIFOF;
   FIFO#(Bool) conff <- mkSizedFIFO(1);

   let verbose = True;
   let debug = False;

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

   Reg#(Bit#(32)) cycleCnt <- mkReg(0);
   Reg#(Bit#(32)) lastHD <- mkReg(0);

   Reg#(Stage)    stage <- mkReg(Config_needle);
   Reg#(Bit#(32)) needleLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackBase <- mkReg(0);
   Reg#(Bit#(32)) jReg <- mkReg(0); // offset in haystack
   Reg#(Bit#(32)) iReg <- mkReg(0); // offset in needle
   Reg#(Bit#(2))  epochReg <- mkReg(0);

   BRAMWriter#(NeedleIdxWidth,configBusWidth) n2b <- mkBRAMWriter(0, needle.portB, configReader);
   BRAMWriter#(NeedleIdxWidth,configBusWidth) mp2b <- mkBRAMWriter(1, mpNext.portB, configReader);

   FIFOF#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFOF(2);
   FIFOF#(Triplet#(Bit#(32))) ssfifo <- mkFIFOF;
   FIFO#(void) doneFifo <- mkFIFO;

   rule countCycles;
      if (debug) $display("******************************************** %d", cycleCnt);
      cycleCnt <= cycleCnt+1;
   endrule

   rule haystackResp;
      if (debug) $display("mkMPEngine::haystackResp");
      let rv <- toGet(haystackReader.data).get;
      haystack.enq(unpack(rv.data));
      if (rv.last)
         conff.deq;
   endrule

   rule haystackDrain(stage != Search);
      if (debug) $display("mkMPEngine::haystackDrain");
      haystack.deq;
   endrule

   rule bramDrain(stage != Search);
      if (debug) $display("mkMPEngine::mpNextDrain");
      let x <- mpNext.portA.response.get;
      let y <- needle.portA.response.get;
      efifo.deq;
   endrule

`define OPTIMIZE_MISMATCH
`ifdef OPTIMIZE_MISMATCH
   rule matchNeedleReq(stage == Search);
      if (debug) $display("mkMPEngine::matchNeedleReq %d %d", epochReg, iReg);
      needle.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      mpNext.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= 1;
   endrule

   rule matchNeedleResp(stage == Search);
      let nv <- needle.portA.response.get;
      let mp <- mpNext.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (debug) $display("mkMPEngine::matchNeedleResp %d %d", epochReg, epoch);
      if (epoch == epochReg) begin
	 Bool deq_haystack = False;
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (debug) $display("mkMPEngine::feck %d %d %d %d %x %x", n, m, i, j, hv[0], nv);
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    stage <= Config_needle;
	    if (debug) $display("mkMPEngine::end of search %d", j);
	    locf.enq(-1);
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    if (debug) $display("mkMPEngine::string match %d", j);
	    locf.enq(unpack(haystackBase+j-i));
	 end
	 else if (nv != hv[0]) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    if (debug) $display("mkMPEngine::char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    if (mp == 0) begin
	       iReg <= 1;
	       jReg <= j+1;
	       deq_haystack = True;
	    end
	    else begin
	       epochReg <= epochReg + 1;
	       iReg <= mp;
	    end
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    if (debug) $display("mkMPEngine::char match(%d) %d %d", (nv == hv[0]), i, j);
	    deq_haystack = True;
	    jReg <= j+1;
	    epochReg <= epochReg + 1;
	    iReg <= i+1;
	 end
	 if (deq_haystack) begin
	    haystack.deq;
	    lastHD <= cycleCnt;
	    if (debug) $display("mkMPEngine:: deq haystack(%d)", cycleCnt-lastHD);
	 end
      end
      else begin
	 if (debug) $display("mkMPEngine::discard");
	 noAction;
      end
   endrule
`else
   rule matchNeedleReq(stage == Search);
      if (debug) $display("mkMPEngine::matchNeedleReq %d %d", epochReg, iReg);
      needle.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      mpNext.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= iReg+1;
   endrule

   rule matchNeedleResp(stage == Search);
      let nv <- needle.portA.response.get;
      let mp <- mpNext.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (debug) $display("mkMPEngine::matchNeedleResp %d %d", epochReg, epoch);
      if (epoch == epochReg) begin
	 Bool deq_haystack = False;
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (debug) $display("mkMPEngine::feck %d %d %d %d %x %x", n, m, i, j, hv[0], nv);
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    stage <= Config_needle;
	    if (debug) $display("mkMPEngine::end of search %d", j);
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    if (debug) $display("mkMPEngine::string match %d", j);
	    locf.enq(unpack(haystackBase+j-i));
	    epochReg <= epochReg + 1;
	    iReg <= 1;
	 end
	 else if (nv != hv[0]) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    if (debug) $display("mkMPEngine::char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    epochReg <= epochReg + 1;
	    if (mp == 0) begin
	       iReg <= 1;
	       jReg <= j+1;
	       deq_haystack = True;
	    end
	    else begin
	       iReg <= mp;
	    end
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    if (debug) $display("mkMPEngine::char match(%d) %d %d", (nv == hv[0]), i, j);
	    deq_haystack = True;
	    jReg <= j+1;
	 end
	 if (deq_haystack) begin
	    haystack.deq;
	    lastHD <= cycleCnt;
	    if (debug) $display("mkMPEngine:: deq haystack(%d)", cycleCnt-lastHD);
	 end
      end
      else begin
	 if (debug) $display("mkMPEngine::discard");
	 noAction;
      end
   endrule
`endif

   rule finish_setup_n2b;
      if (verbose) $display("mkMPEngine::finish_setup_n2b");
      let x <- n2b.finish;
      conff.deq;
      stage <= Config_mpNext;
   endrule

   rule finish_setup_mp2b;
      if (verbose) $display("mkMPEngine::finish_setup_mp2b");
      let y <- mp2b.finish;
      conff.deq;
      stage <= Initialized;
   endrule

   rule setup_needle (stage == Config_needle);
      conff.enq(True);
      match {.needle_sglId, .mpNext_sglId, .needle_len} = ssfifo.first;
      needleLenReg <= extend(needle_len);
      if (verbose) $display("mkMPEngine::setup_needle %d %d", needle_sglId, needle_len);
      n2b.start(needle_sglId, 0, 0, pack(truncate(needle_len)));
   endrule

   rule setup_mpNext (stage == Config_mpNext);
      conff.enq(True);
      match {.needle_sglId, .mpNext_sglId, .needle_len} = ssfifo.first;
      needleLenReg <= extend(needle_len);
      if (verbose) $display("mkMPEngine::setup_mpNext %d %d", mpNext_sglId, needle_len);
      mp2b.start(mpNext_sglId, 0, 0, pack(truncate(needle_len)));
      ssfifo.deq;
   endrule

   rule search (stage == Initialized && !efifo.notEmpty && !haystack.notEmpty);
      stage <= Search;
      conff.enq(True);
      match {.haystack_sglId, .haystack_len, .haystack_base} <- toGet(ssfifo).get;
      haystackLenReg <= extend(haystack_len);
      haystackBase <= extend(haystack_base);
      iReg <= 1;
      jReg <= 1;
      epochReg <= 0;
      Bit#(32) haystack_len_ds = haystack_len+fromInteger(valueOf(haystackBusBytes)-1);
      Bit#(TLog#(haystackBusBytes)) zeros = 0;
      Bit#(32) haystack_len_bytes = {zeros,haystack_len_ds[31:valueOf(TLog#(haystackBusBytes))]} * fromInteger(valueOf(haystackBusBytes));
      $display("haystack read offset=%d burstLen=%d", haystack_base, fromInteger(8*valueOf(haystackBusBytes)));
      haystackReader.request.put(MemengineCmd{sglId:haystack_sglId, base:extend(haystack_base), len:haystack_len_bytes, burstLen:fromInteger(8*valueOf(haystackBusBytes)), tag: 0});
      if (verbose) $display("mkMPEngine::search %d %d %d",  haystack_sglId, haystack_base, haystack_len_bytes);
   endrule

   interface PipeIn setsearch = toPipeIn(ssfifo);
   interface PipeOut locdone = toPipeOut(locf);

endmodule

module mkMPStreamEngine(MPStreamEngine#(haystackBusWidth,configBusWidth))

   provisos(Add#(a__, 8, haystackBusWidth),
	    Div#(haystackBusWidth,8,haystackBusBytes),
	    Mul#(haystackBusBytes,8,haystackBusWidth),
	    Add#(1, b__, haystackBusBytes),
	    Add#(c__, 32, haystackBusWidth),
	    Add#(1, d__, TDiv#(haystackBusWidth, 32)),
	    Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth),
	    Add#(e__, TLog#(haystackBusBytes), 32),
	    Add#(f__, TLog#(TDiv#(haystackBusWidth, 32)), 32)
	    ,Mul#(TDiv#(configBusWidth, 8), 8, configBusWidth)
	    ,Add#(1, g__, TDiv#(configBusWidth, 8))
	    ,Add#(h__, TLog#(TDiv#(configBusWidth, 8)), 32)
	    ,Add#(i__, TLog#(TDiv#(configBusWidth, 32)), 32)
	    ,Add#(1, j__, TDiv#(configBusWidth, 32))
	    ,Mul#(TDiv#(configBusWidth, 32), 32, configBusWidth)
	    );

   FIFOF#(Int#(32)) locf <- mkFIFOF;

   let verbose = True;
   let debug = True;

   Clock clk <- exposeCurrentClock;
   Reset rst <- exposeCurrentReset;
   BRAM2Port#(NeedleIdx, Char) needleBram  <- mkBRAM2Server(defaultValue);
   BRAM2Port#(NeedleIdx, Bit#(32)) mpNextBram <- mkBRAM2Server(defaultValue);
   FIFOF#(MemDataF#(haystackBusWidth)) haystackFifo <- mkFIFOF();
   Gearbox#(haystackBusBytes,1,Char) haystackGb <- mkNto1Gearbox(clk,rst,clk,rst);

   Reg#(Bit#(32)) cycleCnt <- mkReg(0);
   Reg#(Bit#(32)) lastHD <- mkReg(0);

   Reg#(Stage)    stage <- mkReg(Initialized);
   Reg#(Bit#(32)) needleLenReg <- mkReg(0);
   Reg#(Bit#(32)) jReg <- mkReg(1); // offset in haystack
   Reg#(Bit#(32)) iReg <- mkReg(1); // offset in needle

   BRAMPipeIn#(NeedleIdxWidth,configBusWidth) n2b <- mkBRAMPipeIn(0, needleBram.portB);
   BRAMPipeIn#(NeedleIdxWidth,configBusWidth) mp2b <- mkBRAMPipeIn(1, mpNextBram.portB);

   FIFOF#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFOF(2);
   FIFO#(void) doneFifo <- mkFIFO;

   rule countCycles;
      //if (debug) $display("******************************************** %d", cycleCnt);
      cycleCnt <= cycleCnt+1;
   endrule

   rule haystackResp;
      let rv <- toGet(haystackFifo).get;
      if (debug) $display("mkMPEngine::haystackResp rv=%h", rv.data);
      haystackGb.enq(unpack(rv.data));
   endrule

   let x_i <- mkReg(0);
   let t_j <- mkReg(0);
   let m = needleLenReg;
   let i = iReg;
   let matchFsm <- mkAutoFSM(seq
      while (stage != Search) seq
	 iReg <= 1;
      endseq
      action
	 iReg <= 1;
	 jReg <= 1;
	 let t = haystackGb.first[0]; haystackGb.deq();
	 t_j <= t;
	 needleBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      endaction
      action
	 let xNext <- needleBram.portA.response.get();
	 x_i <= xNext;
      endaction
      while (stage == Search) seq
	 $display("initial i=%d j=%d x_i=%h t_j=%h", iReg, jReg, x_i, t_j);
	 while ((i == m + 1) || (i > 0 && x_i != t_j)) seq
	    action
	       mpNextBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      	    endaction
	    action
	       let mpNext <- mpNextBram.portA.response.get();
	       iReg <= mpNext;
	       needleBram.portA.request.put(BRAMRequest{write:False, address: truncate(mpNext-1), datain:?, responseOnWrite:?});
	    endaction
	    action
	       let xNext <- needleBram.portA.response.get();
	       x_i <= xNext;
	       $display("i=%d m+1=%d x_i=%h t_j=%h", i, m+1, xNext, t_j);
	    endaction
	 endseq
	 action
	    iReg <= iReg + 1;
	    jReg <= jReg + 1;
	    needleBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg+1-1), datain:?, responseOnWrite:?});
	    let t = haystackGb.first[0]; haystackGb.deq();
	    t_j <= t;
	    if (t == 0)
	       locf.enq(-1);
	 endaction
	 action
	    let xNext <- needleBram.portA.response.get();
	    x_i <= xNext;
	    $display("step    i=%d j=%d x_i=%h t_j=%h", iReg, jReg, xNext, t_j);
	    if (iReg == m + 1) begin
	       $display("match at j=%d", jReg - iReg);
	       locf.enq(unpack(jReg - iReg));
	    end
	 endaction
      endseq // stage == Search
      endseq);

   interface PipeIn needle = n2b.pipe;
   interface PipeIn mpNext = mp2b.pipe;
   interface PipeIn haystack = toPipeIn(haystackFifo);
   interface PipeOut locdone = toPipeOut(locf);

   method Action clear();
      stage <= Initialized;
   endmethod
   method Action start(Bit#(32) needleLen);
      stage <= Search;
      jReg <= 1;
      iReg <= 1;
      needleLenReg <= needleLen;
   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.

/*
 * Implementation of:
 *    MP algorithm on pages 7-11 from "Pattern Matching Algorithms" by
 *       Alberto Apostolico, Zvi Galil, 1997
 */

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import Gearbox::*;
import Connectable::*;
import ConfigReg::*;

import MemUtils::*;
import MemTypes::*;
import Dma2BRAM::*;
import Pipe::*;
import EHR::*;

interface MPEngine#(numeric type haystackBusWidth, numeric type configBusWidth);
   interface PipeIn#(Triplet#(Bit#(32))) setsearch;
   interface PipeOut#(Int#(32)) locdone;
endinterface

interface MPStreamEngine#(numeric type haystackBusWidth, numeric type configBusWidth);
   interface PipeIn#(MemData#(configBusWidth)) needle;
   interface PipeIn#(MemData#(configBusWidth)) mpNext;
   interface PipeIn#(MemData#(haystackBusWidth)) haystack;
   interface PipeOut#(Int#(32)) locdone;
endinterface

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

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

typedef enum {Config_needle, Config_mpNext, Initialized, Search} Stage deriving (Eq, Bits);

module mkMPEngine#(MemReadEngineServer#(haystackBusWidth) haystackReader,
		   MemReadEngineServer#(configBusWidth) configReader) (MPEngine#(haystackBusWidth,configBusWidth))

   provisos(Add#(a__, 8, haystackBusWidth),
	    Div#(haystackBusWidth,8,haystackBusBytes),
	    Mul#(haystackBusBytes,8,haystackBusWidth),
	    Add#(1, b__, haystackBusBytes),
	    Add#(c__, 32, haystackBusWidth),
	    Add#(1, d__, TDiv#(haystackBusWidth, 32)),
	    Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth),
	    Add#(e__, TLog#(haystackBusBytes), 32),
	    Add#(f__, TLog#(TDiv#(haystackBusWidth, 32)), 32)
	    ,Mul#(TDiv#(configBusWidth, 8), 8, configBusWidth)
	    ,Add#(1, g__, TDiv#(configBusWidth, 8))
	    ,Add#(h__, TLog#(TDiv#(configBusWidth, 8)), 32)
	    ,Add#(i__, TLog#(TDiv#(configBusWidth, 32)), 32)
	    ,Add#(1, j__, TDiv#(configBusWidth, 32))
	    ,Mul#(TDiv#(configBusWidth, 32), 32, configBusWidth)
	    );

   FIFOF#(Int#(32)) locf <- mkFIFOF;
   FIFO#(Bool) conff <- mkSizedFIFO(1);

   let verbose = True;
   let debug = False;

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

   Reg#(Bit#(32)) cycleCnt <- mkReg(0);
   Reg#(Bit#(32)) lastHD <- mkReg(0);

   Reg#(Stage)    stage <- mkReg(Config_needle);
   Reg#(Bit#(32)) needleLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackBase <- mkReg(0);
   Reg#(Bit#(32)) jReg <- mkReg(0); // offset in haystack
   Reg#(Bit#(32)) iReg <- mkReg(0); // offset in needle
   Reg#(Bit#(2))  epochReg <- mkReg(0);

   BRAMWriter#(NeedleIdxWidth,configBusWidth) n2b <- mkBRAMWriter(0, needle.portB, configReader);
   BRAMWriter#(NeedleIdxWidth,configBusWidth) mp2b <- mkBRAMWriter(1, mpNext.portB, configReader);

   FIFOF#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFOF(2);
   FIFOF#(Triplet#(Bit#(32))) ssfifo <- mkFIFOF;
   FIFO#(void) doneFifo <- mkFIFO;

   rule countCycles;
      if (debug) $display("******************************************** %d", cycleCnt);
      cycleCnt <= cycleCnt+1;
   endrule

   rule haystackResp;
      if (debug) $display("mkMPEngine::haystackResp");
      let rv <- toGet(haystackReader.data).get;
      haystack.enq(unpack(rv.data));
      if (rv.last)
         conff.deq;
   endrule

   rule haystackDrain(stage != Search);
      if (debug) $display("mkMPEngine::haystackDrain");
      haystack.deq;
   endrule

   rule bramDrain(stage != Search);
      if (debug) $display("mkMPEngine::mpNextDrain");
      let x <- mpNext.portA.response.get;
      let y <- needle.portA.response.get;
      efifo.deq;
   endrule

`define OPTIMIZE_MISMATCH
`ifdef OPTIMIZE_MISMATCH
   rule matchNeedleReq(stage == Search);
      if (debug) $display("mkMPEngine::matchNeedleReq %d %d", epochReg, iReg);
      needle.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      mpNext.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= 1;
   endrule

   rule matchNeedleResp(stage == Search);
      let nv <- needle.portA.response.get;
      let mp <- mpNext.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (debug) $display("mkMPEngine::matchNeedleResp %d %d", epochReg, epoch);
      if (epoch == epochReg) begin
	 Bool deq_haystack = False;
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (debug) $display("mkMPEngine::feck %d %d %d %d %x %x", n, m, i, j, hv[0], nv);
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    stage <= Config_needle;
	    if (debug) $display("mkMPEngine::end of search %d", j);
	    locf.enq(-1);
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    if (debug) $display("mkMPEngine::string match %d", j);
	    locf.enq(unpack(haystackBase+j-i));
	 end
	 else if (nv != hv[0]) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    if (debug) $display("mkMPEngine::char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    if (mp == 0) begin
	       iReg <= 1;
	       jReg <= j+1;
	       deq_haystack = True;
	    end
	    else begin
	       epochReg <= epochReg + 1;
	       iReg <= mp;
	    end
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    if (debug) $display("mkMPEngine::char match(%d) %d %d", (nv == hv[0]), i, j);
	    deq_haystack = True;
	    jReg <= j+1;
	    epochReg <= epochReg + 1;
	    iReg <= i+1;
	 end
	 if (deq_haystack) begin
	    haystack.deq;
	    lastHD <= cycleCnt;
	    if (debug) $display("mkMPEngine:: deq haystack(%d)", cycleCnt-lastHD);
	 end
      end
      else begin
	 if (debug) $display("mkMPEngine::discard");
	 noAction;
      end
   endrule
`else
   rule matchNeedleReq(stage == Search);
      if (debug) $display("mkMPEngine::matchNeedleReq %d %d", epochReg, iReg);
      needle.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      mpNext.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= iReg+1;
   endrule

   rule matchNeedleResp(stage == Search);
      let nv <- needle.portA.response.get;
      let mp <- mpNext.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (debug) $display("mkMPEngine::matchNeedleResp %d %d", epochReg, epoch);
      if (epoch == epochReg) begin
	 Bool deq_haystack = False;
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (debug) $display("mkMPEngine::feck %d %d %d %d %x %x", n, m, i, j, hv[0], nv);
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    stage <= Config_needle;
	    if (debug) $display("mkMPEngine::end of search %d", j);
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    if (debug) $display("mkMPEngine::string match %d", j);
	    locf.enq(unpack(haystackBase+j-i));
	    epochReg <= epochReg + 1;
	    iReg <= 1;
	 end
	 else if (nv != hv[0]) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    if (debug) $display("mkMPEngine::char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    epochReg <= epochReg + 1;
	    if (mp == 0) begin
	       iReg <= 1;
	       jReg <= j+1;
	       deq_haystack = True;
	    end
	    else begin
	       iReg <= mp;
	    end
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    if (debug) $display("mkMPEngine::char match(%d) %d %d", (nv == hv[0]), i, j);
	    deq_haystack = True;
	    jReg <= j+1;
	 end
	 if (deq_haystack) begin
	    haystack.deq;
	    lastHD <= cycleCnt;
	    if (debug) $display("mkMPEngine:: deq haystack(%d)", cycleCnt-lastHD);
	 end
      end
      else begin
	 if (debug) $display("mkMPEngine::discard");
	 noAction;
      end
   endrule
`endif

   rule finish_setup_n2b;
      if (verbose) $display("mkMPEngine::finish_setup_n2b");
      let x <- n2b.finish;
      conff.deq;
      stage <= Config_mpNext;
   endrule

   rule finish_setup_mp2b;
      if (verbose) $display("mkMPEngine::finish_setup_mp2b");
      let y <- mp2b.finish;
      conff.deq;
      stage <= Initialized;
   endrule

   rule setup_needle (stage == Config_needle);
      conff.enq(True);
      match {.needle_sglId, .mpNext_sglId, .needle_len} = ssfifo.first;
      needleLenReg <= extend(needle_len);
      if (verbose) $display("mkMPEngine::setup_needle %d %d", needle_sglId, needle_len);
      n2b.start(needle_sglId, 0, 0, pack(truncate(needle_len)));
   endrule

   rule setup_mpNext (stage == Config_mpNext);
      conff.enq(True);
      match {.needle_sglId, .mpNext_sglId, .needle_len} = ssfifo.first;
      needleLenReg <= extend(needle_len);
      if (verbose) $display("mkMPEngine::setup_mpNext %d %d", mpNext_sglId, needle_len);
      mp2b.start(mpNext_sglId, 0, 0, pack(truncate(needle_len)));
      ssfifo.deq;
   endrule

   rule search (stage == Initialized && !efifo.notEmpty && !haystack.notEmpty);
      stage <= Search;
      conff.enq(True);
      match {.haystack_sglId, .haystack_len, .haystack_base} <- toGet(ssfifo).get;
      haystackLenReg <= extend(haystack_len);
      haystackBase <= extend(haystack_base);
      iReg <= 1;
      jReg <= 1;
      epochReg <= 0;
      Bit#(32) haystack_len_ds = haystack_len+fromInteger(valueOf(haystackBusBytes)-1);
      Bit#(TLog#(haystackBusBytes)) zeros = 0;
      Bit#(32) haystack_len_bytes = {zeros,haystack_len_ds[31:valueOf(TLog#(haystackBusBytes))]} * fromInteger(valueOf(haystackBusBytes));
      $display("haystack read offset=%d burstLen=%d", haystack_base, fromInteger(8*valueOf(haystackBusBytes)));
      haystackReader.request.put(MemengineCmd{sglId:haystack_sglId, base:extend(haystack_base), len:haystack_len_bytes, burstLen:fromInteger(8*valueOf(haystackBusBytes)), tag: 0});
      if (verbose) $display("mkMPEngine::search %d %d %d",  haystack_sglId, haystack_base, haystack_len_bytes);
   endrule

   interface PipeIn setsearch = toPipeIn(ssfifo);
   interface PipeOut locdone = toPipeOut(locf);

endmodule

module mkMPStreamEngine(MPStreamEngine#(haystackBusWidth,configBusWidth))

   provisos(Add#(a__, 8, haystackBusWidth),
	    Div#(haystackBusWidth,8,haystackBusBytes),
	    Mul#(haystackBusBytes,8,haystackBusWidth),
	    Add#(1, b__, haystackBusBytes),
	    Add#(c__, 32, haystackBusWidth),
	    Add#(1, d__, TDiv#(haystackBusWidth, 32)),
	    Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth),
	    Add#(e__, TLog#(haystackBusBytes), 32),
	    Add#(f__, TLog#(TDiv#(haystackBusWidth, 32)), 32)
	    ,Mul#(TDiv#(configBusWidth, 8), 8, configBusWidth)
	    ,Add#(1, g__, TDiv#(configBusWidth, 8))
	    ,Add#(h__, TLog#(TDiv#(configBusWidth, 8)), 32)
	    ,Add#(i__, TLog#(TDiv#(configBusWidth, 32)), 32)
	    ,Add#(1, j__, TDiv#(configBusWidth, 32))
	    ,Mul#(TDiv#(configBusWidth, 32), 32, configBusWidth)
	    );

   FIFOF#(Int#(32)) locf <- mkFIFOF;
   FIFO#(Bool) conff <- mkSizedFIFO(1);

   let verbose = True;
   let debug = False;

   Clock clk <- exposeCurrentClock;
   Reset rst <- exposeCurrentReset;
   BRAM2Port#(NeedleIdx, Char) needleBram  <- mkBRAM2Server(defaultValue);
   BRAM2Port#(NeedleIdx, Bit#(32)) mpNextBram <- mkBRAM2Server(defaultValue);
   FIFOF#(MemData#(haystackBusWidth)) haystackFifo <- mkFIFOF();
   Gearbox#(haystackBusBytes,1,Char) haystackGb <- mkNto1Gearbox(clk,rst,clk,rst);

   Reg#(Bit#(32)) cycleCnt <- mkReg(0);
   Reg#(Bit#(32)) lastHD <- mkReg(0);

   Reg#(Stage)    stage <- mkReg(Config_needle);
   Reg#(Bit#(32)) needleLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackLenReg <- mkReg(0);
   Reg#(Bit#(32)) haystackBase <- mkReg(0);
   Reg#(Bit#(32)) jReg <- mkReg(0); // offset in haystack
   Reg#(Bit#(32)) iReg <- mkReg(0); // offset in needle
   Reg#(Bit#(2))  epochReg <- mkReg(0);

   BRAMPipeIn#(NeedleIdxWidth,configBusWidth) n2b <- mkBRAMPipeIn(0, needleBram.portB);
   BRAMPipeIn#(NeedleIdxWidth,configBusWidth) mp2b <- mkBRAMPipeIn(1, mpNextBram.portB);

   FIFOF#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFOF(2);
   FIFO#(void) doneFifo <- mkFIFO;

   rule countCycles;
      if (debug) $display("******************************************** %d", cycleCnt);
      cycleCnt <= cycleCnt+1;
   endrule

   rule haystackResp;
      if (debug) $display("mkMPEngine::haystackResp");
      let rv <- toGet(haystackFifo).get;
      haystackGb.enq(unpack(rv.data));
      if (rv.last)
         conff.deq;
   endrule

   rule haystackDrain(stage != Search);
      if (debug) $display("mkMPEngine::haystackDrain");
      haystackGb.deq;
   endrule

   rule bramDrain(stage != Search);
      if (debug) $display("mkMPEngine::mpNextDrain");
      let x <- mpNextBram.portA.response.get;
      let y <- needleBram.portA.response.get;
      efifo.deq;
   endrule

`define OPTIMIZE_MISMATCH
`ifdef OPTIMIZE_MISMATCH
   rule matchNeedleReq(stage == Search);
      if (debug) $display("mkMPEngine::matchNeedleReq %d %d", epochReg, iReg);
      needleBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      mpNextBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= 1;
   endrule

   rule matchNeedleResp(stage == Search);
      let nv <- needleBram.portA.response.get;
      let mp <- mpNextBram.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (debug) $display("mkMPEngine::matchNeedleResp %d %d", epochReg, epoch);
      if (epoch == epochReg) begin
	 Bool deq_haystack = False;
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystackGb.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (debug) $display("mkMPEngine::feck %d %d %d %d %x %x", n, m, i, j, hv[0], nv);
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    stage <= Config_needle;
	    if (debug) $display("mkMPEngine::end of search %d", j);
	    locf.enq(-1);
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    if (debug) $display("mkMPEngine::string match %d", j);
	    locf.enq(unpack(haystackBase+j-i));
	 end
	 else if (nv != hv[0]) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    if (debug) $display("mkMPEngine::char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    if (mp == 0) begin
	       iReg <= 1;
	       jReg <= j+1;
	       deq_haystack = True;
	    end
	    else begin
	       epochReg <= epochReg + 1;
	       iReg <= mp;
	    end
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    if (debug) $display("mkMPEngine::char match(%d) %d %d", (nv == hv[0]), i, j);
	    deq_haystack = True;
	    jReg <= j+1;
	    epochReg <= epochReg + 1;
	    iReg <= i+1;
	 end
	 if (deq_haystack) begin
	    haystackGb.deq;
	    lastHD <= cycleCnt;
	    if (debug) $display("mkMPEngine:: deq haystack(%d)", cycleCnt-lastHD);
	 end
      end
      else begin
	 if (debug) $display("mkMPEngine::discard");
	 noAction;
      end
   endrule
`else
   rule matchNeedleReq(stage == Search);
      if (debug) $display("mkMPEngine::matchNeedleReq %d %d", epochReg, iReg);
      needleBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg-1), datain:?, responseOnWrite:?});
      mpNextBram.portA.request.put(BRAMRequest{write:False, address: truncate(iReg), datain:?, responseOnWrite:?});
      efifo.enq(tuple2(epochReg,iReg));
      iReg <= iReg+1;
   endrule

   rule matchNeedleResp(stage == Search);
      let nv <- needleBram.portA.response.get;
      let mp <- mpNextBram.portA.response.get;
      let epoch = tpl_1(efifo.first);
      efifo.deq;
      if (debug) $display("mkMPEngine::matchNeedleResp %d %d", epochReg, epoch);
      if (epoch == epochReg) begin
	 Bool deq_haystack = False;
	 let n = haystackLenReg;
	 let m = needleLenReg;
	 let hv = haystack.first;
	 let i = tpl_2(efifo.first);
	 let j = jReg;
	 if (debug) $display("mkMPEngine::feck %d %d %d %d %x %x", n, m, i, j, hv[0], nv);
	 if (j > n) begin
	    // jReg points to the end of the haystack; we are done
	    stage <= Config_needle;
	    if (debug) $display("mkMPEngine::end of search %d", j);
	 end
	 else if (i==m+1) begin
	    // iReg points to the end of the needle; we have a match
	    if (debug) $display("mkMPEngine::string match %d", j);
	    locf.enq(unpack(haystackBase+j-i));
	    epochReg <= epochReg + 1;
	    iReg <= 1;
	 end
	 else if (nv != hv[0]) begin
	    // mismatch betwen head of haystack and head of needle; rewind iReg
	    if (debug) $display("mkMPEngine::char mismatch %d %d MP_Next[i]=%d", i, j, mp);
	    epochReg <= epochReg + 1;
	    if (mp == 0) begin
	       iReg <= 1;
	       jReg <= j+1;
	       deq_haystack = True;
	    end
	    else begin
	       iReg <= mp;
	    end
	 end
	 else begin
	    // match between head of needle and head of haystack; increment haystack
	    if (debug) $display("mkMPEngine::char match(%d) %d %d", (nv == hv[0]), i, j);
	    deq_haystack = True;
	    jReg <= j+1;
	 end
	 if (deq_haystack) begin
	    haystack.deq;
	    lastHD <= cycleCnt;
	    if (debug) $display("mkMPEngine:: deq haystack(%d)", cycleCnt-lastHD);
	 end
      end
      else begin
	 if (debug) $display("mkMPEngine::discard");
	 noAction;
      end
   endrule
`endif

   interface PipeIn needle = n2b.pipe;
   interface PipeIn mpNext = mp2b.pipe;
   interface PipeIn haystack = toPipeIn(haystackFifo);
   interface PipeOut locdone = toPipeOut(locf);

endmodule