modify mac works

modify mac works

// 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 Vector::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import GetPut::*;
import DefaultValue::*;
import Clocks::*;

import PacketBuffer::*;
import MemTypes::*;
import Ethernet::*;
import MemoryAPI::*;
import SharedBuff::*;
import StoreAndForward::*;
import IPv4Parser::*;
import GenericMatchTable::*;

`ifndef SIMULATION
import AlteraMacWrap::*;
import EthMac::*;
import AlteraEthPhy::*;
import DE5Pins::*;
`else
import Sims::*;
`endif

typedef 16 NumOfHosts;
typedef 8 SlotLen;

typedef struct {
   Bit#(TLog#(NumOfHosts)) host;
   Bit#(32) id;
   Bit#(32) dstip;
   Bit#(EtherLen) size;
} FQWriteRequest deriving(Bits, Eq);

typedef struct {
   Bit#(TLog#(NumOfHosts)) host;
} FQReadRequest deriving(Bits, Eq);

typedef struct {
   Bit#(32) id;
   Bit#(32) dstip;
   Bit#(EtherLen) size;
} FQReadResp deriving(Bits, Eq);

typedef struct {
   Bit#(32) id;
   Bool ready;
} FQReady deriving(Bits, Eq);

typedef struct {
   Bit#(32) id;
   Bit#(48) data;
} ModifyMacReq deriving(Bits, Eq);

interface TimeSlot;
   interface Get#(Bit#(TLog#(NumOfHosts))) currSlot;
endinterface

module mkTimeSlot(TimeSlot);
   Reg#(Bit#(32)) global_count <- mkReg(0);
   Reg#(Bit#(TLog#(NumOfHosts))) last_slot <- mkReg(0);
   FIFO#(Bit#(TLog#(NumOfHosts))) slot_fifo <- mkFIFO;

   rule increment;
      global_count <= global_count + 1;
   endrule

   function Bit#(TLog#(NumOfHosts)) get_slot (Bit#(32) v);
      let l = fromInteger(valueOf(TLog#(SlotLen)));
      Vector#(TLog#(NumOfHosts), Bit#(1)) slot = takeAt(l, unpack(v));
      return pack(slot);
   endfunction

   rule genNewSlot;
      let v = get_slot(global_count);
      if (v != last_slot) begin
         slot_fifo.enq(v);
         last_slot <= v;
      end
   endrule

   interface Get currSlot = toGet(slot_fifo);
endmodule

// Write stores packet id to per-host queue for scheduling
// Read returns packet id to be transmitted immediately
interface ForwardQ;
   interface Put#(FQWriteRequest) req_w;
   interface Put#(FQReadRequest) req_r;
   interface Get#(FQReadResp) resp_r;
endinterface

module mkForwardQ(ForwardQ);
   // Forward queue as name implies
   Vector#(NumOfHosts, FIFOF#(FQReadResp)) fwdFifo <- replicateM(mkSizedFIFOF(16));
   // ReadyFifo marks fwdFifo as ready to dequeue
   // It serves as synchronization between queueing and packet modification pipeline
   Vector#(NumOfHosts, FIFOF#(FQReady)) readyFifo <- replicateM(mkSizedFIFOF(16));
   FIFO#(FQReadResp) resp_fifo <- mkFIFO;

   interface Put req_w;
      method Action put(FQWriteRequest req);
         let hostIdx = req.host;
         fwdFifo[hostIdx].enq(FQReadResp{id: req.id, dstip: req.dstip, size: req.size});
      endmethod
   endinterface
   interface Put req_r;
      method Action put(FQReadRequest req);
         let hostIdx = req.host;
         if (fwdFifo[hostIdx].notEmpty) begin
            let v = fwdFifo[hostIdx].first;
            resp_fifo.enq(FQReadResp{id: v.id, dstip: v.dstip, size: v.size});
            fwdFifo[hostIdx].deq;
         end
         else begin
            if (fwdFifo[0].notEmpty) begin
               let v = fwdFifo[0].first;
               resp_fifo.enq(FQReadResp{id: v.id, dstip: v.dstip, size: v.size});
               fwdFifo[0].deq;
            end
         end
      endmethod
   endinterface
   interface Get resp_r = toGet(resp_fifo);
endmodule

interface ModifyMac;
   interface Put#(ModifyMacReq) request;
   interface Get#(Bit#(MemTagSize)) done;
   interface MemWriteClient#(`DataBusWidth) writeClient;
