From AXI spec, VALID signals should not depend on READY signals. FIFO based solution is used to break combinatorial loops for BVALID/RVALID from BREADY/RREADY,

// Copyright (c) 2015 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 Vector::*;
import PPS7LIB::*;
import AxiMasterSlave::*;
import Axi4MasterSlave::*;
import AxiBits::*;
import GetPutM::*;
import FIFOF::*;

instance ToPutM#(AxiMasterBits#(addrWidth,dataWidth,tagWidth,Empty), Axi3ReadResponse#(dataWidth, tagWidth));
   module toPutM#(AxiMasterBits#(addrWidth, dataWidth, tagWidth, Empty) m)(Put#(Axi3ReadResponse#(dataWidth, tagWidth)));
      FIFOF#(Axi3ReadResponse#(dataWidth, tagWidth)) dfifo <- mkFIFOF();

      rule handshake;
          m.rvalid(pack(dfifo.notEmpty()));
      endrule

      rule deq if (unpack(m.rready()));
          let d = dfifo.first;
          m.rid(d.id);
          m.rresp(d.resp);
          m.rdata(d.data);
          m.rlast(d.last);
          dfifo.deq;
      endrule

      return toPut(dfifo);
   endmodule
endinstance

instance ToPutM#(AxiMasterBits#(addrWidth,dataWidth,tagWidth,Empty), Axi3WriteResponse#(tagWidth));
   module toPutM#(AxiMasterBits#(addrWidth, dataWidth, tagWidth, Empty) m)(Put#(Axi3WriteResponse#(tagWidth)));
      FIFOF#(Axi3WriteResponse#(tagWidth)) dfifo <- mkFIFOF();

      rule handshake;
          m.bvalid(pack(dfifo.notEmpty()));
      endrule

      rule deq if (unpack(m.rready()));
          let d = dfifo.first;
          m.bid(d.id);
          m.bresp(d.resp);
          dfifo.deq;
      endrule

      return toPut(dfifo);
   endmodule
endinstance

interface AxiMasterCommon#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth);
    method Bit#(1)            aresetn();
    interface Axi3Master#(addrWidth,dataWidth,tagWidth) client;
endinterface

interface AxiSlaveCommon#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(1)            aresetn();
    interface Axi3Slave#(addrWidth,dataWidth,tagWidth) server;
    interface extraType   extra;
endinterface

interface Axi4SlaveCommon#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(1)            aresetn();
    interface Axi4Slave#(addrWidth,dataWidth,tagWidth) server;
    interface extraType   extra;
endinterface

module mkAxi3MasterGather#(AxiMasterBits#(addrWidth, dataWidth, tagWidth, Empty) axiWires)(AxiMasterCommon#(addrWidth, dataWidth, tagWidth));
   Wire#(Bit#(1)) arready <- mkDWire(0);
   Wire#(Bit#(1)) awready <- mkDWire(0);
   Wire#(Bit#(1)) rvalid <- mkDWire(0);
   Wire#(Bit#(1)) wready <- mkDWire(0);
   Wire#(Bit#(tagWidth)) rid <- mkDWire(0);
   Wire#(Bit#(2)) rresp <- mkDWire(0);
   Wire#(Bit#(dataWidth)) rdata <- mkDWire(0);
   Wire#(Bit#(1)) rlast <- mkDWire(0);
   Wire#(Bit#(1)) bvalid <- mkDWire(0);
   Wire#(Bit#(tagWidth)) bid <- mkDWire(0);
   Wire#(Bit#(2)) bresp <- mkDWire(0);

   rule handshake1;
        axiWires.arready(arready);
   endrule
   rule handshake2;
        axiWires.awready(awready);
   endrule
   rule handshake4;
        axiWires.wready(wready);
   endrule

   // rule handshake 3 & 5 done in toPutM modules
   Put#(Axi3ReadResponse#(dataWidth, tagWidth)) resp_read_put <- toPutM(axiWires);
   Put#(Axi3WriteResponse#(tagWidth)) resp_b_put <- toPutM(axiWires);

   interface Axi3Master client;
        interface Get req_ar;
             method ActionValue#(Axi3ReadRequest#(addrWidth,tagWidth)) get() if (axiWires.arvalid() != 0);
                 Axi3ReadRequest#(addrWidth,tagWidth) v;
                 v.address = axiWires.araddr();
                 v.burst = axiWires.arburst();
                 v.cache = axiWires.arcache();
                 v.id = axiWires.arid();
                 v.len = axiWires.arlen();
                 v.lock = axiWires.arlock();
                 v.prot = axiWires.arprot();
                 v.qos = axiWires.arqos();
                 v.size = {0, axiWires.arsize()};

                arready <= 1;
                return v;
            endmethod
        endinterface
        interface Get req_aw;
            method ActionValue#(Axi3WriteRequest#(addrWidth,tagWidth)) get() if (axiWires.awvalid() != 0);
                Axi3WriteRequest#(addrWidth,tagWidth) v;
                v.address = axiWires.awaddr();
                v.burst = axiWires.awburst();
                v.cache = axiWires.awcache();
                v.id = axiWires.awid();
                v.len = axiWires.awlen();
                v.lock = axiWires.awlock();
                v.prot = axiWires.awprot();
                v.qos = axiWires.awqos();
                v.size = {0, axiWires.awsize()};

                awready <= 1;
                return v;
           endmethod
        endinterface
        interface Put resp_read = resp_read_put;
        interface Get resp_write;
            method ActionValue#(Axi3WriteData#(dataWidth,tagWidth)) get() if (axiWires.wvalid() != 0);
                Axi3WriteData#(dataWidth,tagWidth) v;
                v.id = axiWires.wid();
                v.byteEnable = axiWires.wstrb();
                v.data = axiWires.wdata();
                v.last = axiWires.wlast();

                wready <= 1;
                return v;
            endmethod
        endinterface
        interface Put resp_b = resp_b_put;
    endinterface
    method aresetn = axiWires.aresetn;
endmodule