endinterface
module mkModifyMac(ModifyMac);
   let verbose = True;
   FIFO#(ModifyMacReq) modifyMacReqFifo <- mkFIFO;

   // Memory Client
   FIFO#(MemRequest) writeReqFifo <- mkSizedFIFO(4);
   FIFO#(MemData#(`DataBusWidth)) writeDataFifo <- mkSizedFIFO(16);
   FIFO#(Bit#(MemTagSize)) writeDoneFifo <- mkSizedFIFO(4);
   MemWriteClient#(`DataBusWidth) dmaWriteClient = (interface MemWriteClient;
   interface Get writeReq = toGet(writeReqFifo);
   interface Get writeData = toGet(writeDataFifo);
   interface Put writeDone = toPut(writeDoneFifo);
   endinterface);

   rule modifyMacAddress;
      let req <- toGet(modifyMacReqFifo).get;
      // FIXME: busrtLen must be multiple of 16..
      if(verbose) $display("TDM:: modifyMac %h ", req.id);
      writeReqFifo.enq(MemRequest {sglId: req.id, offset: 0,
                                   burstLen: 'h10, tag: 0
`ifdef BYTE_ENABLES
                                   , firstbe: 'hffff, lastbe: 'h003f
`endif
                                  });
      writeDataFifo.enq(MemData{data: extend(req.data), tag:0, last: True});
   endrule

   interface Put request= toPut(modifyMacReqFifo);
   interface Get done = toGet(writeDoneFifo);
   interface writeClient = dmaWriteClient;
endmodule

interface TDM;
   // To Rings, doubt if we need these.
   interface Vector#(4, PktWriteClient) writeClients;
   // From Rings, doubt if we need these.
   interface Vector#(4, PktReadServer) readServers;
endinterface

module mkTDM#(StoreAndFwdFromRingToMem ingress, StoreAndFwdFromMemToRing egress, Parser parser, MatchTable matchTable, ModifyMac modMac)(TDM);

   FIFOF#(FQWriteRequest) ingress_fifo <- mkSizedFIFOF(16);
   FIFOF#(FQWriteRequest) egress_fifo <- mkSizedFIFOF(16);

   let verbose = True;
   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule cycleRule if (verbose);
      cycle <= cycle + 1;
   endrule

   TimeSlot timeSlot <- mkTimeSlot();
   ForwardQ fwdq <- mkForwardQ();

   // packet processing pipeline: ingress
   rule tableLookupResp;
      let v <- matchTable.lookupPort.response.get;
      $display("TDM:: bcam matches %h", v);
      let req <- toGet(ingress_fifo).get;
      // assume logic is table match implies forward
      modMac.request.put(ModifyMacReq{id: req.id, data:'h123456789abc});
      egress_fifo.enq(req);
   endrule

   // packet processing pipelie: egress
   rule modifyMacResp;
      let req <- toGet(egress_fifo).get;
      let v <- modMac.done.get;
      $display("TDM:: modifyMac done %h", v);
      fwdq.req_w.put(req);
   endrule

   //! Function: ipToIndex
   //! Currently, take low-order bits as indices
   rule enqueuePacketInstance;
      let v <- ingress.eventPktCommitted.get;
      let ipv4 <- toGet(parser.parsedOut_ipv4_dstAddr).get;
      if (verbose) $display("TDM:: %d enqueuePkt: %h %h %h", cycle, v.id, v.size, ipv4);
      // Enqueue data for processing.
      matchTable.lookupPort.request.put(MatchField{dstip:ipv4});
      ingress_fifo.enq(FQWriteRequest{host: truncate(ipv4), id: v.id,
                                  dstip: ipv4, size: v.size});
   endrule

   rule slotRequest;
      let slot <- timeSlot.currSlot.get;
      fwdq.req_r.put(FQReadRequest{host:slot});
   endrule

   rule dequeuePacketInstance;
      let resp <- fwdq.resp_r.get;
      egress.eventPktSend.put(PacketInstance{id: resp.id, size: resp.size});
      if (verbose) $display("TDM:: %d dequeuePkt: %h %h", cycle, resp.id, resp.size);
      if (verbose) $display("TDM:: %d dequeuePkt: %h", cycle, resp.dstip);
   endrule
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 Vector::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import GetPut::*;
import DefaultValue::*;
import Clocks::*;

import PacketBuffer::*;
import MemTypes::*;
import Ethernet::*;
import MemoryAPI::*;
import SharedBuff::*;
import StoreAndForward::*;
import IPv4Parser::*;
import GenericMatchTable::*;

`ifndef SIMULATION
import AlteraMacWrap::*;
import EthMac::*;
import AlteraEthPhy::*;
import DE5Pins::*;
`else
import Sims::*;
`endif

typedef 16 NumOfHosts;
typedef 8 SlotLen;

typedef struct {
   Bit#(TLog#(NumOfHosts)) host;
   Bit#(32) id;
   Bit#(32) dstip;
   Bit#(EtherLen) size;
} FQWriteRequest deriving(Bits, Eq);

typedef struct {
   Bit#(TLog#(NumOfHosts)) host;
} FQReadRequest deriving(Bits, Eq);

typedef struct {
   Bit#(32) id;
   Bit#(32) dstip;
   Bit#(EtherLen) size;
} FQReadResp deriving(Bits, Eq);

typedef struct {
   Bit#(32) id;
   Bool ready;
} FQReady deriving(Bits, Eq);

typedef struct {
   Bit#(32) id;
   Bit#(48) data;
} ModifyMacReq deriving(Bits, Eq);

interface TimeSlot;
   interface Get#(Bit#(TLog#(NumOfHosts))) currSlot;
endinterface

module mkTimeSlot(TimeSlot);
   Reg#(Bit#(32)) global_count <- mkReg(0);
   Reg#(Bit#(TLog#(NumOfHosts))) last_slot <- mkReg(0);
   FIFO#(Bit#(TLog#(NumOfHosts))) slot_fifo <- mkFIFO;

   rule increment;
      global_count <= global_count + 1;
   endrule

   function Bit#(TLog#(NumOfHosts)) get_slot (Bit#(32) v);
      let l = fromInteger(valueOf(TLog#(SlotLen)));
      Vector#(TLog#(NumOfHosts), Bit#(1)) slot = takeAt(l, unpack(v));
      return pack(slot);
   endfunction

   rule genNewSlot;
      let v = get_slot(global_count);
      if (v != last_slot) begin
         slot_fifo.enq(v);
         last_slot <= v;
      end
   endrule

   interface Get currSlot = toGet(slot_fifo);
endmodule

// Write stores packet id to per-host queue for scheduling
// Read returns packet id to be transmitted immediately
interface ForwardQ;
   interface Put#(FQWriteRequest) req_w;
   interface Put#(FQReadRequest) req_r;
   interface Get#(FQReadResp) resp_r;
endinterface

module mkForwardQ(ForwardQ);
   // Forward queue as name implies
   Vector#(NumOfHosts, FIFOF#(FQReadResp)) fwdFifo <- replicateM(mkSizedFIFOF(16));
   // ReadyFifo marks fwdFifo as ready to dequeue
   // It serves as synchronization between queueing and packet modification pipeline
   Vector#(NumOfHosts, FIFOF#(FQReady)) readyFifo <- replicateM(mkSizedFIFOF(16));
   FIFO#(FQReadResp) resp_fifo <- mkFIFO;

   interface Put req_w;
      method Action put(FQWriteRequest req);
         let hostIdx = req.host;
         fwdFifo[hostIdx].enq(FQReadResp{id: req.id, dstip: req.dstip, size: req.size});
      endmethod
   endinterface
   interface Put req_r;
      method Action put(FQReadRequest req);
         let hostIdx = req.host;
         if (fwdFifo[hostIdx].notEmpty) begin
            let v = fwdFifo[hostIdx].first;
            resp_fifo.enq(FQReadResp{id: v.id, dstip: v.dstip, size: v.size});
            fwdFifo[hostIdx].deq;
         end
         else begin
            if (fwdFifo[0].notEmpty) begin
               let v = fwdFifo[0].first;
               resp_fifo.enq(FQReadResp{id: v.id, dstip: v.dstip, size: v.size});
               fwdFifo[0].deq;
            end
         end
      endmethod
   endinterface
   interface Get resp_r = toGet(resp_fifo);
endmodule

interface ModifyMac;
   interface Put#(ModifyMacReq) request;
   interface Get#(Bit#(MemTagSize)) done;
   interface MemWriteClient#(`DataBusWidth) writeClient;
endinterface
module mkModifyMac(ModifyMac);
   let verbose = True;
   FIFO#(ModifyMacReq) modifyMacReqFifo <- mkFIFO;

   // Memory Client
   FIFO#(MemRequest) writeReqFifo <- mkSizedFIFO(4);
   FIFO#(MemData#(`DataBusWidth)) writeDataFifo <- mkSizedFIFO(16);
   FIFO#(Bit#(MemTagSize)) writeDoneFifo <- mkSizedFIFO(4);
   MemWriteClient#(`DataBusWidth) dmaWriteClient = (interface MemWriteClient;
   interface Get writeReq = toGet(writeReqFifo);
   interface Get writeData = toGet(writeDataFifo);
   interface Put writeDone = toPut(writeDoneFifo);
   endinterface);

   rule modifyMacAddress;
      let req <- toGet(modifyMacReqFifo).get;
      // FIXME: offset and mask
      if(verbose) $display("TDM:: modifyMac %h", req.id);
      writeReqFifo.enq(MemRequest {sglId: req.id, offset: 0,
                                   burstLen: 1, tag: 0
`ifdef BYTE_ENABLES
                                   , firstbe: 'hffff, lastbe: 'hffff
`endif
                                  });
      writeDataFifo.enq(MemData{data: extend(req.data), tag:0, last: True});
   endrule

   interface Put request= toPut(modifyMacReqFifo);
   interface Get done = toGet(writeDoneFifo);
   interface writeClient = dmaWriteClient;