module mkAxi3SlaveGather#(AxiSlaveBits#(addrWidth, dataWidth, tagWidth,
    extraType) axiWires)(AxiSlaveCommon#(addrWidth, dataWidth,tagWidth,extraType));
    Wire#(Bit#(addrWidth)) araddr <- mkDWire(0);
    Wire#(Bit#(2)) arburst <- mkDWire(0);
    Wire#(Bit#(4)) arcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) arid <- mkDWire(0);
    Wire#(Bit#(4)) arlen <- mkDWire(0);
    Wire#(Bit#(2)) arlock <- mkDWire(0);
    Wire#(Bit#(3)) arprot <- mkDWire(0);
    Wire#(Bit#(4)) arqos <- mkDWire(0);
    Wire#(Bit#(2)) arsize <- mkDWire(0);
    Wire#(Bit#(1)) arvalid <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddr <- mkDWire(0);
    Wire#(Bit#(2)) awburst <- mkDWire(0);
    Wire#(Bit#(4)) awcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) awid <- mkDWire(0);
    Wire#(Bit#(4)) awlen <- mkDWire(0);
    Wire#(Bit#(2)) awlock <- mkDWire(0);
    Wire#(Bit#(3)) awprot <- mkDWire(0);
    Wire#(Bit#(4)) awqos <- mkDWire(0);
    Wire#(Bit#(2)) awsize <- mkDWire(0);
    Wire#(Bit#(1)) awvalid <- mkDWire(0);

    Wire#(Bit#(1)) rready <- mkDWire(0);
    Wire#(Bit#(tagWidth)) wid <- mkDWire(0);
    Wire#(Bit#(TDiv#(dataWidth,8))) wstrb <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdata <- mkDWire(0);
    Wire#(Bit#(1)) wlast <- mkDWire(0);
    Wire#(Bit#(1)) wvalid <- mkDWire(0);
    Wire#(Bit#(1)) bready <- mkDWire(0);

    rule handshake1;
          axiWires.araddr(araddr);
          axiWires.arburst(arburst);
          axiWires.arcache(arcache);
          axiWires.arid(arid);
          axiWires.arlen(arlen);
          axiWires.arlock(arlock);
          axiWires.arprot(arprot);
          axiWires.arqos(arqos);
          axiWires.arsize(arsize);
          axiWires.arvalid(arvalid);
    endrule
    rule handshake2;
          axiWires.awaddr(awaddr);
          axiWires.awburst(awburst);
          axiWires.awcache(awcache);
          axiWires.awid(awid);
          axiWires.awlen(awlen);
          axiWires.awlock(awlock);
          axiWires.awprot(awprot);
          axiWires.awqos(awqos);
          axiWires.awsize(awsize);
          axiWires.awvalid(awvalid);
    endrule
    rule handshake3;
         axiWires.rready(rready);
    endrule
    rule handshake4;
          axiWires.wid(wid);
          axiWires.wstrb(wstrb);
          axiWires.wdata(wdata);
          axiWires.wlast(wlast);
          axiWires.wvalid(wvalid);
    endrule
    rule handshake5;
         axiWires.bready(bready);
    endrule
    interface Axi3Slave server;
    interface Put req_ar;
        method Action put(Axi3ReadRequest#(addrWidth,tagWidth) v) if (axiWires.arready() != 0);
           araddr <= v.address;
           arburst <= v.burst;
           arcache <= v.cache;
           arid <= v.id;
           arlen <= v.len;
           arlock <= v.lock;
           arprot <= v.prot;
           arqos <= v.qos;
           arsize <= v.size[1:0];

           arvalid <= 1;
        endmethod
    endinterface
    interface Put req_aw;
        method Action put(Axi3WriteRequest#(addrWidth,tagWidth) v) if (axiWires.awready() != 0);
           awaddr <= v.address;
           awburst <= v.burst;
           awcache <= v.cache;
           awid <= v.id;
           awlen <= v.len;
           awlock <= v.lock;
           awprot <= v.prot;
           awqos <= v.qos;
           awsize <= v.size[1:0];

           awvalid <= 1;
        endmethod
    endinterface
    interface Put resp_write;
        method Action put(Axi3WriteData#(dataWidth,tagWidth) v) if (axiWires.wready() != 0);
           wid <= v.id;
           wstrb <= v.byteEnable;
           wdata <= v.data;
           wlast <= v.last;

           wvalid <= 1;
        endmethod
    endinterface
    interface Get resp_read;
        method ActionValue#(Axi3ReadResponse#(dataWidth, tagWidth)) get() if (axiWires.rvalid() != 0);
            Axi3ReadResponse#(dataWidth, tagWidth) v;
            v.id = axiWires.rid();
            v.resp = axiWires.rresp();
            v.data = axiWires.rdata();
            v.last = axiWires.rlast();

            rready <= 1;
            return v;
        endmethod
         endinterface
    interface Get resp_b;
        method ActionValue#(Axi3WriteResponse#(tagWidth)) get() if (axiWires.bvalid() != 0);
            Axi3WriteResponse#(tagWidth) v;
            v.id = axiWires.bid();
            v.resp = axiWires.bresp();

            bready <= 1;
            return v;
        endmethod
     endinterface
     endinterface
     interface extra = axiWires.extra;
     method aresetn = axiWires.aresetn;
endmodule

module mkAxi4SlaveGather#(Axi4SlaveBits#(addrWidth, dataWidth, tagWidth, extraType) axiWires)
   (Axi4SlaveCommon#(addrWidth, dataWidth,tagWidth,extraType));
    Wire#(Bit#(addrWidth)) araddr <- mkDWire(0);
    Wire#(Bit#(2)) arburst <- mkDWire(0);
    Wire#(Bit#(4)) arcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) arid <- mkDWire(0);
    Wire#(Bit#(8)) arlen <- mkDWire(0);
    Wire#(Bit#(2)) arlock <- mkDWire(0);
    Wire#(Bit#(3)) arprot <- mkDWire(0);
    Wire#(Bit#(4)) arqos <- mkDWire(0);
    Wire#(Bit#(3)) arsize <- mkDWire(0);
    Wire#(Bit#(1)) arvalid <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddr <- mkDWire(0);
    Wire#(Bit#(2)) awburst <- mkDWire(0);
    Wire#(Bit#(4)) awcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) awid <- mkDWire(0);
    Wire#(Bit#(8)) awlen <- mkDWire(0);
    Wire#(Bit#(2)) awlock <- mkDWire(0);
    Wire#(Bit#(3)) awprot <- mkDWire(0);
    Wire#(Bit#(4)) awqos <- mkDWire(0);
    Wire#(Bit#(3)) awsize <- mkDWire(0);
    Wire#(Bit#(1)) awvalid <- mkDWire(0);

    Wire#(Bit#(1)) rready <- mkDWire(0);
    Wire#(Bit#(tagWidth)) wid <- mkDWire(0);
    Wire#(Bit#(TDiv#(dataWidth,8))) wstrb <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdata <- mkDWire(0);
    Wire#(Bit#(1)) wlast <- mkDWire(0);
    Wire#(Bit#(1)) wvalid <- mkDWire(0);
    Wire#(Bit#(1)) bready <- mkDWire(0);

    rule handshake1;
          axiWires.araddr(araddr);
          axiWires.arburst(arburst);
          axiWires.arcache(arcache);
          axiWires.arid(arid);
          axiWires.arlen(arlen);
          axiWires.arlock(arlock);
          axiWires.arprot(arprot);
          axiWires.arqos(arqos);
          axiWires.arsize(arsize);
          axiWires.arvalid(arvalid);
    endrule
    rule handshake2;
          axiWires.awaddr(awaddr);
          axiWires.awburst(awburst);
          axiWires.awcache(awcache);
          axiWires.awid(awid);
          axiWires.awlen(awlen);
          axiWires.awlock(awlock);
          axiWires.awprot(awprot);
          axiWires.awqos(awqos);
          axiWires.awsize(awsize);
          axiWires.awvalid(awvalid);
    endrule
    rule handshake3;
         axiWires.rready(rready);
    endrule
    rule handshake4;
          axiWires.wid(wid);
          axiWires.wstrb(wstrb);
          axiWires.wdata(wdata);
          axiWires.wlast(wlast);
          axiWires.wvalid(wvalid);
    endrule
    rule handshake5;
         axiWires.bready(bready);
    endrule
    interface Axi4Slave server;
    interface Put req_ar;
        method Action put(Axi4ReadRequest#(addrWidth,tagWidth) v) if (axiWires.arready() != 0);
           araddr <= v.address;
           arburst <= v.burst;
           arcache <= v.cache;
           arid <= v.id;
           arlen <= v.len;
           arlock <= v.lock;
           arprot <= v.prot;
           arqos <= v.qos;
           arsize <= v.size;

           arvalid <= 1;
        endmethod
    endinterface
    interface Put req_aw;
        method Action put(Axi4WriteRequest#(addrWidth,tagWidth) v) if (axiWires.awready() != 0);
           awaddr <= v.address;
           awburst <= v.burst;
           awcache <= v.cache;
           awid <= v.id;
           awlen <= v.len;
           awlock <= v.lock;
           awprot <= v.prot;
           awqos <= v.qos;
           awsize <= v.size;

           awvalid <= 1;
        endmethod
    endinterface
    interface Put resp_write;
        method Action put(Axi4WriteData#(dataWidth,tagWidth) v) if (axiWires.wready() != 0);
           wid <= v.id;
           wstrb <= v.byteEnable;
           wdata <= v.data;
           wlast <= v.last;

           wvalid <= 1;
        endmethod
    endinterface
    interface Get resp_read;
        method ActionValue#(Axi4ReadResponse#(dataWidth, tagWidth)) get() if (axiWires.rvalid() != 0);
            Axi4ReadResponse#(dataWidth, tagWidth) v;
            v.id = axiWires.rid();
            v.resp = axiWires.rresp();
            v.data = axiWires.rdata();
            v.last = axiWires.rlast();

            rready <= 1;
            return v;
        endmethod
         endinterface
    interface Get resp_b;
        method ActionValue#(Axi4WriteResponse#(tagWidth)) get() if (axiWires.bvalid() != 0);
            Axi4WriteResponse#(tagWidth) v;
            v.id = axiWires.bid();
            v.resp = axiWires.bresp();

            bready <= 1;
            return v;
        endmethod
     endinterface
     endinterface
     interface extra = axiWires.extra;
     method aresetn = axiWires.aresetn;
endmodule

// Copyright (c) 2015 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 Vector::*;
import PPS7LIB::*;
import AxiMasterSlave::*;
import Axi4MasterSlave::*;
import AxiBits::*;

interface AxiMasterCommon#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth);
    method Bit#(1)            aresetn();
    interface Axi3Master#(addrWidth,dataWidth,tagWidth) client;
endinterface

interface AxiSlaveCommon#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(1)            aresetn();
    interface Axi3Slave#(addrWidth,dataWidth,tagWidth) server;
    interface extraType   extra;
endinterface

interface Axi4SlaveCommon#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(1)            aresetn();
    interface Axi4Slave#(addrWidth,dataWidth,tagWidth) server;
    interface extraType   extra;
endinterface

module mkAxi3MasterGather#(AxiMasterBits#(addrWidth, dataWidth, tagWidth, Empty) axiWires)(AxiMasterCommon#(addrWidth, dataWidth, tagWidth));
   Wire#(Bit#(1)) arready <- mkDWire(0);
   Wire#(Bit#(1)) awready <- mkDWire(0);
   Wire#(Bit#(1)) rvalid <- mkDWire(0);
   Wire#(Bit#(1)) wready <- mkDWire(0);
   Wire#(Bit#(tagWidth)) rid <- mkDWire(0);
   Wire#(Bit#(2)) rresp <- mkDWire(0);
   Wire#(Bit#(dataWidth)) rdata <- mkDWire(0);
   Wire#(Bit#(1)) rlast <- mkDWire(0);
   Wire#(Bit#(1)) bvalid <- mkDWire(0);
   Wire#(Bit#(tagWidth)) bid <- mkDWire(0);
   Wire#(Bit#(2)) bresp <- mkDWire(0);

   rule handshake1;
        axiWires.arready(arready);
   endrule
   rule handshake2;
        axiWires.awready(awready);
   endrule
   rule handshake3;
        axiWires.rid(rid);
        axiWires.rresp(rresp);
        axiWires.rdata(rdata);
        axiWires.rlast(rlast);
        axiWires.rvalid(rvalid);
   endrule
   rule handshake4;
        axiWires.wready(wready);
   endrule
   rule handshake5;
        axiWires.bvalid(bvalid);
        axiWires.bid(bid);
        axiWires.bresp(bresp);
   endrule

   interface Axi3Master client;
        interface Get req_ar;
             method ActionValue#(Axi3ReadRequest#(addrWidth,tagWidth)) get() if (axiWires.arvalid() != 0);
                 Axi3ReadRequest#(addrWidth,tagWidth) v;
                 v.address = axiWires.araddr();
                 v.burst = axiWires.arburst();
                 v.cache = axiWires.arcache();
                 v.id = axiWires.arid();
                 v.len = axiWires.arlen();
                 v.lock = axiWires.arlock();
                 v.prot = axiWires.arprot();
                 v.qos = axiWires.arqos();
                 v.size = {0, axiWires.arsize()};

                arready <= 1;
                return v;
            endmethod
        endinterface
        interface Get req_aw;
            method ActionValue#(Axi3WriteRequest#(addrWidth,tagWidth)) get() if (axiWires.awvalid() != 0);
                Axi3WriteRequest#(addrWidth,tagWidth) v;
                v.address = axiWires.awaddr();
                v.burst = axiWires.awburst();
                v.cache = axiWires.awcache();
                v.id = axiWires.awid();
                v.len = axiWires.awlen();
                v.lock = axiWires.awlock();
                v.prot = axiWires.awprot();
                v.qos = axiWires.awqos();
                v.size = {0, axiWires.awsize()};

                awready <= 1;
                return v;
           endmethod
        endinterface
        interface Put resp_read;
            method Action put(Axi3ReadResponse#(dataWidth, tagWidth) v) if (axiWires.rready() != 0);
                rid <= v.id;
                rresp <= v.resp;
                rdata <= v.data;
                rlast <= v.last;
                rvalid <= 1;
            endmethod
        endinterface
        interface Get resp_write;
            method ActionValue#(Axi3WriteData#(dataWidth,tagWidth)) get() if (axiWires.wvalid() != 0);
                Axi3WriteData#(dataWidth,tagWidth) v;
                v.id = axiWires.wid();
                v.byteEnable = axiWires.wstrb();
                v.data = axiWires.wdata();
                v.last = axiWires.wlast();

                wready <= 1;
                return v;
            endmethod
        endinterface
        interface Put resp_b;
            method Action put(Axi3WriteResponse#(tagWidth) v) if (axiWires.bready() != 0);
                bvalid <= 1;
                bid    <= v.id;
                bresp  <= v.resp;
            endmethod
        endinterface
    endinterface
    method aresetn = axiWires.aresetn;
endmodule

module mkAxi3SlaveGather#(AxiSlaveBits#(addrWidth, dataWidth, tagWidth,
    extraType) axiWires)(AxiSlaveCommon#(addrWidth, dataWidth,tagWidth,extraType));
    Wire#(Bit#(addrWidth)) araddr <- mkDWire(0);
    Wire#(Bit#(2)) arburst <- mkDWire(0);
    Wire#(Bit#(4)) arcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) arid <- mkDWire(0);
    Wire#(Bit#(4)) arlen <- mkDWire(0);
    Wire#(Bit#(2)) arlock <- mkDWire(0);
    Wire#(Bit#(3)) arprot <- mkDWire(0);
    Wire#(Bit#(4)) arqos <- mkDWire(0);
    Wire#(Bit#(2)) arsize <- mkDWire(0);
    Wire#(Bit#(1)) arvalid <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddr <- mkDWire(0);
    Wire#(Bit#(2)) awburst <- mkDWire(0);
    Wire#(Bit#(4)) awcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) awid <- mkDWire(0);
    Wire#(Bit#(4)) awlen <- mkDWire(0);
    Wire#(Bit#(2)) awlock <- mkDWire(0);
    Wire#(Bit#(3)) awprot <- mkDWire(0);
    Wire#(Bit#(4)) awqos <- mkDWire(0);
    Wire#(Bit#(2)) awsize <- mkDWire(0);
    Wire#(Bit#(1)) awvalid <- mkDWire(0);

    Wire#(Bit#(1)) rready <- mkDWire(0);
    Wire#(Bit#(tagWidth)) wid <- mkDWire(0);
    Wire#(Bit#(TDiv#(dataWidth,8))) wstrb <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdata <- mkDWire(0);
    Wire#(Bit#(1)) wlast <- mkDWire(0);
    Wire#(Bit#(1)) wvalid <- mkDWire(0);
    Wire#(Bit#(1)) bready <- mkDWire(0);

    rule handshake1;
          axiWires.araddr(araddr);
          axiWires.arburst(arburst);
          axiWires.arcache(arcache);
          axiWires.arid(arid);
          axiWires.arlen(arlen);
          axiWires.arlock(arlock);
          axiWires.arprot(arprot);
          axiWires.arqos(arqos);
          axiWires.arsize(arsize);
          axiWires.arvalid(arvalid);
    endrule
    rule handshake2;
          axiWires.awaddr(awaddr);
          axiWires.awburst(awburst);
          axiWires.awcache(awcache);
          axiWires.awid(awid);
          axiWires.awlen(awlen);
          axiWires.awlock(awlock);
          axiWires.awprot(awprot);
          axiWires.awqos(awqos);
          axiWires.awsize(awsize);
          axiWires.awvalid(awvalid);
    endrule
    rule handshake3;
         axiWires.rready(rready);
    endrule
    rule handshake4;
          axiWires.wid(wid);
          axiWires.wstrb(wstrb);
          axiWires.wdata(wdata);
          axiWires.wlast(wlast);
          axiWires.wvalid(wvalid);
    endrule
    rule handshake5;
         axiWires.bready(bready);
    endrule
    interface Axi3Slave server;
    interface Put req_ar;
        method Action put(Axi3ReadRequest#(addrWidth,tagWidth) v) if (axiWires.arready() != 0);
           araddr <= v.address;
           arburst <= v.burst;
           arcache <= v.cache;
           arid <= v.id;
           arlen <= v.len;
           arlock <= v.lock;
           arprot <= v.prot;
           arqos <= v.qos;
           arsize <= v.size[1:0];

           arvalid <= 1;
        endmethod
    endinterface
    interface Put req_aw;
        method Action put(Axi3WriteRequest#(addrWidth,tagWidth) v) if (axiWires.awready() != 0);
           awaddr <= v.address;
           awburst <= v.burst;
           awcache <= v.cache;
           awid <= v.id;
           awlen <= v.len;
           awlock <= v.lock;
           awprot <= v.prot;
           awqos <= v.qos;
           awsize <= v.size[1:0];

           awvalid <= 1;
        endmethod
    endinterface
    interface Put resp_write;
        method Action put(Axi3WriteData#(dataWidth,tagWidth) v) if (axiWires.wready() != 0);
           wid <= v.id;
           wstrb <= v.byteEnable;
           wdata <= v.data;
           wlast <= v.last;

           wvalid <= 1;
        endmethod
    endinterface
    interface Get resp_read;
        method ActionValue#(Axi3ReadResponse#(dataWidth, tagWidth)) get() if (axiWires.rvalid() != 0);
            Axi3ReadResponse#(dataWidth, tagWidth) v;
            v.id = axiWires.rid();
            v.resp = axiWires.rresp();
            v.data = axiWires.rdata();
            v.last = axiWires.rlast();

            rready <= 1;
            return v;
        endmethod
         endinterface
    interface Get resp_b;
        method ActionValue#(Axi3WriteResponse#(tagWidth)) get() if (axiWires.bvalid() != 0);
            Axi3WriteResponse#(tagWidth) v;
            v.id = axiWires.bid();
            v.resp = axiWires.bresp();

            bready <= 1;
            return v;
        endmethod
     endinterface
     endinterface
     interface extra = axiWires.extra;
     method aresetn = axiWires.aresetn;
endmodule

module mkAxi4SlaveGather#(Axi4SlaveBits#(addrWidth, dataWidth, tagWidth, extraType) axiWires)
   (Axi4SlaveCommon#(addrWidth, dataWidth,tagWidth,extraType));
    Wire#(Bit#(addrWidth)) araddr <- mkDWire(0);
    Wire#(Bit#(2)) arburst <- mkDWire(0);
    Wire#(Bit#(4)) arcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) arid <- mkDWire(0);
    Wire#(Bit#(8)) arlen <- mkDWire(0);
    Wire#(Bit#(2)) arlock <- mkDWire(0);
    Wire#(Bit#(3)) arprot <- mkDWire(0);
    Wire#(Bit#(4)) arqos <- mkDWire(0);
    Wire#(Bit#(3)) arsize <- mkDWire(0);
    Wire#(Bit#(1)) arvalid <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddr <- mkDWire(0);
    Wire#(Bit#(2)) awburst <- mkDWire(0);
    Wire#(Bit#(4)) awcache <- mkDWire(0);
    Wire#(Bit#(tagWidth)) awid <- mkDWire(0);
    Wire#(Bit#(8)) awlen <- mkDWire(0);
    Wire#(Bit#(2)) awlock <- mkDWire(0);
    Wire#(Bit#(3)) awprot <- mkDWire(0);
    Wire#(Bit#(4)) awqos <- mkDWire(0);
    Wire#(Bit#(3)) awsize <- mkDWire(0);
    Wire#(Bit#(1)) awvalid <- mkDWire(0);

    Wire#(Bit#(1)) rready <- mkDWire(0);
    Wire#(Bit#(tagWidth)) wid <- mkDWire(0);
    Wire#(Bit#(TDiv#(dataWidth,8))) wstrb <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdata <- mkDWire(0);
    Wire#(Bit#(1)) wlast <- mkDWire(0);
    Wire#(Bit#(1)) wvalid <- mkDWire(0);
    Wire#(Bit#(1)) bready <- mkDWire(0);

    rule handshake1;
          axiWires.araddr(araddr);
          axiWires.arburst(arburst);
          axiWires.arcache(arcache);
          axiWires.arid(arid);
          axiWires.arlen(arlen);
          axiWires.arlock(arlock);
          axiWires.arprot(arprot);
          axiWires.arqos(arqos);
          axiWires.arsize(arsize);
          axiWires.arvalid(arvalid);
    endrule
    rule handshake2;
          axiWires.awaddr(awaddr);
          axiWires.awburst(awburst);
          axiWires.awcache(awcache);
          axiWires.awid(awid);
          axiWires.awlen(awlen);
          axiWires.awlock(awlock);
          axiWires.awprot(awprot);
          axiWires.awqos(awqos);
          axiWires.awsize(awsize);
          axiWires.awvalid(awvalid);
    endrule
    rule handshake3;
         axiWires.rready(rready);
    endrule
    rule handshake4;
          axiWires.wid(wid);
          axiWires.wstrb(wstrb);
          axiWires.wdata(wdata);
          axiWires.wlast(wlast);
          axiWires.wvalid(wvalid);
    endrule
    rule handshake5;
         axiWires.bready(bready);
    endrule
    interface Axi4Slave server;
    interface Put req_ar;
        method Action put(Axi4ReadRequest#(addrWidth,tagWidth) v) if (axiWires.arready() != 0);
           araddr <= v.address;
           arburst <= v.burst;
           arcache <= v.cache;
           arid <= v.id;
           arlen <= v.len;
           arlock <= v.lock;
           arprot <= v.prot;
           arqos <= v.qos;
           arsize <= v.size;

           arvalid <= 1;
        endmethod
    endinterface
    interface Put req_aw;
        method Action put(Axi4WriteRequest#(addrWidth,tagWidth) v) if (axiWires.awready() != 0);
           awaddr <= v.address;
           awburst <= v.burst;
           awcache <= v.cache;
           awid <= v.id;
           awlen <= v.len;
           awlock <= v.lock;
           awprot <= v.prot;
           awqos <= v.qos;
           awsize <= v.size;

           awvalid <= 1;
        endmethod
    endinterface
    interface Put resp_write;
        method Action put(Axi4WriteData#(dataWidth,tagWidth) v) if (axiWires.wready() != 0);
           wid <= v.id;
           wstrb <= v.byteEnable;
           wdata <= v.data;
           wlast <= v.last;

           wvalid <= 1;
        endmethod
    endinterface
    interface Get resp_read;
        method ActionValue#(Axi4ReadResponse#(dataWidth, tagWidth)) get() if (axiWires.rvalid() != 0);
            Axi4ReadResponse#(dataWidth, tagWidth) v;
            v.id = axiWires.rid();
            v.resp = axiWires.rresp();
            v.data = axiWires.rdata();
            v.last = axiWires.rlast();

            rready <= 1;
            return v;
        endmethod
         endinterface
    interface Get resp_b;
        method ActionValue#(Axi4WriteResponse#(tagWidth)) get() if (axiWires.bvalid() != 0);
            Axi4WriteResponse#(tagWidth) v;
            v.id = axiWires.bid();
            v.resp = axiWires.bresp();

            bready <= 1;
            return v;
        endmethod
     endinterface
     endinterface
     interface extra = axiWires.extra;
     method aresetn = axiWires.aresetn;
endmodule


Now works in 2 cycles per inner loop iteration

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

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

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

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

import StmtFSM::*;
import BRAM::*;
import MCSAlgorithm::*;

module mkHirschB#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL, int dir)(MCSAlgorithm)
         provisos(Add#(0, 7, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(7)) aStartReg <- mkReg(0);
   Reg#(Bit#(7)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(7)) aLenReg <- mkReg(0);
   Reg#(Bit#(7)) bLenReg <- mkReg(0);
   Reg#(Bit#(7)) ii <- mkReg(0);
   Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) k1j <- mkReg(0);
   Reg#(Bit#(16)) k1jm1 <- mkReg(0);
   Reg#(Bit#(16)) k0j <- mkReg(0);
   Reg#(Bit#(16)) k0jm1 <- mkReg(0);
   BRAM1Port#(Bit#(lIndexWidth), Bit#(16)) k0  <- mkBRAM1Server(defaultValue);

/* The original algorithm B uses two vectors K0 and K1 to store two rows of the full L
 * matrix from algoritm A.  For any particular iteration, K[0][j-1] K[0][j]
 * and K[1][j-1] are used to compute K[1][j]
 *
 * Each cycle, K[1] is copied to K[0], and then a new K[1] is computed.  First, the
 * the previous K[0][j] is copied to K[0][j-1] and the previous K[1][j] is copied to
 * K[1][j-1].  Then a new K[1][j] is computed.
 *
 * In the revised version, a single vector is used, plus auxiliary registers.
 * First the old K[0][j] auxiliary is copied to K[0][j-1] and the K[1][j] auxiliary
 * is copied to K[1][j-1].  Then K[0][j] is read. Then K[1][j] is computed <and written> to
 * K[0][j].  When the row is finished, K[0] is effectively K[1]
 *
 */

  Stmt hirschB =
   seq
      $display("hirschB running ");
      /* initialize K1 (stored in lMat) of temporary storage */
      for (jj <= 0; jj <= bLenReg; jj <= jj + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: 0});
	 endseq
      /* Loop through string a */
      for (ii <= 1; ii <= aLenReg; ii <= ii + 1)
	 seq
	    //$display("hirschB ii = %d", ii);
	    par
	       /* initialize pipelining */
	       jj <= 1;
	       k0j <= 0;
	       k1j <= 0;
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: ii-1, datain: 0});
	       /* Read b[j] */
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 0, datain: 0});
	       /* start read of k0j */
	       matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 1, datain: 0});
	    endpar
	    action
	       let ta <- strA.response.get(); /* read a[i] */
	       aData <= ta;
	    endaction

	    /* Loop through string B */
	    while (jj <= bLenReg)
	       seq
		  //$display("hirschB jj = %d", jj);
		  action
		     let tb <- strB.response.get();
		     let tk <- matL.response.get();
		     k0jm1 <= k0j;  /* pipeline from previous cycle */
		     k1jm1 <= k1j;
		     bData <= tb;   /* read b[j] from bram */
		     k0j <= tk;     /* read k[0][j] from bram */
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
		  endaction
		  //$display("hirschB ii %d jj %d A %d B %d", ii, jj, aData, bData);
		  action
		     let tmp = ?;
		     /* Read b[j] */
		     strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: jj-1, datain: 0});
		     if (aData == bData)
			tmp = k0jm1 + 1;
		     else
		        tmp = max(k0j,k1jm1);
		     k1j <= tmp;
		     jj <= jj + 1;
		     /* start read of k0j */
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj+1), datain: 0});
		  endaction
		  //$display("     L[%d][%d] = %d ", ii, jj, k1j);
	       endseq
	    action
	       let tb <- strB.response.get();
	       let tk <- matL.response.get();
	       matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
	    endaction
	 endseq
   endseq;

   FSM hB <- mkFSM(hirschB);

   method Action setupA(Bit#(7) start, Bit#(7) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(7) start, Bit#(7) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
      rStartReg <= start;
   endmethod

   interface FSM fsm = hB;

endmodule

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

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

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

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

import StmtFSM::*;
import BRAM::*;
import MCSAlgorithm::*;

module mkHirschB#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL, int dir)(MCSAlgorithm)
         provisos(Add#(0, 7, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(7)) aStartReg <- mkReg(0);
   Reg#(Bit#(7)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(7)) aLenReg <- mkReg(0);
   Reg#(Bit#(7)) bLenReg <- mkReg(0);
   Reg#(Bit#(7)) ii <- mkReg(0);
   Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) k1j <- mkReg(0);
   Reg#(Bit#(16)) k1jm1 <- mkReg(0);
   Reg#(Bit#(16)) k0j <- mkReg(0);
   Reg#(Bit#(16)) k0jm1 <- mkReg(0);
   BRAM1Port#(Bit#(lIndexWidth), Bit#(16)) k0  <- mkBRAM1Server(defaultValue);

/* The original algorithm B uses two vectors K0 and K1 to store two rows of the full L
 * matrix from algoritm A.  For any particular iteration, K[0][j-1] K[0][j]
 * and K[1][j-1] are used to compute K[1][j]
 *
 * Each cycle, K[1] is copied to K[0], and then a new K[1] is computed.  First, the
 * the previous K[0][j] is copied to K[0][j-1] and the previous K[1][j] is copied to
 * K[1][j-1].  Then a new K[1][j] is computed.
 *
 * In the revised version, a single vector is used, plus auxiliary registers.
 * First the old K[0][j] auxiliary is copied to K[0][j-1] and the K[1][j] auxiliary
 * is copied to K[1][j-1].  Then K[0][j] is read. Then K[1][j] is computed <and written> to
 * K[0][j].  When the row is finished, K[0] is effectively K[1]
 *
 */

  Stmt hirschB =
   seq
      $display("hirschB running ");
      /* initialize K1 (stored in lMat) of temporary storage */
      for (jj <= 0; jj <= bLenReg; jj <= jj + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: 0});
	 endseq
      /* Loop through string a */
      for (ii <= 1; ii <= aLenReg; ii <= ii + 1)
	 seq
	    //$display("hirschB ii = %d", ii);
	    par
	       /* initialize pipelining */
	       jj <= 0;
	       k0j <= 0;
	       k1j <= 0;
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: ii-1, datain: 0});
	       /* Read b[j] */
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 0, datain: 0});
	    endpar
	    action
	       let ta <- strA.response.get(); /* read a[i] */
	       aData <= ta;
	    endaction

	    /* Loop through string B */
	    while (jj <= bLenReg)
	       seq
		  //$display("hirschB jj = %d", jj);
		  action
		     /* start read of k0j */
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: 0});
		  endaction
		  action
		     let tb <- strB.response.get();
		     let tk <- matL.response.get();
		     k0jm1 <= k0j;  /* pipeline from previous cycle */
		     k1jm1 <= k1j;
		     bData <= tb;   /* read b[j] from bram */
		     k0j <= tk;     /* read k[0][j] from bram */
		  endaction
		  //$display("hirschB ii %d jj %d A %d B %d", ii, jj, aData, bData);
		  action
		     let tmp = ?;
		     /* Read b[j] */
		     strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: jj-1, datain: 0});
		     if (aData == bData)
			tmp = k0jm1 + 1;
		     else
		        tmp = max(k0j,k1jm1);
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: tmp});
		     k1j <= tmp;
		     jj <= jj + 1;
		  endaction
		  //$display("     L[%d][%d] = %d ", ii, jj, k1j);
	       endseq
	    action
	       let tb <- strB.response.get();
	    endaction
	 endseq
   endseq;

   FSM hB <- mkFSM(hirschB);

   method Action setupA(Bit#(7) start, Bit#(7) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(7) start, Bit#(7) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
      rStartReg <= start;
   endmethod

   interface FSM fsm = hB;

endmodule


add comments for direction, fix index in strB fetch (maybe)

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

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

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

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

import StmtFSM::*;
import BRAM::*;
import MCSAlgorithm::*;

module mkHirschB#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL, int dir)(MCSAlgorithm)
         provisos(Add#(0, 7, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(7)) aStartReg <- mkReg(0);
   Reg#(Bit#(7)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(7)) aLenReg <- mkReg(0);
   Reg#(Bit#(7)) bLenReg <- mkReg(0);
   Reg#(Bit#(7)) ii <- mkReg(0);
   Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) k1j <- mkReg(0);
   Reg#(Bit#(16)) k1jm1 <- mkReg(0);
   Reg#(Bit#(16)) k0j <- mkReg(0);
   Reg#(Bit#(16)) k0jm1 <- mkReg(0);
   BRAM1Port#(Bit#(lIndexWidth), Bit#(16)) k0  <- mkBRAM1Server(defaultValue);

/* The original algorithm B uses two vectors K0 and K1 to store two rows of the full L
 * matrix from algoritm A.  For any particular iteration, K[0][j-1] K[0][j]
 * and K[1][j-1] are used to compute K[1][j]
 *
 * Each cycle, K[1] is copied to K[0], and then a new K[1] is computed.  First, the
 * the previous K[0][j] is copied to K[0][j-1] and the previous K[1][j] is copied to
 * K[1][j-1].  Then a new K[1][j] is computed.
 *
 * In the revised version, a single vector is used, plus auxiliary registers.
 * First the old K[0][j] auxiliary is copied to K[0][j-1] and the K[1][j] auxiliary
 * is copied to K[1][j-1].  Then K[0][j] is read. Then K[1][j] is computed <and written> to
 * K[0][j].  When the row is finished, K[0] is effectively K[1]
 *
 */

  Stmt hirschB =
   seq
      $display("hirschB running ");
      /* initialize K1 (stored in lMat) of temporary storage */
      for (jj <= 0; jj <= bLenReg; jj <= jj + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: 0});
	 endseq
      /* Loop through string a */
      for (ii <= 1; ii <= aLenReg; ii <= ii + 1)
	 seq
	    //$display("hirschB ii = %d", ii);
	    par
	       /* initialize pipelining */
	       jj <= 1;
	       k0j <= 0;
	       k1j <= 0;
      /* if backwards, A[aStartReg + aLenReg - i] */
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: ii-1, datain: 0});
	       /* Read b[j] */
	       /* if backwards, [bStartReg + bLenReg - 1]
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 0, datain: 0});
	       /* start read of k0j */
	       matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 1, datain: 0});
	    endpar
	    action
	       let ta <- strA.response.get(); /* read a[i] */
	       aData <= ta;
	    endaction

	    /* Loop through string B */
	    while (jj <= bLenReg)
	       seq
		  //$display("hirschB jj = %d", jj);
		  action
		     let tb <- strB.response.get();
		     let tk <- matL.response.get();
		     k0jm1 <= k0j;  /* pipeline from previous cycle */
		     k1jm1 <= k1j;
		     bData <= tb;   /* read b[j] from bram */
		     k0j <= tk;     /* read k[0][j] from bram */
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
		  endaction
		  //$display("hirschB ii %d jj %d A %d B %d", ii, jj, aData, bData);
		  action
		     let tmp = ?;
		     /* Read b[j] */
		     /* ib backwards B[bStartReg + bLenReg - jj] */
		     strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: jj, datain: 0});
		     if (aData == bData)
			tmp = k0jm1 + 1;
		     else
		        tmp = max(k0j,k1jm1);
		     k1j <= tmp;
		     jj <= jj + 1;
		     /* start read of k0j */
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj+1), datain: 0});
		  endaction
		  //$display("     L[%d][%d] = %d ", ii, jj, k1j);
	       endseq
	    action
	       let tb <- strB.response.get();
	       let tk <- matL.response.get();
	       matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
	    endaction
	 endseq
   endseq;

   FSM hB <- mkFSM(hirschB);

   method Action setupA(Bit#(7) start, Bit#(7) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(7) start, Bit#(7) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
      rStartReg <= start;
   endmethod

   interface FSM fsm = hB;

endmodule

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

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

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

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

import StmtFSM::*;
import BRAM::*;
import MCSAlgorithm::*;

module mkHirschB#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL, int dir)(MCSAlgorithm)
         provisos(Add#(0, 7, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(7)) aStartReg <- mkReg(0);
   Reg#(Bit#(7)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(7)) aLenReg <- mkReg(0);
   Reg#(Bit#(7)) bLenReg <- mkReg(0);
   Reg#(Bit#(7)) ii <- mkReg(0);
   Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) k1j <- mkReg(0);
   Reg#(Bit#(16)) k1jm1 <- mkReg(0);
   Reg#(Bit#(16)) k0j <- mkReg(0);
   Reg#(Bit#(16)) k0jm1 <- mkReg(0);
   BRAM1Port#(Bit#(lIndexWidth), Bit#(16)) k0  <- mkBRAM1Server(defaultValue);

/* The original algorithm B uses two vectors K0 and K1 to store two rows of the full L
 * matrix from algoritm A.  For any particular iteration, K[0][j-1] K[0][j]
 * and K[1][j-1] are used to compute K[1][j]
 *
 * Each cycle, K[1] is copied to K[0], and then a new K[1] is computed.  First, the
 * the previous K[0][j] is copied to K[0][j-1] and the previous K[1][j] is copied to
 * K[1][j-1].  Then a new K[1][j] is computed.
 *
 * In the revised version, a single vector is used, plus auxiliary registers.
 * First the old K[0][j] auxiliary is copied to K[0][j-1] and the K[1][j] auxiliary
 * is copied to K[1][j-1].  Then K[0][j] is read. Then K[1][j] is computed <and written> to
 * K[0][j].  When the row is finished, K[0] is effectively K[1]
 *
 */

  Stmt hirschB =
   seq
      $display("hirschB running ");
      /* initialize K1 (stored in lMat) of temporary storage */
      for (jj <= 0; jj <= bLenReg; jj <= jj + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: 0});
	 endseq
      /* Loop through string a */
      for (ii <= 1; ii <= aLenReg; ii <= ii + 1)
	 seq
	    //$display("hirschB ii = %d", ii);
	    par
	       /* initialize pipelining */
	       jj <= 1;
	       k0j <= 0;
	       k1j <= 0;
	       strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: ii-1, datain: 0});
	       /* Read b[j] */
	       strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 0, datain: 0});
	       /* start read of k0j */
	       matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: 1, datain: 0});
	    endpar
	    action
	       let ta <- strA.response.get(); /* read a[i] */
	       aData <= ta;
	    endaction

	    /* Loop through string B */
	    while (jj <= bLenReg)
	       seq
		  //$display("hirschB jj = %d", jj);
		  action
		     let tb <- strB.response.get();
		     let tk <- matL.response.get();
		     k0jm1 <= k0j;  /* pipeline from previous cycle */
		     k1jm1 <= k1j;
		     bData <= tb;   /* read b[j] from bram */
		     k0j <= tk;     /* read k[0][j] from bram */
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
		  endaction
		  //$display("hirschB ii %d jj %d A %d B %d", ii, jj, aData, bData);
		  action
		     let tmp = ?;
		     /* Read b[j] */
		     strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: jj-1, datain: 0});
		     if (aData == bData)
			tmp = k0jm1 + 1;
		     else
		        tmp = max(k0j,k1jm1);
		     k1j <= tmp;
		     jj <= jj + 1;
		     /* start read of k0j */
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj+1), datain: 0});
		  endaction
		  //$display("     L[%d][%d] = %d ", ii, jj, k1j);
	       endseq
	    action
	       let tb <- strB.response.get();
	       let tk <- matL.response.get();
	       matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
	    endaction
	 endseq
   endseq;

   FSM hB <- mkFSM(hirschB);

   method Action setupA(Bit#(7) start, Bit#(7) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(7) start, Bit#(7) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
      rStartReg <= start;
   endmethod

   interface FSM fsm = hB;

endmodule


removed duplicate declaration of mmDebugIndicationProxy

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;
import Connectable::*;

// portz libraries
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import PortalMemory::*;
import MemServer::*;
import PortalMemory::*;
import Dma::*;
import DmaUtils::*;
import RbmTypes::*;

// generated by tool
import DmaConfigWrapper::*;
import DmaIndicationProxy::*;
import MmIndicationProxy::*;
import MmRequestWrapper::*;
import TimerIndicationProxy::*;
import TimerRequestWrapper::*;
import MmDebugIndicationProxy::*;

// defined by user
import Matrix::*;

//typedef TAdd#(K,J) NumMasters;
`ifdef PCIE
typedef 1 NumMasters;
`else
typedef 1 NumMasters;
`endif

typedef TMul#(TDiv#(TAdd#(K,J),NumMasters),NumMasters)  NumReadBuffers;
typedef TMul#(TDiv#(J,NumMasters),NumMasters)  NumWriteBuffers;

typedef 1                                        ReadClientFanout;
typedef TDiv#(NumReadBuffers,ReadClientFanout)   NumReadClients;
typedef 1                                        WriteClientFanout;
typedef TDiv#(NumWriteBuffers,WriteClientFanout) NumWriteClients;

module [Module] mkPortalTop(PortalTop#(addrWidth,TMul#(32,N),Empty,NumMasters))
   provisos (Add#(a__, addrWidth, 40),
	     Add#(a__, b__, 40),
	     Add#(addrWidth, c__, 52),
	     Add#(addrWidth, d__, 64),
	     Add#(e__, f__, 40),
	     Add#(f__, 12, b__),
	     Add#(b__, g__, 44)
	     );

   DmaIndicationProxy dmaIndicationProxy <- mkDmaIndicationProxy(DmaIndicationPortal);

   MmDebugIndicationProxy mmDebugIndicationProxy <- mkMmDebugIndicationProxy(MmDebugIndicationPortal);
   MmIndicationProxy mmIndicationProxy <- mkMmIndicationProxy(MmIndicationPortal);
   TimerIndicationProxy timerIndicationProxy <- mkTimerIndicationProxy(TimerIndicationPortal);
   Mm#(N) mm <- mkMm(mmIndicationProxy.ifc, timerIndicationProxy.ifc, mmDebugIndicationProxy.ifc);
   MmRequestWrapper mmRequestWrapper <- mkMmRequestWrapper(MmRequestPortal,mm.mmRequest);
   TimerRequestWrapper timerRequestWrapper <- mkTimerRequestWrapper(TimerRequestPortal,mm.timerRequest);

   Vector#(NumReadBuffers, DmaReadBuffer#(TMul#(32,N),BurstLen)) read_buffers <- replicateM(mkDmaReadBuffer);
   zipWithM(mkConnection, mm.readClients, map(ors, read_buffers));
   let readBufferClients = map(orc, read_buffers);

   Vector#(NumReadClients,ObjectReadClient#(TMul#(32,N))) readClients;
   if (valueOf(NumReadClients) < valueOf(NumReadBuffers)) begin
      module mkFanoutReadClients#(Integer i)(ObjectReadClient#(TMul#(32,N)));
	 Vector#(ReadClientFanout, ObjectReadClient#(TMul#(32,N))) subReadClients = takeAt(i*valueOf(ReadClientFanout), readBufferClients);
	 let readMux <- mkDmaReadMux(subReadClients);
	 return readMux;
      endmodule
      readClients <- genWithM(mkFanoutReadClients);
   end
   else begin
      //readClients = take(readBufferClients);
      readClients = readBufferClients;
   end

   Vector#(NumWriteBuffers, DmaWriteBuffer#(TMul#(32,N),BurstLen)) write_buffers <- replicateM(mkDmaWriteBuffer);
   zipWithM(mkConnection, mm.writeClients, map(ows,takeAt(0,write_buffers)));
   let writeBufferClients = map(owc, write_buffers);

   Vector#(NumWriteClients,ObjectWriteClient#(TMul#(32,N))) writeClients;
   if (valueOf(NumWriteClients) < valueOf(NumWriteBuffers)) begin
      module mkFanoutWriteClients#(Integer i)(ObjectWriteClient#(TMul#(32,N)));
	 Vector#(WriteClientFanout, ObjectWriteClient#(TMul#(32,N))) subWriteClients = takeAt(i*valueOf(WriteClientFanout), writeBufferClients);
	 let writeMux <- mkDmaWriteMux(/* i*valueOf(WriteClientFanout), */ subWriteClients);
	 return writeMux;
      endmodule
      writeClients <- genWithM(mkFanoutWriteClients);
   end
   else begin
      //writeClients = take(writeBufferClients);
      writeClients = writeBufferClients;
   end

   Reg#(Bool) once <- mkReg(False);
   rule foobar if (!once);
      $display("read buffers %d read clients %d write buffers %d write clients %d", valueOf(NumReadBuffers), valueOf(NumReadClients), valueOf(NumWriteBuffers), valueOf(NumWriteClients));
      once <= True;
   endrule

   MemServer#(addrWidth, TMul#(32,N), NumMasters) dma <- mkMemServer(dmaIndicationProxy.ifc, readClients, writeClients);
   DmaConfigWrapper dmaConfigWrapper <- mkDmaConfigWrapper(DmaConfigPortal,dma.request);

   Vector#(7,StdPortal) portals;
   portals[0] = mmRequestWrapper.portalIfc;
   portals[1] = mmIndicationProxy.portalIfc;
   portals[2] = dmaConfigWrapper.portalIfc;
   portals[3] = dmaIndicationProxy.portalIfc;
   portals[4] = timerRequestWrapper.portalIfc;
   portals[5] = timerIndicationProxy.portalIfc;
   portals[6] = mmDebugIndicationProxy.portalIfc;
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = dma.masters;

endmodule : mkPortalTop

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;
import Connectable::*;

// portz libraries
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import PortalMemory::*;
import MemServer::*;
import PortalMemory::*;
import Dma::*;
import DmaUtils::*;
import RbmTypes::*;

// generated by tool
import DmaConfigWrapper::*;
import DmaIndicationProxy::*;
import MmIndicationProxy::*;
import MmRequestWrapper::*;
import TimerIndicationProxy::*;
import TimerRequestWrapper::*;
import MmDebugIndicationProxy::*;

// defined by user
import Matrix::*;

//typedef TAdd#(K,J) NumMasters;
`ifdef PCIE
typedef 1 NumMasters;
`else
typedef 1 NumMasters;
`endif

typedef TMul#(TDiv#(TAdd#(K,J),NumMasters),NumMasters)  NumReadBuffers;
typedef TMul#(TDiv#(J,NumMasters),NumMasters)  NumWriteBuffers;

typedef 1                                        ReadClientFanout;
typedef TDiv#(NumReadBuffers,ReadClientFanout)   NumReadClients;
typedef 1                                        WriteClientFanout;
typedef TDiv#(NumWriteBuffers,WriteClientFanout) NumWriteClients;

module [Module] mkPortalTop(PortalTop#(addrWidth,TMul#(32,N),Empty,NumMasters))
   provisos (Add#(a__, addrWidth, 40),
	     Add#(a__, b__, 40),
	     Add#(addrWidth, c__, 52),
	     Add#(addrWidth, d__, 64),
	     Add#(e__, f__, 40),
	     Add#(f__, 12, b__),
	     Add#(b__, g__, 44)
	     );

   MmDebugIndicationProxy mmDebugIndicationProxy <- mkMmDebugIndicationProxy(MmDebugIndicationPortal);

   DmaIndicationProxy dmaIndicationProxy <- mkDmaIndicationProxy(DmaIndicationPortal);

   MmDebugIndicationProxy mmDebugIndicationProxy <- mkMmDebugIndicationProxy(MmDebugIndicationPortal);
   MmIndicationProxy mmIndicationProxy <- mkMmIndicationProxy(MmIndicationPortal);
   TimerIndicationProxy timerIndicationProxy <- mkTimerIndicationProxy(TimerIndicationPortal);
   Mm#(N) mm <- mkMm(mmIndicationProxy.ifc, timerIndicationProxy.ifc, mmDebugIndicationProxy.ifc);
   MmRequestWrapper mmRequestWrapper <- mkMmRequestWrapper(MmRequestPortal,mm.mmRequest);
   TimerRequestWrapper timerRequestWrapper <- mkTimerRequestWrapper(TimerRequestPortal,mm.timerRequest);

   Vector#(NumReadBuffers, DmaReadBuffer#(TMul#(32,N),BurstLen)) read_buffers <- replicateM(mkDmaReadBuffer);
   zipWithM(mkConnection, mm.readClients, map(ors, read_buffers));
   let readBufferClients = map(orc, read_buffers);

   Vector#(NumReadClients,ObjectReadClient#(TMul#(32,N))) readClients;
   if (valueOf(NumReadClients) < valueOf(NumReadBuffers)) begin
      module mkFanoutReadClients#(Integer i)(ObjectReadClient#(TMul#(32,N)));
	 Vector#(ReadClientFanout, ObjectReadClient#(TMul#(32,N))) subReadClients = takeAt(i*valueOf(ReadClientFanout), readBufferClients);
	 let readMux <- mkDmaReadMux(subReadClients);
	 return readMux;
      endmodule
      readClients <- genWithM(mkFanoutReadClients);
   end
   else begin
      //readClients = take(readBufferClients);
      readClients = readBufferClients;
   end

   Vector#(NumWriteBuffers, DmaWriteBuffer#(TMul#(32,N),BurstLen)) write_buffers <- replicateM(mkDmaWriteBuffer);
   zipWithM(mkConnection, mm.writeClients, map(ows,takeAt(0,write_buffers)));
   let writeBufferClients = map(owc, write_buffers);

   Vector#(NumWriteClients,ObjectWriteClient#(TMul#(32,N))) writeClients;
   if (valueOf(NumWriteClients) < valueOf(NumWriteBuffers)) begin
      module mkFanoutWriteClients#(Integer i)(ObjectWriteClient#(TMul#(32,N)));
	 Vector#(WriteClientFanout, ObjectWriteClient#(TMul#(32,N))) subWriteClients = takeAt(i*valueOf(WriteClientFanout), writeBufferClients);
	 let writeMux <- mkDmaWriteMux(/* i*valueOf(WriteClientFanout), */ subWriteClients);
	 return writeMux;
      endmodule
      writeClients <- genWithM(mkFanoutWriteClients);
   end
   else begin
      //writeClients = take(writeBufferClients);
      writeClients = writeBufferClients;
   end

   Reg#(Bool) once <- mkReg(False);
   rule foobar if (!once);
      $display("read buffers %d read clients %d write buffers %d write clients %d", valueOf(NumReadBuffers), valueOf(NumReadClients), valueOf(NumWriteBuffers), valueOf(NumWriteClients));
      once <= True;
   endrule

   MemServer#(addrWidth, TMul#(32,N), NumMasters) dma <- mkMemServer(dmaIndicationProxy.ifc, readClients, writeClients);
   DmaConfigWrapper dmaConfigWrapper <- mkDmaConfigWrapper(DmaConfigPortal,dma.request);

   Vector#(7,StdPortal) portals;
   portals[0] = mmRequestWrapper.portalIfc;
   portals[1] = mmIndicationProxy.portalIfc;
   portals[2] = dmaConfigWrapper.portalIfc;
   portals[3] = dmaIndicationProxy.portalIfc;
   portals[4] = timerRequestWrapper.portalIfc;
   portals[5] = timerIndicationProxy.portalIfc;
   portals[6] = mmDebugIndicationProxy.portalIfc;
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = dma.masters;

endmodule : mkPortalTop