endmodule

interface TDM;
   // To Rings, doubt if we need these.
   interface Vector#(4, PktWriteClient) writeClients;
   // From Rings, doubt if we need these.
   interface Vector#(4, PktReadServer) readServers;
endinterface

module mkTDM#(StoreAndFwdFromRingToMem ingress, StoreAndFwdFromMemToRing egress, Parser parser, MatchTable matchTable, ModifyMac modMac)(TDM);

   FIFOF#(FQWriteRequest) ingress_fifo <- mkSizedFIFOF(16);
   FIFOF#(FQWriteRequest) egress_fifo <- mkSizedFIFOF(16);

   let verbose = True;
   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule cycleRule if (verbose);
      cycle <= cycle + 1;
   endrule

   TimeSlot timeSlot <- mkTimeSlot();
   ForwardQ fwdq <- mkForwardQ();

   // packet processing pipeline: ingress
   rule tableLookupResp;
      let v <- matchTable.lookupPort.response.get;
      $display("TDM:: bcam matches %h", v);
      let req <- toGet(ingress_fifo).get;
      // assume logic is table match implies forward
      modMac.request.put(ModifyMacReq{id: req.id, data:'h123456789abc });
      egress_fifo.enq(req);
   endrule

   // packet processing pipelie: egress
   rule modifyMacResp;
      let req <- toGet(egress_fifo).get;
      let v <- modMac.done.get;
      $display("TDM:: modifyMac done %h", v);
      fwdq.req_w.put(req);
   endrule

   //! Function: ipToIndex
   //! Currently, take low-order bits as indices
   rule enqueuePacketInstance;
      let v <- ingress.eventPktCommitted.get;
      let ipv4 <- toGet(parser.parsedOut_ipv4_dstAddr).get;
      if (verbose) $display("TDM:: %d enqueuePkt: %h %h %h", cycle, v.id, v.size, ipv4);
      // Enqueue data for processing.
      matchTable.lookupPort.request.put(MatchField{dstip:ipv4});
      ingress_fifo.enq(FQWriteRequest{host: truncate(ipv4), id: v.id,
                                  dstip: ipv4, size: v.size});
   endrule

   rule slotRequest;
      let slot <- timeSlot.currSlot.get;
      fwdq.req_r.put(FQReadRequest{host:slot});
   endrule

   rule dequeuePacketInstance;
      let resp <- fwdq.resp_r.get;
      egress.eventPktSend.put(PacketInstance{id: resp.id, size: resp.size});
      if (verbose) $display("TDM:: %d dequeuePkt: %h %h", cycle, resp.id, resp.size);
      if (verbose) $display("TDM:: %d dequeuePkt: %h", cycle, resp.dstip);
   endrule
endmodule


handle all read requests in the rule

handle all read requests in the rule

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

// bsv libraries
import Vector::*;
import FIFO::*;
import FIFOF::*;
import RegFile::*;
import SpecialFIFOs::*;
import GetPut::*;
import BRAM::*;
import Assert::*;

//portz libraries
import Portal::*;
import MemTypes::*;
import Ctrl2BRAM::*;

interface Directory#(numeric type _n,
		     numeric type _a,
		     numeric type _d);
   interface MemPortal#(_a,_d) portalIfc;
endinterface

typedef Directory#(16,16,32) StdDirectory;

typedef 6 StartDirectoryOffset;

module mkStdDirectoryPortalIfc#(BRAMServer#(Bit#(16), Bit#(32)) br)(StdPortal);
   MemSlave#(16,32) ctrl <- mkCtrl2BRAM(br);
   method Bit#(32) ifcId();
      return 0;
   endmethod
   method Bit#(32) ifcType();
      return 0;
   endmethod
   interface MemSlave slave = ctrl;
   interface ReadOnly interrupt;
      method Bool _read;
	 return False;
      endmethod
   endinterface
endmodule

module mkStdDirectory#(Vector#(n,StdPortal) portals) (StdDirectory);

   Reg#(Bit#(64)) cycle_count <- mkReg(0);
   Reg#(Bit#(32))    snapshot <- mkReg(0);
   FIFOF#(Bit#(16))  addrFifo <- mkFIFOF1();
   FIFO#(Bit#(32))   dataFifo <- mkFIFO1();
   let startDirectoryOffset=valueOf(StartDirectoryOffset);

   let base = 128;

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   rule handle_read;
      let addr <- toGet(addrFifo).get();
      if (addr < 6+base) begin
	 if (addr == 0+base)
	    dataFifo.enq(2); // directory version
	 else if (addr == 1+base)
	    dataFifo.enq(0); // remove timestamp from builds, so that they are reproducable. `TimeStamp);
	 else if (addr == 2+base)
	    dataFifo.enq(fromInteger(valueOf(n)));
	 else if (addr == 3+base)
	    dataFifo.enq(16); // portal Addr bits
	 else if (addr == 4+base) begin
	    snapshot <= truncate(cycle_count);
	    dataFifo.enq(cycle_count[63:32]);
	 end
	 else if (addr == 5+base)
	    dataFifo.enq(snapshot);
      end
      else begin
	  let idx = (addr-fromInteger(startDirectoryOffset)-base);
	  if (idx[0] == 0)
	     dataFifo.enq(portals[idx>>1].ifcId);
	  else
	     dataFifo.enq(portals[idx>>1].ifcType);
      end
   endrule

   let br = (interface BRAMServer#(Bit#(16), Bit#(32));
		interface Put request;
		   method Action put(BRAMRequest#(Bit#(16),Bit#(32)) req) if (!addrFifo.notEmpty);
		      if (!req.write) begin
			 addrFifo.enq(truncate(req.address));
		      end
		   endmethod
		endinterface
		interface Get response;
		   method ActionValue#(Bit#(32)) get;
		      dataFifo.deq;
		      return dataFifo.first;
      		   endmethod
		endinterface
      	     endinterface);
   let ifc <- mkStdDirectoryPortalIfc(br);
   interface StdPortal portalIfc = 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.

// bsv libraries
import Vector::*;
import FIFO::*;
import FIFOF::*;
import RegFile::*;
import SpecialFIFOs::*;
import GetPut::*;
import BRAM::*;
import Assert::*;

//portz libraries
import Portal::*;
import MemTypes::*;
import Ctrl2BRAM::*;

interface Directory#(numeric type _n,
		     numeric type _a,
		     numeric type _d);
   interface MemPortal#(_a,_d) portalIfc;
endinterface

typedef Directory#(16,16,32) StdDirectory;

typedef 6 StartDirectoryOffset;

module mkStdDirectoryPortalIfc#(BRAMServer#(Bit#(16), Bit#(32)) br)(StdPortal);
   MemSlave#(16,32) ctrl <- mkCtrl2BRAM(br);
   method Bit#(32) ifcId();
      return 0;
   endmethod
   method Bit#(32) ifcType();
      return 0;
   endmethod
   interface MemSlave slave = ctrl;
   interface ReadOnly interrupt;
      method Bool _read;
	 return False;
      endmethod
   endinterface
endmodule

module mkStdDirectory#(Vector#(n,StdPortal) portals) (StdDirectory);

   Reg#(Bit#(64)) cycle_count <- mkReg(0);
   Reg#(Bit#(32))    snapshot <- mkReg(0);
   FIFOF#(Bit#(16))  addrFifo <- mkSizedFIFOF(1);
   FIFO#(Bit#(32))   dataFifo <- mkSizedFIFO(1);
   let startDirectoryOffset=valueOf(StartDirectoryOffset);

   let base = 128;

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   rule req1;
      let addr = addrFifo.first;
      addrFifo.deq;
      let idx = (addr-fromInteger(startDirectoryOffset)-base);
      if (idx[0] == 0)
	 dataFifo.enq(portals[idx>>1].ifcId);
      else
	 dataFifo.enq(portals[idx>>1].ifcType);
   endrule

   let br = (interface BRAMServer#(Bit#(16), Bit#(32));
		interface Put request;
		   method Action put(BRAMRequest#(Bit#(16),Bit#(32)) req) if (!addrFifo.notEmpty);
		      if (!req.write) begin
      			 if (req.address == 0+base)
			    dataFifo.enq(2); // directory version
			 else if (req.address == 1+base)
			    dataFifo.enq(0); // remove timestamp from builds, so that they are reproducable. `TimeStamp);
			 else if (req.address == 2+base)
			    dataFifo.enq(fromInteger(valueOf(n)));
			 else if (req.address == 3+base)
			    dataFifo.enq(16); // portal Addr bits
			 else if (req.address == 4+base) begin
			    snapshot <= truncate(cycle_count);
			    dataFifo.enq(cycle_count[63:32]);
			 end
			 else if (req.address == 5+base)
			    dataFifo.enq(snapshot);
			 else begin
			    addrFifo.enq(truncate(req.address));
			 end
		      end
		   endmethod
		endinterface
		interface Get response;
		   method ActionValue#(Bit#(32)) get;
		      dataFifo.deq;
		      return dataFifo.first;
      		   endmethod
		endinterface
      	     endinterface);
   let ifc <- mkStdDirectoryPortalIfc(br);
   interface StdPortal portalIfc = ifc;
endmodule


shortening the burst-length specified in MPEngine, and change the expression so it causes a compile error if the value is too large to fit in the allocated bits

// 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#(Tripple#(Bit#(32))) setsearch;
   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#(MemreadServer#(haystackBusWidth) haystackReader,
		   MemreadServer#(configBusWidth) configReader) (MPEngine#(haystackBusWidth,configBusWidth))

   provisos(Add#(a__, 8, haystackBusWidth),
	    Div#(haystackBusWidth,8,nc),
	    Mul#(nc,8,haystackBusWidth),
	    Add#(1, b__, nc),
	    Add#(c__, 32, haystackBusWidth),
	    Add#(1, d__, TDiv#(haystackBusWidth, 32)),
	    Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth),
	    Add#(e__, TLog#(nc), 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#(nc,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.cmdServer, configReader.dataPipe);
   BRAMWriter#(NeedleIdxWidth,configBusWidth) mp2b <- mkBRAMWriter(1, mpNext.portB, configReader.cmdServer, configReader.dataPipe);

   FIFOF#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFOF(2);
   FIFOF#(Tripple#(Bit#(32))) ssfifo <- mkFIFOF;

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

   rule haystackResp;
      if (debug) $display("mkMPEngine::haystackResp");
      let rv <- toGet(haystackReader.dataPipe).get;
      haystack.enq(unpack(rv));
   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 finish_search;
      let rv <- haystackReader.cmdServer.response.get;
      conff.deq;
      if (verbose) $display("mkMPEngine::finish_search");
   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(nc)-1);
      Bit#(TLog#(nc)) zeros = 0;
      Bit#(32) haystack_len_bytes = {zeros,haystack_len_ds[31:valueOf(TLog#(nc))]} * fromInteger(valueOf(nc));
      haystackReader.cmdServer.request.put(MemengineCmd{sglId:haystack_sglId, base:extend(haystack_base), len:haystack_len_bytes, burstLen:fromInteger(8*valueOf(nc))});
      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

// 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#(Tripple#(Bit#(32))) setsearch;
   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#(MemreadServer#(haystackBusWidth) haystackReader,
		   MemreadServer#(configBusWidth) configReader) (MPEngine#(haystackBusWidth,configBusWidth))

   provisos(Add#(a__, 8, haystackBusWidth),
	    Div#(haystackBusWidth,8,nc),
	    Mul#(nc,8,haystackBusWidth),
	    Add#(1, b__, nc),
	    Add#(c__, 32, haystackBusWidth),
	    Add#(1, d__, TDiv#(haystackBusWidth, 32)),
	    Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth),
	    Add#(e__, TLog#(nc), 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#(nc,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.cmdServer, configReader.dataPipe);
   BRAMWriter#(NeedleIdxWidth,configBusWidth) mp2b <- mkBRAMWriter(1, mpNext.portB, configReader.cmdServer, configReader.dataPipe);

   FIFOF#(Tuple2#(Bit#(2),Bit#(32))) efifo <- mkSizedFIFOF(2);
   FIFOF#(Tripple#(Bit#(32))) ssfifo <- mkFIFOF;

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

   rule haystackResp;
      if (debug) $display("mkMPEngine::haystackResp");
      let rv <- toGet(haystackReader.dataPipe).get;
      haystack.enq(unpack(rv));
   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 finish_search;
      let rv <- haystackReader.cmdServer.response.get;
      conff.deq;
      if (verbose) $display("mkMPEngine::finish_search");
   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(nc)-1);
      Bit#(TLog#(nc)) zeros = 0;
      Bit#(32) haystack_len_bytes = {zeros,haystack_len_ds[31:valueOf(TLog#(nc))]} * fromInteger(valueOf(nc));
      haystackReader.cmdServer.request.put(MemengineCmd{sglId:haystack_sglId, base:extend(haystack_base), len:haystack_len_bytes, burstLen:16*fromInteger(valueOf(nc))});
      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


fix bug in satd[8x8] (lack sum of 8 rows); new feature input 2 of 8x8 as 16x8

// Copyright (c) 2016-2017 Min Chen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

import ConfigReg::*;
import Vector::*;
import GetPut::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BUtils::*;

interface ISatd8;
   interface Put#(Vector#(8, Bit#(9))) inp;
   interface Get#(Bit#(19)) oup;
endinterface

interface ISatd8x2;
   interface Put#(Vector#(16, Bit#(9))) inp;
   interface Get#(Vector#(2, Bit#(19))) oup;
endinterface

function Vector#(8, Bit#(na)) satd_1d(Vector#(8, Bit#(n)) x)
   provisos(
      Add#(n, 3, na)
   );
   Vector#(8, Bit#(na)) m0;
   Vector#(8, Bit#(na)) m1;
   Vector#(8, Bit#(na)) m2;

   m0[0] = sExtend(x[0]) + sExtend(x[4]);
   m0[1] = sExtend(x[1]) + sExtend(x[5]);
   m0[2] = sExtend(x[2]) + sExtend(x[6]);
   m0[3] = sExtend(x[3]) + sExtend(x[7]);
   m0[4] = sExtend(x[0]) - sExtend(x[4]);
   m0[5] = sExtend(x[1]) - sExtend(x[5]);
   m0[6] = sExtend(x[2]) - sExtend(x[6]);
   m0[7] = sExtend(x[3]) - sExtend(x[7]);

   m1[0] = m0[0] + m0[2];
   m1[1] = m0[1] + m0[3];
   m1[2] = m0[0] - m0[2];
   m1[3] = m0[1] - m0[3];
   m1[4] = m0[4] + m0[6];
   m1[5] = m0[5] + m0[7];
   m1[6] = m0[4] - m0[6];
   m1[7] = m0[5] - m0[7];

   m2[0] = m0[0] + m0[1];
   m2[1] = m0[0] - m0[1];
   m2[2] = m0[2] + m0[3];
   m2[3] = m0[2] - m0[3];
   m2[4] = m0[4] + m0[5];
   m2[5] = m0[4] - m0[5];
   m2[6] = m0[6] + m0[7];
   m2[7] = m0[6] - m0[7];

   return m2;
endfunction

(* synthesize *)
module mkSatd8(ISatd8);
   FIFOF#(Vector#(8, Bit#(9)))               fifo_inp    <- mkPipelineFIFOF;
   FIFOF#(Bit#(19))                          fifo_out    <- mkPipelineFIFOF;

   RWire#(Vector#(8, Bit#(12)))              rw_trans    <- mkRWire;
   RWire#(Bool)                              rw_oflag    <- mkRWire;

   Reg#(Bit#(8))                             flags       <- mkConfigReg(0);
   Reg#(Bool)                                dir         <- mkConfigReg(True);
   Vector#(8, Reg#(Vector#(8, Bit#(12))))    matrix      <- replicateM(mkConfigRegU);

   Reg#(Bit#(3))                             sum_cnt     <- mkReg(0);
   Reg#(Bit#(21))                            sum_satd    <- mkReg(0);

   rule shift_matrix(isValid(rw_trans.wget) || flags[7] != 0);
      let x = fromMaybe(?, rw_trans.wget);
      let y = isValid(rw_trans.wget) ? 1 : 0;

      if (dir) begin
         // Row shift
         for(Integer i = 0; i < 8 - 1; i = i + 1) begin
            matrix[i] <= matrix[i + 1];
         end
         matrix[8 - 1] <= x;
      end
      else begin
         // Column shift
         for(Integer i = 0; i < 8; i = i + 1) begin
            matrix[i] <= shiftInAtN(matrix[i], x[i]);
         end
      end

      let next_flags = (flags << 1) + y;
      flags <= next_flags;
      if (next_flags == 8'b1111_1111)
         dir <= !dir;
   endrule

   rule do_2d(flags[7] != 0);
      Vector#(8, Bit#(12)) tmp = ?;

      // Get 2D SATD data
      if (dir) begin
         tmp = matrix[0];
      end
      else begin
         for(Integer i = 0; i < 8; i = i + 1) begin
            tmp[i] = matrix[i][0];
         end
      end

      // 2D Transform
      let x = satd_1d(tmp);

      // Sum of row
      Bit#(16) sum = 0;

      for(Integer i = 0; i < 8; i = i + 1) begin
         Int#(15) v = unpack(x[i]);
         sum = sum + zExtend(pack(abs(v)));
      end

      // Sum 8 rows to final value
      let next_sum_satd = sum_satd + zExtend(sum);

      if (sum_cnt == 3'b111) begin
         let y = truncate((next_sum_satd + 2) >> 2);
         fifo_out.enq(y);
         next_sum_satd = 0;
      end
      sum_satd <= next_sum_satd;
      sum_cnt <= sum_cnt + 1;
   endrule

   rule do_1d(fifo_inp.notEmpty());
      let x = fifo_inp.first;
      fifo_inp.deq;

      let y = satd_1d(x);

      rw_trans.wset(y);
   endrule

   interface Put inp = toPut(fifo_inp);
   interface Get oup = toGet(fifo_out);
endmodule

(* synthesize *)
module mkSatd8x2(ISatd8x2);
   ISatd8   satd0    <- mkSatd8;
   ISatd8   satd1    <- mkSatd8;

   interface Put inp = interface Put;
                          method Action put(Vector#(16, Bit#(9)) x);
                             Vector#(2, Vector#(8, Bit#(9))) y = unpack(pack(x));
                             satd0.inp.put(y[0]);
                             satd1.inp.put(y[1]);
                          endmethod
                       endinterface;

   interface Get oup = interface Get;
                          method ActionValue#(Vector#(2, Bit#(19))) get();
                             let x0 <- satd0.oup.get();
                             let x1 <- satd1.oup.get();
                             Vector#(2, Bit#(19)) y = unpack({x0, x1});
                             return y;
                          endmethod
                       endinterface;
endmodule

// Copyright (c) 2016-2017 Min Chen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

import ConfigReg::*;
import Vector::*;
import GetPut::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BUtils::*;

interface ISatd8;
   interface Put#(Vector#(8, Bit#(9))) inp;
   interface Get#(Bit#(16)) oup;
endinterface

function Vector#(8, Bit#(na)) satd_1d(Vector#(8, Bit#(n)) x)
   provisos(
      Add#(n, 3, na)
   );
   Vector#(8, Bit#(na)) m0;
   Vector#(8, Bit#(na)) m1;
   Vector#(8, Bit#(na)) m2;

   m0[0] = sExtend(x[0]) + sExtend(x[4]);
   m0[1] = sExtend(x[1]) + sExtend(x[5]);
   m0[2] = sExtend(x[2]) + sExtend(x[6]);
   m0[3] = sExtend(x[3]) + sExtend(x[7]);
   m0[4] = sExtend(x[0]) - sExtend(x[4]);
   m0[5] = sExtend(x[1]) - sExtend(x[5]);
   m0[6] = sExtend(x[2]) - sExtend(x[6]);
   m0[7] = sExtend(x[3]) - sExtend(x[7]);

   m1[0] = m0[0] + m0[2];
   m1[1] = m0[1] + m0[3];
   m1[2] = m0[0] - m0[2];
   m1[3] = m0[1] - m0[3];
   m1[4] = m0[4] + m0[6];
   m1[5] = m0[5] + m0[7];
   m1[6] = m0[4] - m0[6];
   m1[7] = m0[5] - m0[7];

   m2[0] = m0[0] + m0[1];
   m2[1] = m0[0] - m0[1];
   m2[2] = m0[2] + m0[3];
   m2[3] = m0[2] - m0[3];
   m2[4] = m0[4] + m0[5];
   m2[5] = m0[4] - m0[5];
   m2[6] = m0[6] + m0[7];
   m2[7] = m0[6] - m0[7];

   return m2;
endfunction

(* synthesize *)
module mkSatd8(ISatd8);
   FIFOF#(Vector#(8, Bit#(9)))               fifo_inp    <- mkPipelineFIFOF;
   FIFOF#(Bit#(16))                          fifo_out    <- mkPipelineFIFOF;

   RWire#(Vector#(8, Bit#(12)))              rw_trans    <- mkRWire;
   RWire#(Bool)                              rw_oflag    <- mkRWire;

   Reg#(Bit#(8))                             flags       <- mkConfigReg(0);
   Reg#(Bool)                                dir         <- mkConfigReg(True);
   Vector#(8, Reg#(Vector#(8, Bit#(12))))    matrix      <- replicateM(mkConfigRegU);

   rule shift_matrix(isValid(rw_trans.wget) || flags[7] != 0);
      let x = fromMaybe(?, rw_trans.wget);
      let y = isValid(rw_trans.wget) ? 1 : 0;

      if (dir) begin
         // Row shift
         for(Integer i = 0; i < 8 - 1; i = i + 1) begin
            matrix[i] <= matrix[i + 1];
         end
         matrix[8 - 1] <= x;
      end
      else begin
         // Column shift
         for(Integer i = 0; i < 8; i = i + 1) begin
            matrix[i] <= shiftInAtN(matrix[i], x[i]);
         end
      end

      let next_flags = (flags << 1) + y;
      flags <= next_flags;
      if (next_flags == 8'b1111_1111)
         dir <= !dir;
   endrule

   rule do_2d(flags[7] != 0);
      Vector#(8, Bit#(12)) tmp = ?;

      if (dir) begin
         tmp = matrix[0];
      end
      else begin
         for(Integer i = 0; i < 8; i = i + 1) begin
            tmp[i] = matrix[i][0];
         end
      end
      let x = satd_1d(tmp);
      Bit#(16) sum = 0;

      for(Integer i = 0; i < 8; i = i + 1) begin
         Int#(15) v = unpack(x[i]);
         sum = sum + zExtend(pack(abs(v)));
      end

      fifo_out.enq(sum);
   endrule

   rule do_1d(fifo_inp.notEmpty());
      let x = fifo_inp.first;
      fifo_inp.deq;

      let y = satd_1d(x);

      rw_trans.wset(y);
   endrule

   interface Put inp = toPut(fifo_inp);
   interface Get oup = toGet(fifo_out);
endmodule