cleanup AxiGather

cleanup AxiGather

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

interface AxiMasterCommon;
    method Bit#(1)            aresetn();
    interface Axi3Master#(32,32,12) client;
endinterface

interface AxiSlaveCommon#(numeric type data_width, numeric type id_width);
    method Bit#(1)            aresetn();
    interface Axi3Slave#(32,data_width,id_width) server;
endinterface

interface AxiSlaveHighSpeed;
    interface AxiSlaveCommon#(64,6) axi;
    method Bit#(3)            racount();
    method Bit#(8)            rcount();
    method Action             rdissuecap1en(Bit#(1) v);
    method Bit#(6)            wacount();
    method Bit#(8)            wcount();
    method Action             wrissuecap1en(Bit#(1) v);
endinterface

interface AxiMasterWires;
   interface Wire#(Bit#(1)) arready;
   interface Wire#(Bit#(1)) awready;
   interface Wire#(Bit#(1)) rvalid;
   interface Wire#(Bit#(1)) wready;
   interface Wire#(Bit#(1)) bvalid;

   interface Wire#(Bit#(12)) rid;
   interface Wire#(Bit#(2))  rresp;
   interface Wire#(Bit#(32)) rdata;
   interface Wire#(Bit#(1))  rlast;
   interface Wire#(Bit#(12)) bid;
   interface Wire#(Bit#(2)) bresp;
endinterface

interface AxiSlaveWires#(numeric type data_width, numeric type id_width);
   interface Wire#(Bit#(32)) araddr;
   interface Wire#(Bit#(2)) arburst;
   interface Wire#(Bit#(4)) arcache;
   interface Wire#(Bit#(id_width)) arid;
   interface Wire#(Bit#(4)) arlen;
   interface Wire#(Bit#(2)) arlock;
   interface Wire#(Bit#(3)) arprot;
   interface Wire#(Bit#(4)) arqos;
   interface Wire#(Bit#(2)) arsize;
   interface Wire#(Bit#(5)) aruser;
   interface Wire#(Bit#(1)) arvalid;
   interface Wire#(Bit#(32)) awaddr;
   interface Wire#(Bit#(2)) awburst;
   interface Wire#(Bit#(4)) awcache;
   interface Wire#(Bit#(id_width)) awid;
   interface Wire#(Bit#(4)) awlen;
   interface Wire#(Bit#(2)) awlock;
   interface Wire#(Bit#(3)) awprot;
   interface Wire#(Bit#(4)) awqos;
   interface Wire#(Bit#(2)) awsize;
   interface Wire#(Bit#(5)) awuser;
   interface Wire#(Bit#(1)) awvalid;
   interface Wire#(Bit#(1)) rready;
   interface Wire#(Bit#(id_width)) wid;
   interface Wire#(Bit#(TDiv#(data_width,8))) wstrb;
   interface Wire#(Bit#(data_width)) wdata;
   interface Wire#(Bit#(1)) wlast;
   interface Wire#(Bit#(1)) wvalid;
   interface Wire#(Bit#(1)) bready;
endinterface

module mkAxiMasterWires(AxiMasterWires);
   Vector#(6, Wire#(Bit#(1))) wires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(32))) datawires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(12))) idwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) respwires <- replicateM(mkDWire(0));
   interface Wire arready = wires[0];
   interface Wire awready = wires[1];
   interface Wire rvalid = wires[2];
   interface Wire wready = wires[3];
   interface Wire rid  = idwires[0];
   interface Wire rresp  = respwires[0];
   interface Wire rdata  = datawires[0];
   interface Wire rlast  = wires[4];
   interface Wire bvalid = wires[5];
   interface Wire bid    = idwires[1];
   interface Wire bresp  = respwires[1];
endmodule

module mkAxiSlaveWires(AxiSlaveWires#(data_width, id_width));
   Vector#(5, Wire#(Bit#(1))) wires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(32))) addrwires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(data_width))) datawires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) burstwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(4))) cachewires <- replicateM(mkDWire(0));
   Vector#(3, Wire#(Bit#(id_width))) idwires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(TDiv#(data_width,8)))) strbwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(4))) lenwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) lockwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(3))) protwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(4))) qoswires <- replicateM(mkDWire(0));
   Vector#(3, Wire#(Bit#(1))) validwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) sizewires <- replicateM(mkDWire(0));
   Vector#(3, Wire#(Bit#(1))) readywires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(5))) userwires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(1))) lastwires <- replicateM(mkDWire(0));
   interface Wire araddr = addrwires[0];
   interface Wire arburst = burstwires[0];
   interface Wire arcache = cachewires[0];
   interface Wire arid = idwires[0];
   interface Wire arlen = lenwires[0];
   interface Wire arlock = lockwires[0];
   interface Wire arprot = protwires[0];
   interface Wire arqos = qoswires[0];
   interface Wire arsize = sizewires[0];
   interface Wire aruser = userwires[0];
   interface Wire arvalid = validwires[0];

   interface Wire awaddr = addrwires[1];
   interface Wire awburst = burstwires[1];
   interface Wire awcache = cachewires[1];
   interface Wire awid = idwires[1];
   interface Wire awlen = lenwires[1];
   interface Wire awlock = lockwires[1];
   interface Wire awprot = protwires[1];
   interface Wire awqos = qoswires[1];
   interface Wire awsize = sizewires[1];
   interface Wire awuser = userwires[1];
   interface Wire awvalid = validwires[1];

   interface Wire rready = readywires[0];
   interface Wire wid = idwires[2];
   interface Wire wstrb = strbwires[0];
   interface Wire wdata = datawires[0];
   interface Wire wlast = lastwires[0];
   interface Wire wvalid = validwires[2];
   interface Wire bready = readywires[1];
endmodule

module mkAxi3MasterGather#(Pps7Maxigp axiWires)(AxiMasterCommon);
   AxiMasterWires vtopmw <- mkAxiMasterWires;
   rule handshake1;
        axiWires.arready(vtopmw.arready);
   endrule
   rule handshake2;
        axiWires.awready(vtopmw.awready);
   endrule
   rule handshake3;
        axiWires.rid(vtopmw.rid);
        axiWires.rresp(vtopmw.rresp);
        axiWires.rdata(vtopmw.rdata);
        axiWires.rlast(vtopmw.rlast);
        axiWires.rvalid(vtopmw.rvalid);
   endrule
   rule handshake4;
        axiWires.wready(vtopmw.wready);
   endrule
   rule handshake5;
        axiWires.bvalid(vtopmw.bvalid);
        axiWires.bid(vtopmw.bid);
        axiWires.bresp(vtopmw.bresp);
   endrule

   interface Axi3Master client;
        interface Get req_ar;
             method ActionValue#(Axi3ReadRequest#(32,12)) get() if (axiWires.arvalid() != 0);
                 Axi3ReadRequest#(32,12) 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()};

                vtopmw.arready <= 1;

                return v;
            endmethod
        endinterface
        interface Get req_aw;
            method ActionValue#(Axi3WriteRequest#(32,12)) get() if (axiWires.awvalid() != 0);
                Axi3WriteRequest#(32,12) 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()};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

module mkAxiSlaveHighSpeedGather#(Pps7Saxihp axiWires)(AxiSlaveHighSpeed);
    AxiSlaveWires#(64,6) vtopsw <- mkAxiSlaveWires;
    rule handshake1;
          axiWires.araddr(vtopsw.araddr);
          axiWires.arburst(vtopsw.arburst);
          axiWires.arcache(vtopsw.arcache);
          axiWires.arid(vtopsw.arid);
          axiWires.arlen(vtopsw.arlen);
          axiWires.arlock(vtopsw.arlock);
          axiWires.arprot(vtopsw.arprot);
          axiWires.arqos(vtopsw.arqos);
          axiWires.arsize(vtopsw.arsize);
          axiWires.arvalid(vtopsw.arvalid);
    endrule
    rule handshake2;
          axiWires.awaddr(vtopsw.awaddr);
          axiWires.awburst(vtopsw.awburst);
          axiWires.awcache(vtopsw.awcache);
          axiWires.awid(vtopsw.awid);
          axiWires.awlen(vtopsw.awlen);
          axiWires.awlock(vtopsw.awlock);
          axiWires.awprot(vtopsw.awprot);
          axiWires.awqos(vtopsw.awqos);
          axiWires.awsize(vtopsw.awsize);
          axiWires.awvalid(vtopsw.awvalid);
    endrule
    rule handshake3;
       axiWires.rready(vtopsw.rready);
    endrule
    rule handshake4;
          axiWires.wid(vtopsw.wid);
          axiWires.wstrb(vtopsw.wstrb);
          axiWires.wdata(vtopsw.wdata);
          axiWires.wlast(vtopsw.wlast);
          axiWires.wvalid(vtopsw.wvalid);
    endrule
    rule handshake5;
         axiWires.bready(vtopsw.bready);
    endrule
    rule issuecap;
          axiWires.rdissuecap1en(0);
          axiWires.wrissuecap1en(0);
    endrule
    interface AxiSlaveCommon axi;
    interface Axi3Slave server;
    interface Put req_ar;
        method Action put(Axi3ReadRequest#(32,6) v) if (axiWires.arready() != 0);
           vtopsw.araddr <= v.address;
           vtopsw.arburst <= v.burst;
           vtopsw.arcache <= v.cache;
           vtopsw.arid <= v.id;
           vtopsw.arlen <= v.len;
           vtopsw.arlock <= v.lock;
           vtopsw.arprot <= v.prot;
           vtopsw.arqos <= v.qos;
           vtopsw.arsize <= v.size[1:0];

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

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

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

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

            vtopsw.bready <= 1;
            return v;
        endmethod
      endinterface: resp_b
    endinterface: server
    method aresetn = axiWires.aresetn;
    endinterface: axi
    method racount = axiWires.racount;
    method rcount = axiWires.rcount;
    method rdissuecap1en = axiWires.rdissuecap1en;
    method wacount = axiWires.wacount;
    method wcount = axiWires.wcount;
    method wrissuecap1en = axiWires.wrissuecap1en;
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::*;

interface AxiMasterCommon;
    method Bit#(1)            aresetn();
    interface Axi3Master#(32,32,12) client;
endinterface

interface AxiSlaveCommon#(numeric type data_width, numeric type id_width);
    method Bit#(1)            aresetn();
    interface Axi3Slave#(32,data_width,id_width) server;
endinterface

interface AxiSlaveHighSpeed;
    interface AxiSlaveCommon#(64,6) axi;
    method Bit#(3)            racount();
    method Bit#(8)            rcount();
    method Action             rdissuecap1en(Bit#(1) v);
    method Bit#(6)            wacount();
    method Bit#(8)            wcount();
    method Action             wrissuecap1en(Bit#(1) v);
endinterface

interface AxiMasterWires;
   interface Wire#(Bit#(1)) arready;
   interface Wire#(Bit#(1)) awready;
   interface Wire#(Bit#(1)) rvalid;
   interface Wire#(Bit#(1)) wready;
   interface Wire#(Bit#(1)) bvalid;

   interface Wire#(Bit#(12)) rid;
   interface Wire#(Bit#(2))  rresp;
   interface Wire#(Bit#(32)) rdata;
   interface Wire#(Bit#(1))  rlast;
   interface Wire#(Bit#(12)) bid;
   interface Wire#(Bit#(2)) bresp;
endinterface

interface AxiSlaveWires#(numeric type data_width, numeric type id_width);
   interface Wire#(Bit#(32)) araddr;
   interface Wire#(Bit#(2)) arburst;
   interface Wire#(Bit#(4)) arcache;
   interface Wire#(Bit#(id_width)) arid;
   interface Wire#(Bit#(4)) arlen;
   interface Wire#(Bit#(2)) arlock;
   interface Wire#(Bit#(3)) arprot;
   interface Wire#(Bit#(4)) arqos;
   interface Wire#(Bit#(2)) arsize;
   interface Wire#(Bit#(5)) aruser;
   interface Wire#(Bit#(1)) arvalid;
   interface Wire#(Bit#(32)) awaddr;
   interface Wire#(Bit#(2)) awburst;
   interface Wire#(Bit#(4)) awcache;
   interface Wire#(Bit#(id_width)) awid;
   interface Wire#(Bit#(4)) awlen;
   interface Wire#(Bit#(2)) awlock;
   interface Wire#(Bit#(3)) awprot;
   interface Wire#(Bit#(4)) awqos;
   interface Wire#(Bit#(2)) awsize;
   interface Wire#(Bit#(5)) awuser;
   interface Wire#(Bit#(1)) awvalid;
   interface Wire#(Bit#(1)) rready;
   interface Wire#(Bit#(id_width)) wid;
   interface Wire#(Bit#(TDiv#(data_width,8))) wstrb;
   interface Wire#(Bit#(data_width)) wdata;
   interface Wire#(Bit#(1)) wlast;
   interface Wire#(Bit#(1)) wvalid;
   interface Wire#(Bit#(1)) bready;
endinterface

module mkAxiMasterWires(AxiMasterWires);
   Vector#(6, Wire#(Bit#(1))) wires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(32))) datawires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(12))) idwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) respwires <- replicateM(mkDWire(0));
   interface Wire arready = wires[0];
   interface Wire awready = wires[1];
   interface Wire rvalid = wires[2];
   interface Wire wready = wires[3];
   interface Wire rid  = idwires[0];
   interface Wire rresp  = respwires[0];
   interface Wire rdata  = datawires[0];
   interface Wire rlast  = wires[4];
   interface Wire bvalid = wires[5];
   interface Wire bid    = idwires[1];
   interface Wire bresp  = respwires[1];
endmodule

module mkAxiSlaveWires(AxiSlaveWires#(data_width, id_width));
   Vector#(5, Wire#(Bit#(1))) wires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(32))) addrwires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(data_width))) datawires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) burstwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(4))) cachewires <- replicateM(mkDWire(0));
   Vector#(3, Wire#(Bit#(id_width))) idwires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(TDiv#(data_width,8)))) strbwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(4))) lenwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) lockwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(3))) protwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(4))) qoswires <- replicateM(mkDWire(0));
   Vector#(3, Wire#(Bit#(1))) validwires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(2))) sizewires <- replicateM(mkDWire(0));
   Vector#(3, Wire#(Bit#(1))) readywires <- replicateM(mkDWire(0));
   Vector#(2, Wire#(Bit#(5))) userwires <- replicateM(mkDWire(0));
   Vector#(1, Wire#(Bit#(1))) lastwires <- replicateM(mkDWire(0));
   interface Wire araddr = addrwires[0];
   interface Wire arburst = burstwires[0];
   interface Wire arcache = cachewires[0];
   interface Wire arid = idwires[0];
   interface Wire arlen = lenwires[0];
   interface Wire arlock = lockwires[0];
   interface Wire arprot = protwires[0];
   interface Wire arqos = qoswires[0];
   interface Wire arsize = sizewires[0];
   interface Wire aruser = userwires[0];
   interface Wire arvalid = validwires[0];

   interface Wire awaddr = addrwires[1];
   interface Wire awburst = burstwires[1];
   interface Wire awcache = cachewires[1];
   interface Wire awid = idwires[1];
   interface Wire awlen = lenwires[1];
   interface Wire awlock = lockwires[1];
   interface Wire awprot = protwires[1];
   interface Wire awqos = qoswires[1];
   interface Wire awsize = sizewires[1];
   interface Wire awuser = userwires[1];
   interface Wire awvalid = validwires[1];

   interface Wire rready = readywires[0];
   interface Wire wid = idwires[2];
   interface Wire wstrb = strbwires[0];
   interface Wire wdata = datawires[0];
   interface Wire wlast = lastwires[0];
   interface Wire wvalid = validwires[2];
   interface Wire bready = readywires[1];
endmodule

module mkAxi3MasterGather#(Pps7Maxigp axiWires)(AxiMasterCommon);
   AxiMasterWires vtopmw <- mkAxiMasterWires;
   rule axi_gp_handshake1;
        axiWires.arready(vtopmw.arready);
   endrule
   rule axi_gp_handshake2;
        axiWires.awready(vtopmw.awready);
   endrule
   rule axi_gp_handshake3;
        axiWires.rid(vtopmw.rid);
        axiWires.rresp(vtopmw.rresp);
        axiWires.rdata(vtopmw.rdata);
        axiWires.rlast(vtopmw.rlast);
        axiWires.rvalid(vtopmw.rvalid);
   endrule
   rule axi_gp_handshake4;
        axiWires.wready(vtopmw.wready);
   endrule
   rule axi_gp_handshake5;
        axiWires.bvalid(vtopmw.bvalid);
        axiWires.bid(vtopmw.bid);
        axiWires.bresp(vtopmw.bresp);
   endrule

   interface Axi3Master client;
        interface Get req_ar;
             method ActionValue#(Axi3ReadRequest#(32,12)) get() if (axiWires.arvalid() != 0);
                 Axi3ReadRequest#(32,12) 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()};

                vtopmw.arready <= 1;

                return v;
            endmethod
        endinterface
        interface Get req_aw;
            method ActionValue#(Axi3WriteRequest#(32,12)) get() if (axiWires.awvalid() != 0);
                Axi3WriteRequest#(32,12) 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()};

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

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

module mkAxi3SlaveGather#(Pps7Saxigp axiWires)(AxiSlaveCommon#(32,6));
    AxiSlaveWires#(32,6) vtopsw <- mkAxiSlaveWires;
    rule axi_gp_handshake11;
          axiWires.araddr(vtopsw.araddr);
          axiWires.arburst(vtopsw.arburst);
          axiWires.arcache(vtopsw.arcache);
          axiWires.arid(vtopsw.arid);
          axiWires.arlen(vtopsw.arlen);
          axiWires.arlock(vtopsw.arlock);
          axiWires.arprot(vtopsw.arprot);
          axiWires.arqos(vtopsw.arqos);
          axiWires.arsize(vtopsw.arsize);
          axiWires.arvalid(vtopsw.arvalid);
    endrule
    rule axi_gp_handshake12;
          axiWires.awaddr(vtopsw.awaddr);
          axiWires.awburst(vtopsw.awburst);
          axiWires.awcache(vtopsw.awcache);
          axiWires.awid(vtopsw.awid);
          axiWires.awlen(vtopsw.awlen);
          axiWires.awlock(vtopsw.awlock);
          axiWires.awprot(vtopsw.awprot);
          axiWires.awqos(vtopsw.awqos);
          axiWires.awsize(vtopsw.awsize);
          axiWires.awvalid(vtopsw.awvalid);
    endrule
    rule axi_gp_handshake13;
         axiWires.rready(vtopsw.rready);
    endrule
    rule axi_gp_handshake14;
          axiWires.wid(vtopsw.wid);
          axiWires.wstrb(vtopsw.wstrb);
          axiWires.wdata(vtopsw.wdata);
          axiWires.wlast(vtopsw.wlast);
          axiWires.wvalid(vtopsw.wvalid);
    endrule
    rule axi_gp_handshake15;
         axiWires.bready(vtopsw.bready);
    endrule
    interface Axi3Slave server;
    interface Put req_ar;
        method Action put(Axi3ReadRequest#(32,6) v) if (axiWires.arready() != 0);
           vtopsw.araddr <= v.address;
           vtopsw.arburst <= v.burst;
           vtopsw.arcache <= v.cache;
           vtopsw.arid <= v.id;
           vtopsw.arlen <= v.len;
           vtopsw.arlock <= v.lock;
           vtopsw.arprot <= v.prot;
           vtopsw.arqos <= v.qos;
           vtopsw.arsize <= v.size[1:0];

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

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

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

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

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

module mkAxi3SlaveGather64#(Pps7Saxiacp axiWires)(AxiSlaveCommon#(64,3));
    AxiSlaveWires#(64,3) vtopsw <- mkAxiSlaveWires;
    rule axi_acp_handshake1;
          axiWires.araddr(vtopsw.araddr);
          axiWires.arburst(vtopsw.arburst);
          axiWires.arcache(vtopsw.arcache);
          axiWires.arid(vtopsw.arid);
          axiWires.arlen(vtopsw.arlen);
          axiWires.arlock(vtopsw.arlock);
          axiWires.arprot(vtopsw.arprot);
          axiWires.arqos(vtopsw.arqos);
          axiWires.arsize(vtopsw.arsize);
          axiWires.aruser(vtopsw.aruser);
          axiWires.arvalid(vtopsw.arvalid);
    endrule
    rule axi_acp_handshake2;
          axiWires.awaddr(vtopsw.awaddr);
          axiWires.awburst(vtopsw.awburst);
          axiWires.awcache(vtopsw.awcache);
          axiWires.awid(vtopsw.awid);
          axiWires.awlen(vtopsw.awlen);
          axiWires.awlock(vtopsw.awlock);
          axiWires.awprot(vtopsw.awprot);
          axiWires.awqos(vtopsw.awqos);
          axiWires.awsize(vtopsw.awsize);
          axiWires.awuser(vtopsw.awuser);
          axiWires.awvalid(vtopsw.awvalid);
    endrule
    rule axi_acp_handshake3;
         axiWires.rready(vtopsw.rready);
    endrule
    rule axi_acp_handshake4;
          axiWires.wid(vtopsw.wid);
          axiWires.wstrb(vtopsw.wstrb);
          axiWires.wdata(vtopsw.wdata);
          axiWires.wlast(vtopsw.wlast);
          axiWires.wvalid(vtopsw.wvalid);
    endrule
    rule axi_acp_handshake5;
         axiWires.bready(vtopsw.bready);
    endrule
    interface Axi3Slave server;
    interface Put req_ar;
        method Action put(Axi3ReadRequest#(32,3) v) if (axiWires.arready() != 0);
           vtopsw.araddr <= v.address;
           vtopsw.arburst <= v.burst;
           vtopsw.arcache <= v.cache;
           vtopsw.arid <= v.id;
           vtopsw.arlen <= v.len;
           vtopsw.arlock <= v.lock;
           vtopsw.arprot <= v.prot;
           vtopsw.arqos <= v.qos;
           vtopsw.arsize <= v.size[1:0];

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

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

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

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

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

module mkAxiSlaveHighSpeedGather#(Pps7Saxihp axiWires)(AxiSlaveHighSpeed);
    AxiSlaveWires#(64,6) vtopsw <- mkAxiSlaveWires;
    rule axi_hp_handshake1;
          axiWires.araddr(vtopsw.araddr);
          axiWires.arburst(vtopsw.arburst);
          axiWires.arcache(vtopsw.arcache);
          axiWires.arid(vtopsw.arid);
          axiWires.arlen(vtopsw.arlen);
          axiWires.arlock(vtopsw.arlock);
          axiWires.arprot(vtopsw.arprot);
          axiWires.arqos(vtopsw.arqos);
          axiWires.arsize(vtopsw.arsize);
          axiWires.arvalid(vtopsw.arvalid);
    endrule
    rule axi_hp_handshake2;
          axiWires.awaddr(vtopsw.awaddr);
          axiWires.awburst(vtopsw.awburst);
          axiWires.awcache(vtopsw.awcache);
          axiWires.awid(vtopsw.awid);
          axiWires.awlen(vtopsw.awlen);
          axiWires.awlock(vtopsw.awlock);
          axiWires.awprot(vtopsw.awprot);
          axiWires.awqos(vtopsw.awqos);
          axiWires.awsize(vtopsw.awsize);
          axiWires.awvalid(vtopsw.awvalid);
    endrule
    rule axi_hp_handshake3;
       axiWires.rready(vtopsw.rready);
    endrule
    rule axi_hp_handshake4;
          axiWires.wid(vtopsw.wid);
          axiWires.wstrb(vtopsw.wstrb);
          axiWires.wdata(vtopsw.wdata);
          axiWires.wlast(vtopsw.wlast);
          axiWires.wvalid(vtopsw.wvalid);
    endrule
    rule axi_hp_handshake5;
         axiWires.bready(vtopsw.bready);
    endrule
    rule issuecap;
          axiWires.rdissuecap1en(0);
          axiWires.wrissuecap1en(0);
    endrule
    interface AxiSlaveCommon axi;
    interface Axi3Slave server;
    interface Put req_ar;
        method Action put(Axi3ReadRequest#(32,6) v) if (axiWires.arready() != 0);
           vtopsw.araddr <= v.address;
           vtopsw.arburst <= v.burst;
           vtopsw.arcache <= v.cache;
           vtopsw.arid <= v.id;
           vtopsw.arlen <= v.len;
           vtopsw.arlock <= v.lock;
           vtopsw.arprot <= v.prot;
           vtopsw.arqos <= v.qos;
           vtopsw.arsize <= v.size[1:0];

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

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

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

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

            vtopsw.bready <= 1;
            return v;
        endmethod
      endinterface: resp_b
    endinterface: server
    method aresetn = axiWires.aresetn;
    endinterface: axi
    method racount = axiWires.racount;
    method rcount = axiWires.rcount;
    method rdissuecap1en = axiWires.rdissuecap1en;
    method wacount = axiWires.wacount;
    method wcount = axiWires.wcount;
    method wrissuecap1en = axiWires.wrissuecap1en;
endmodule


adding previous ver of EthMac

adding previous ver of EthMac

// Copyright (c) 2014 Cornell University.

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

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

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

package EthMac;

import Clocks::*;
import Vector::*;
import Connectable                   ::*;
import Pipe                          ::*;
import FIFOF                         ::*;
import GetPut                        ::*;
import Pipe::*;
import DefaultValue::*;
import OInt::*;

import AlteraMacWrap::*;
import Ethernet::*;

interface EthMacIfc;
   (* always_ready, always_enabled *)
   method Bit#(72) tx;
   (* always_ready, always_enabled *)
   method Action rx (Bit#(72) v);
   interface Put#(PacketDataT#(64)) packet_tx;
   interface Get#(PacketDataT#(64)) packet_rx;
endinterface

typedef struct {
   Bit#(n) data;
   Bit#(TDiv#(n, 8)) mask;
   Bit#(1) sop;
   Bit#(1) eop;
} PacketDataT#(numeric type n) deriving (Bits,Eq);

instance DefaultValue#(PacketDataT#(64));
    defaultValue = PacketDataT {
        data : 0,
        mask : 0,
        sop : 0,
        eop : 0
    };
endinstance

// Mac Wrapper
(* synthesize *)
module mkEthMac#(Clock clk_50, Clock clk_156_25, Clock rx_clk, Reset rst_156_25_n)(EthMacIfc);
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;

   Reset rx_rst_n <- mkAsyncReset(2, rst_156_25_n, rx_clk);
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, clk_50);

   // Wire data_dw
   Wire#(Maybe#(Bit#(64))) tx_data_w <- mkDWire(tagged Invalid, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(3)) tx_empty_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_ready_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_sop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_eop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);

   FIFOF#(PacketDataT#(64)) rx_fifo <- mkFIFOF(clocked_by rx_clk, reset_by rx_rst_n);

   MacWrap mac <- mkMacWrap(clk_50, clk_156_25, rx_clk, rst_50_n, rst_156_25_n, rx_rst_n, clocked_by clk_156_25, reset_by rst_156_25_n);

   rule tx_ready;
      tx_ready_w <= mac.tx.fifo_in_ready();
   endrule

   rule tx_data;
      mac.tx.fifo_in_data(fromMaybe(0,tx_data_w));
   endrule

   rule tx_sop;
      mac.tx.fifo_in_startofpacket(tx_sop_w);
   endrule

   rule tx_eop;
      mac.tx.fifo_in_endofpacket(tx_eop_w);
   endrule

   rule tx_empty;
      mac.tx.fifo_in_empty(tx_empty_w);
   endrule

   rule tx_error;
      mac.tx.fifo_in_error(1'b0);
   endrule

   rule tx_valid;
      mac.tx.fifo_in_valid(pack(isValid(tx_data_w)));
   endrule

   rule rx_data;
      let valid = mac.rx.fifo_out_valid();

      PacketDataT#(64) packet = defaultValue;
      packet.data = mac.rx.fifo_out_data();
      packet.sop = mac.rx.fifo_out_startofpacket();
      packet.eop = mac.rx.fifo_out_endofpacket();
      packet.mask = 1<<mac.rx.fifo_out_empty() - 1;

      if (valid == 1'b1) begin
         rx_fifo.enq(packet);
      end
   endrule

   rule rx_ready;
      mac.rx.fifo_out_ready(pack(rx_fifo.notFull));
   endrule

   method tx = mac.xgmii.tx_data;
   method Action rx(x) = mac.xgmii.rx_data(x);
   interface Put packet_tx;
      method Action put(PacketDataT#(64) d) if (tx_ready_w != 0);
         Bit#(3) tx_empty = truncate(pack(countOnes(maxBound-unpack(d.mask))));
         //Bit#(3) tx_empty = truncate(fromOInt(unpack(d.mask + 1)));
         tx_data_w <= tagged Valid pack(d.data);
         tx_empty_w <= tx_empty;
         tx_sop_w <= pack(d.sop);
         tx_eop_w <= pack(d.eop);
         //$display("tx_empty %h", tx_empty);
      endmethod
   endinterface
   interface Get packet_rx = toGet(rx_fifo);
endmodule
endpackage: EthMac

// Copyright (c) 2014 Cornell University.

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

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

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

package EthMac;

import Clocks::*;
import Vector::*;
import Connectable                   ::*;
import Pipe                          ::*;
import FIFOF                         ::*;
import GetPut                        ::*;
import Pipe::*;
import DefaultValue::*;
import OInt::*;

import AlteraMacWrap::*;
import Ethernet::*;

interface EthMacIfc;
   (* always_ready, always_enabled *)
   interface Get#(Bit#(72)) tx;
   (* always_ready, always_enabled *)
   interface Put#(Bit#(72)) rx;
   interface Put#(PacketDataT#(64)) packet_tx;
   interface Get#(PacketDataT#(64)) packet_rx;
endinterface

typedef struct {
   Bit#(n) data;
   Bit#(TDiv#(n, 8)) mask;
   Bit#(1) sop;
   Bit#(1) eop;
} PacketDataT#(numeric type n) deriving (Bits,Eq);

instance DefaultValue#(PacketDataT#(64));
    defaultValue = PacketDataT {
        data : 0,
        mask : 0,
        sop : 0,
        eop : 0
    };
endinstance

// Mac Wrapper
(* synthesize *)
module mkEthMac#(Clock clk_50, Clock clk_156_25, Clock rx_clk, Reset rst_156_25_n)(EthMacIfc);
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;

   Reset rx_rst_n <- mkAsyncReset(2, rst_156_25_n, rx_clk);
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, clk_50);

   // Wire data_dw
   Wire#(Maybe#(Bit#(64))) tx_data_w <- mkDWire(tagged Invalid, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(3)) tx_empty_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_ready_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_sop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_eop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);

   FIFOF#(PacketDataT#(64)) rx_fifo <- mkFIFOF(clocked_by rx_clk, reset_by rx_rst_n);

   MacWrap mac <- mkMacWrap(clk_50, clk_156_25, rx_clk, rst_50_n, rst_156_25_n, rx_rst_n, clocked_by clk_156_25, reset_by rst_156_25_n);

   rule tx_ready;
      tx_ready_w <= mac.tx.fifo_in_ready();
   endrule

   rule tx_data;
      mac.tx.fifo_in_data(fromMaybe(0,tx_data_w));
   endrule

   rule tx_sop;
      mac.tx.fifo_in_startofpacket(tx_sop_w);
   endrule

   rule tx_eop;
      mac.tx.fifo_in_endofpacket(tx_eop_w);
   endrule

   rule tx_empty;
      mac.tx.fifo_in_empty(tx_empty_w);
   endrule

   rule tx_error;
      mac.tx.fifo_in_error(1'b0);
   endrule

   rule tx_valid;
      mac.tx.fifo_in_valid(pack(isValid(tx_data_w)));
   endrule

   rule rx_data;
      let valid = mac.rx.fifo_out_valid();

      PacketDataT#(64) packet = defaultValue;
      packet.data = mac.rx.fifo_out_data();
      packet.sop = mac.rx.fifo_out_startofpacket();
      packet.eop = mac.rx.fifo_out_endofpacket();
      packet.mask = 1<<mac.rx.fifo_out_empty() - 1;

      if (valid == 1'b1) begin
         rx_fifo.enq(packet);
      end
   endrule

   rule rx_ready;
      mac.rx.fifo_out_ready(pack(rx_fifo.notFull));
   endrule

   interface Get tx;
      method ActionValue#(Bit#(72)) get;
         return mac.xgmii.tx_data;
      endmethod
   endinterface
   interface Put rx;
      method Action put(Bit#(72) v);
         mac.xgmii.rx_data(v);
      endmethod
   endinterface
   interface Put packet_tx;
      method Action put(PacketDataT#(64) d) if (tx_ready_w != 0);
         Bit#(3) tx_empty = truncate(pack(countOnes(maxBound-unpack(d.mask))));
         //Bit#(3) tx_empty = truncate(fromOInt(unpack(d.mask + 1)));
         tx_data_w <= tagged Valid pack(d.data);
         tx_empty_w <= tx_empty;
         tx_sop_w <= pack(d.sop);
         tx_eop_w <= pack(d.eop);
         //$display("tx_empty %h", tx_empty);
      endmethod
   endinterface
   interface Get packet_rx = toGet(rx_fifo);
endmodule
endpackage: EthMac


do not release the rename_tag until all beats of request have been received, even if response is split

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

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

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

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

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

// CONNECTAL Libraries
import MemTypes::*;
import ConnectalMemory::*;
import ConnectalClocks::*;
import MMU::*;
import ConnectalCompletionBuffer::*;

typedef 32 BeatCountSize;

typedef 9 MMU_PIPELINE_DEPTH;

interface DmaDbg;
   method ActionValue#(Bit#(64)) getMemoryTraffic();
   method ActionValue#(DmaDbgRec) dbg();
endinterface

interface MemWriteInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemWriteClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, MemWriteServer#(busWidth)) servers;
endinterface

interface MemReadInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemReadClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, MemReadServer#(busWidth)) servers;
endinterface

function Bool sglid_outofrange(SGLId p);
   return ((p[15:0]) >= fromInteger(valueOf(MaxNumSGLists)));
endfunction

import RegFile::*;

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

typedef struct {MemRequest req;
		Bit#(addrWidth) pa;
		Bit#(MemTagSize) rename_tag;
		Bit#(TLog#(TMax#(1,numClients))) client; } RRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {Bit#(MemTagSize) req_tag;
		Bit#(BurstLenSize) req_burstLen;
		Bit#(MemTagSize) rename_tag;
		Bit#(TLog#(TMax#(1,numClients))) client;
		Bool last;
   } DRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

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

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

module mkMemReadInternal#(MemServerIndication ind,
			  Vector#(numMMUs,Server#(AddrTransRequest,Bit#(addrWidth))) mmus)
   (MemReadInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
	    ,Div#(busWidth,8,busWidthBytes)
	    ,Add#(beatShift, a__, 8)
	    ,Add#(b__, TLog#(numTags), 6)
	    ,Add#(beatShift, c__, BurstLenSize)
	    );

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = MMU_PIPELINE_DEPTH)
   FIFO#(LRec#(numServers,addrWidth)) clientRequest <- mkSizedFIFO(valueOf(MMU_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth))  serverRequest <- mkFIFO;
   // stage 2: read commands
   BRAM_Configure bramConfig = defaultValue;
   if (mainClockPeriod < 8)
      bramConfig.latency = 2;
   BRAM2Port#(Bit#(TLog#(numTags)), DRec#(numServers,addrWidth)) serverProcessing <- mkBRAM2Server(bramConfig);
   BRAM2Port#(Bit#(TAdd#(TLog#(numTags),TSub#(BurstLenSize,beatShift))), MemData#(busWidth)) clientData <- mkBRAM2Server(bramConfig);
   // stage 3: read data
   FIFO#(MemData#(busWidth)) serverData <- mkFIFO;

   let verbose = False;

   RegFile#(Bit#(TLog#(numTags)),Tuple2#(Bool,Bit#(BurstLenSize))) clientBurstLen <- mkRegFileFull();
   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);

   Reg#(Bit#(32))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   TagGen#(numTags) tag_gen <- mkTagGen;

   Reg#(Bit#(BurstLenSize))      compCountReg <- mkReg(0);
   Reg#(Bit#(TLog#(numTags)))    compTagReg <- mkReg(0);
   Reg#(Bit#(TLog#(TMax#(1,numServers)))) compClientReg <- mkReg(0);
   Reg#(Bit#(2))                 compTileReg <- mkReg(0);
   FIFO#(Bit#(TAdd#(1,TLog#(TMax#(1,numServers))))) clientSelect <- mkFIFO;
   FIFO#(Bit#(TLog#(numTags)))   serverTag <- mkFIFO;

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

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

   rule checkMmuResp;
      let request <- toGet(clientRequest).get();
      let physAddr <- mmus[request.req.sglId[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      let burstLenBeats = request.req.burstLen >> beat_shift;
      clientBurstLen.upd(truncate(rename_tag), tuple2(burstLenBeats == 1, burstLenBeats));

      serverRequest.enq(RRec{req:request.req, pa:physAddr, client:request.client, rename_tag:extend(rename_tag)});
      if (verbose) $display("mkMemReadInternal::checkMmuResp: client=%d, tag=%d rename_tag=%d burstLen=%d", request.client, request.req.tag, rename_tag, burstLenBeats);
      if (verbose) $display("mkMemReadInternal::mmuResp %d %d", request.client, cycle_cnt-last_mmuResp);
      last_mmuResp <= cycle_cnt;
   endrule

   rule read_data;
      let response <- toGet(serverData).get();
      let drq <- serverProcessing.portA.response.get;
      let tag = drq.req_tag;
      match { .last, .burstLen } = clientBurstLen.sub(truncate(response.tag));
      let first   = firstReg;
      if (first) begin
	 dynamicAssert(last == (burstLen==1), "Last incorrect");
      end
      if (last && burstLen != 1)
	 $display("rename_tag=%d tag=%d burstLen=%d last=%d", response.tag, tag, burstLen, last);
      Bit#(TLog#(numTags)) tt = truncate(response.tag);
      clientData.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, datain:MemData{data: response.data, tag: tag, last: last},
					       address:{tt,truncate(burstLen)}});
      if (last) begin
	 tag_gen.returnTag(truncate(response.tag));
      end
      last_readData <= cycle_cnt;
      if (verbose) $display("mkMemReadInternal::read_data cyclediff %d", cycle_cnt-last_readData);
      clientBurstLen.upd(truncate(response.tag), tuple2((burstLen-1 == 1),burstLen-1));
      firstReg <= response.last;
   endrule

   rule tag_completed;
      let tag <- tag_gen.complete;
      serverProcessing.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
      serverTag.enq(tag);
      if(verbose) $display("mkMemReadInternal::complete_burst0 %h", tag);
   endrule

   rule complete_burst1a if (compCountReg==0);
      let drq <- serverProcessing.portB.response.get;
      let req_burstLen = drq.req_burstLen;
      let client = drq.client;
      let cnt = req_burstLen >> beat_shift;
      let tag <- toGet(serverTag).get;
      if(killv[drq.req_tag[5:4]] == False) begin
	 clientSelect.enq(extend(client));
	 clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      compTagReg <= tag;
      compClientReg <= client;
      compTileReg <= drq.req_tag[5:4];
      if(verbose) $display("mkMemReadInternal::complete_burst1a %h", client);
   endrule

   rule burst_remainder if (compCountReg > 0);
      let cnt = compCountReg;
      let tag = compTagReg;
      let client = compClientReg;
      if(killv[compTileReg] == False) begin
	 clientSelect.enq(extend(client));
	 clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      if(verbose) $display("mkMemReadInternal::complete_burst1b count %h", compCountReg);
   endrule

   Vector#(numServers, MemReadServer#(busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface MemReadServer;
		  interface Put readReq;
		     method Action put(MemRequest req);
			last_loadClient <= cycle_cnt;
			let mmusel = req.sglId[31:16];
      			if (verbose) $display("mkMemReadInternal::loadClient server %d mmusel %d burstLen %d tag %d cycle %d",
			   i, mmusel, req.burstLen >> beat_shift, req.tag, cycle_cnt-last_loadClient);
			if (mmusel >= fromInteger(valueOf(numMMUs)))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorMMUOutOfRange_r, pref: req.sglId });
   			else if (sglid_outofrange(req.sglId))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorSGLIdOutOfRange_r, pref: req.sglId });
   			else if (stopv[req.tag[5:4]] == False) begin
   			   clientRequest.enq(LRec{req:req, client:fromInteger(i)});
   			   mmus[mmusel].request.put(AddrTransRequest{id:truncate(req.sglId),off:req.offset});
   			end
		     endmethod
		  endinterface
		  interface Get readData;
		     method ActionValue#(MemData#(busWidth)) get if (clientSelect.first == fromInteger(i));
			clientSelect.deq;
			let data <- clientData.portB.response.get;
			if (verbose) $display("mkMemReadInternal::comp server %d data %x cycle %d", i, data.data, cycle_cnt-last_comp);
			last_comp <= cycle_cnt;
			return data;
		     endmethod
		  endinterface
	       endinterface);

   interface servers = sv;
   interface PhysMemReadClient client;
      interface Get readReq;
	 method ActionValue#(PhysMemRequest#(addrWidth,dataWidth)) get();
	    let request <- toGet(serverRequest).get;
	    let req = request.req;
	    if (False && request.pa[31:24] != 0)
	       $display("mkMemReadInternal::req_ar: funny physAddr req.sglId=%d req.offset=%h physAddr=%h", req.sglId, req.offset, request.pa);
	    serverProcessing.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(request.rename_tag),
						   datain:DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:request.client, rename_tag:request.rename_tag, last:(req.burstLen == fromInteger(valueOf(busWidthBytes)))}});
	    //$display("mkMemReadInternal::readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", request.client,request.rename_tag,request.pa, req.burstLen, beat_shift, req.burstLen == beat_shift);
	    if (verbose) $display("mkMemReadInternal::read_client.readReq %d", cycle_cnt-last_readReq);
	    last_readReq <= cycle_cnt;
	    return PhysMemRequest{addr:request.pa, burstLen:req.burstLen, tag:request.rename_tag
`ifdef BYTE_ENABLES
				  , firstbe: request.req.firstbe, lastbe: request.req.lastbe
`endif
	       };
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(MemData#(busWidth) response);
	    serverData.enq(response);
	    serverProcessing.portA.request.put(BRAMRequest{write:False, address:truncate(response.tag), datain: ?, responseOnWrite: ?});
	    beatCount <= beatCount+1;
	 endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
	 let tile = tc.tile;
	 let kv = True;
	 let sv = True;
	 if (tc.state == Running || tc.state == Stopped)
	    kv = False;
	 if (tc.state == Running)
	    sv = False;
	 killv[tile] <= kv;
	 stopv[tile] <= sv;
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:0, y:0, z:0, w:0};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return extend(beatCount);
      endmethod
   endinterface
endmodule

module mkMemWriteInternal#(MemServerIndication ind,
			   Vector#(numMMUs,Server#(AddrTransRequest,Bit#(addrWidth))) mmus)
   (MemWriteInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
	    ,Div#(busWidth,8,busWidthBytes)
	    ,Add#(beatShift, a__, 8)
	    ,Add#(b__, TLog#(numTags), 6)
	    ,Add#(beatShift, c__, BurstLenSize)
	    );

   let verbose = False;

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = MMU_PIPELINE_DEPTH)
   FIFO#(LRec#(numServers,addrWidth)) clientRequest <- mkSizedFIFO(valueOf(MMU_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth))  serverRequest <- mkFIFO;
   // stage 2: write commands
   FIFO#(DRec#(numServers, addrWidth)) serverProcessing <- mkSizedFIFO(valueOf(numTags));
   // stage 3: write data
   BRAM2Port#(Bit#(TLog#(numTags)), RResp#(numServers,addrWidth)) respFifos <- mkBRAM2Server(defaultValue);
   TagGen#(numTags) tag_gen <- mkTagGen;
   FIFO#(RResp#(numServers,addrWidth)) clientResponse <- mkFIFO;

   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);
   Reg#(Bool)               lastReg <- mkReg(False);
   Reg#(Bit#(BeatCountSize)) beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_mmuResp <- mkReg(0);

   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

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

   rule checkMmuResp;
      let request <- toGet(clientRequest).get;
      let req = request.req;
      let client = request.client;
      let physAddr <- mmus[req.sglId[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      serverRequest.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //if (verbose) $display("mkMemWriteInternal::checkMmuResp: client=%d, rename_tag=%d", client,rename_tag);
      if (verbose) $display("mkMemWriteInternal::mmuResp %d %d", client, cycle_cnt-last_mmuResp);
      last_mmuResp <= cycle_cnt;
   endrule

   rule writeDoneComp0;
      let tag <- tag_gen.complete;
      respFifos.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
   endrule

   FIFO#(MemData#(busWidth)) memDataFifo <- mkFIFO();
   Vector#(numServers, FIFO#(MemData#(busWidth))) clientWriteData <- replicateM(mkFIFO);

   if(valueOf(numServers) > 0)
      rule memdata;
	 let drq = serverProcessing.first;
	 let req_tag = drq.req_tag;
	 let req_burstLen = drq.req_burstLen;
	 let rename_tag = drq.rename_tag;
	 let client = drq.client;
	 MemData#(busWidth) tagdata = unpack(0);
	 if (killv[req_tag[5:4]] == False) begin
	    tagdata = clientWriteData[client].first;
	    clientWriteData[client].deq;
	 end
	 let burstLen = burstReg;
	 let first    = firstReg;
	 let last     = lastReg;
	 if (first) begin
	    burstLen = req_burstLen >> beat_shift;
	    last     = serverProcessing.first.last;
	    respFifos.portA.request.put(BRAMRequest{write:True,responseOnWrite:False, address:truncate(rename_tag), datain:RResp{orig_tag:req_tag, client:client}});
	 end
	 burstReg <= burstLen-1;
	 firstReg <= (burstLen-1 == 0);
	 lastReg  <= (burstLen-1 == 1);
	 beatCount <= beatCount+1;
	 if (last)
	    serverProcessing.deq();
	 //$display("mkMemWriteInternal::writeData: client=%d, rename_tag=%d", client, rename_tag);
	 memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: last });
      endrule

   rule fill_clientResponse;
      let rv <- respFifos.portB.response.get;
      clientResponse.enq(rv);
   endrule

   Vector#(numServers, MemWriteServer#(busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface MemWriteServer;
		  interface Put writeReq;
		     method Action put(MemRequest req);
      			if (verbose) $display("mkMemWriteInternal::loadClient %d %d", i, cycle_cnt-last_loadClient);
			last_loadClient <= cycle_cnt;
			let mmusel = req.sglId[31:16];
			if (mmusel >= fromInteger(valueOf(numMMUs)))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorMMUOutOfRange_w, pref: req.sglId });
   			else if (sglid_outofrange(req.sglId))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorSGLIdOutOfRange_w, pref: req.sglId });
   			else if (stopv[req.tag[5:4]] == False) begin
   			   clientRequest.enq(LRec{req:req, client:fromInteger(i)});
   			   mmus[mmusel].request.put(AddrTransRequest{id:truncate(req.sglId),off:req.offset});
   			end
		     endmethod
		  endinterface
		  interface Put writeData = toPut(clientWriteData[i]);
		  interface Get writeDone;
		     method ActionValue#(Bit#(MemTagSize)) get if (clientResponse.first.client == fromInteger(i));
			clientResponse.deq;
			return clientResponse.first.orig_tag;
		     endmethod
		  endinterface
	       endinterface);

   interface servers = sv;
   interface PhysMemWriteClient client;
      interface Get writeReq;
	 method ActionValue#(PhysMemRequest#(addrWidth,dataWidth)) get();
	    let request <- toGet(serverRequest).get();
	    let req = request.req;
	    let physAddr = request.pa;
	    let client = request.client;
	    let rename_tag = request.rename_tag;
	    serverProcessing.enq(DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:client, rename_tag:rename_tag, last: (req.burstLen == fromInteger(valueOf(busWidthBytes))) });
	    //$display("mkMemWriteInternal::writeReq: client=%d, rename_tag=%d", client,rename_tag);
	    return PhysMemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)
`ifdef BYTE_ENABLES
				  , firstbe: req.firstbe, lastbe: req.lastbe
`endif
};
	 endmethod
      endinterface
      interface Get writeData = toGet(memDataFifo);
      interface Put writeDone;
	 method Action put(Bit#(MemTagSize) resp);
	    tag_gen.returnTag(truncate(resp));
	    if (verbose) $display("mkMemWriteInternal::writeDone: resp=%d", resp);
	 endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
	 let tile = tc.tile;
	 let kv = True;
	 let sv = True;
	 if (tc.state == Running || tc.state == Stopped)
	    kv = False;
	 if (tc.state == Running)
	    sv = False;
	 killv[tile] <= kv;
	 stopv[tile] <= sv;
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:fromInteger(valueOf(numServers)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return extend(beatCount);
      endmethod
   endinterface
endmodule

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

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

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

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

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

// CONNECTAL Libraries
import MemTypes::*;
import ConnectalMemory::*;
import ConnectalClocks::*;
import MMU::*;
import ConnectalCompletionBuffer::*;

typedef 32 BeatCountSize;

typedef 9 MMU_PIPELINE_DEPTH;

interface DmaDbg;
   method ActionValue#(Bit#(64)) getMemoryTraffic();
   method ActionValue#(DmaDbgRec) dbg();
endinterface

interface MemWriteInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemWriteClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, MemWriteServer#(busWidth)) servers;
endinterface

interface MemReadInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemReadClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, MemReadServer#(busWidth)) servers;
endinterface

function Bool sglid_outofrange(SGLId p);
   return ((p[15:0]) >= fromInteger(valueOf(MaxNumSGLists)));
endfunction

import RegFile::*;

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

typedef struct {MemRequest req;
		Bit#(addrWidth) pa;
		Bit#(MemTagSize) rename_tag;
		Bit#(TLog#(TMax#(1,numClients))) client; } RRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {Bit#(MemTagSize) req_tag;
		Bit#(BurstLenSize) req_burstLen;
		Bit#(MemTagSize) rename_tag;
		Bit#(TLog#(TMax#(1,numClients))) client;
		Bool last;
   } DRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

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

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

module mkMemReadInternal#(MemServerIndication ind,
			  Vector#(numMMUs,Server#(AddrTransRequest,Bit#(addrWidth))) mmus)
   (MemReadInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
	    ,Div#(busWidth,8,busWidthBytes)
	    ,Add#(beatShift, a__, 8)
	    ,Add#(b__, TLog#(numTags), 6)
	    ,Add#(beatShift, c__, BurstLenSize)
	    );

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = MMU_PIPELINE_DEPTH)
   FIFO#(LRec#(numServers,addrWidth)) clientRequest <- mkSizedFIFO(valueOf(MMU_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth))  serverRequest <- mkFIFO;
   // stage 2: read commands
   BRAM_Configure bramConfig = defaultValue;
   if (mainClockPeriod < 8)
      bramConfig.latency = 2;
   BRAM2Port#(Bit#(TLog#(numTags)), DRec#(numServers,addrWidth)) serverProcessing <- mkBRAM2Server(bramConfig);
   BRAM2Port#(Bit#(TAdd#(TLog#(numTags),TSub#(BurstLenSize,beatShift))), MemData#(busWidth)) clientData <- mkBRAM2Server(bramConfig);
   // stage 3: read data
   FIFO#(MemData#(busWidth)) serverData <- mkFIFO;

   let verbose = False;

   RegFile#(Bit#(TLog#(numTags)),Bit#(BurstLenSize)) clientBurstLen <- mkRegFileFull();
   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);
   Reg#(Bool)                lastReg <- mkReg(False);

   Reg#(Bit#(32))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   TagGen#(numTags) tag_gen <- mkTagGen;

   Reg#(Bit#(BurstLenSize))      compCountReg <- mkReg(0);
   Reg#(Bit#(TLog#(numTags)))    compTagReg <- mkReg(0);
   Reg#(Bit#(TLog#(TMax#(1,numServers)))) compClientReg <- mkReg(0);
   Reg#(Bit#(2))                 compTileReg <- mkReg(0);
   FIFO#(Bit#(TAdd#(1,TLog#(TMax#(1,numServers))))) clientSelect <- mkFIFO;
   FIFO#(Bit#(TLog#(numTags)))   serverTag <- mkFIFO;

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

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

   rule checkMmuResp;
      let request <- toGet(clientRequest).get();
      let physAddr <- mmus[request.req.sglId[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      let burstLenBeats = request.req.burstLen >> beat_shift;
      clientBurstLen.upd(truncate(rename_tag), burstLenBeats);

      serverRequest.enq(RRec{req:request.req, pa:physAddr, client:request.client, rename_tag:extend(rename_tag)});
      if (verbose) $display("mkMemReadInternal::checkMmuResp: client=%d, tag=%d rename_tag=%d burstLen=%d", request.client, request.req.tag, rename_tag, burstLenBeats);
      if (verbose) $display("mkMemReadInternal::mmuResp %d %d", request.client, cycle_cnt-last_mmuResp);
      last_mmuResp <= cycle_cnt;
   endrule

   rule read_data;
      let response <- toGet(serverData).get();
      let drq <- serverProcessing.portA.response.get;
      let tag = drq.req_tag;
      let burstLen = clientBurstLen.sub(truncate(response.tag));
      let first   = firstReg;
      let last    = response.last;
      if (first) begin
	 last = drq.last;
	 dynamicAssert(last == (burstLen==1), "Last incorrect");
      end
      if (last && burstLen != 1)
	 $display("rename_tag=%d tag=%d burstLen=%d last=%d", response.tag, tag, burstLen, last);
      Bit#(TLog#(numTags)) tt = truncate(response.tag);
      clientData.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, datain:MemData{data: response.data, tag: tag, last: last},
					       address:{tt,truncate(burstLen)}});
      if (last) begin
	 tag_gen.returnTag(truncate(response.tag));
      end
      last_readData <= cycle_cnt;
      if (verbose) $display("mkMemReadInternal::read_data cyclediff %d", cycle_cnt-last_readData);
      clientBurstLen.upd(truncate(response.tag), burstLen-1);
      firstReg <= last;
      lastReg  <= burstLen-1 == 1;
   endrule

   rule tag_completed;
      let tag <- tag_gen.complete;
      serverProcessing.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
      serverTag.enq(tag);
      if(verbose) $display("mkMemReadInternal::complete_burst0 %h", tag);
   endrule

   rule complete_burst1a if (compCountReg==0);
      let drq <- serverProcessing.portB.response.get;
      let req_burstLen = drq.req_burstLen;
      let client = drq.client;
      let cnt = req_burstLen >> beat_shift;
      let tag <- toGet(serverTag).get;
      if(killv[drq.req_tag[5:4]] == False) begin
	 clientSelect.enq(extend(client));
	 clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      compTagReg <= tag;
      compClientReg <= client;
      compTileReg <= drq.req_tag[5:4];
      if(verbose) $display("mkMemReadInternal::complete_burst1a %h", client);
   endrule

   rule burst_remainder if (compCountReg > 0);
      let cnt = compCountReg;
      let tag = compTagReg;
      let client = compClientReg;
      if(killv[compTileReg] == False) begin
	 clientSelect.enq(extend(client));
	 clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      if(verbose) $display("mkMemReadInternal::complete_burst1b count %h", compCountReg);
   endrule

   Vector#(numServers, MemReadServer#(busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface MemReadServer;
		  interface Put readReq;
		     method Action put(MemRequest req);
			last_loadClient <= cycle_cnt;
			let mmusel = req.sglId[31:16];
      			if (verbose) $display("mkMemReadInternal::loadClient server %d mmusel %d burstLen %d tag %d cycle %d",
			   i, mmusel, req.burstLen >> beat_shift, req.tag, cycle_cnt-last_loadClient);
			if (mmusel >= fromInteger(valueOf(numMMUs)))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorMMUOutOfRange_r, pref: req.sglId });
   			else if (sglid_outofrange(req.sglId))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorSGLIdOutOfRange_r, pref: req.sglId });
   			else if (stopv[req.tag[5:4]] == False) begin
   			   clientRequest.enq(LRec{req:req, client:fromInteger(i)});
   			   mmus[mmusel].request.put(AddrTransRequest{id:truncate(req.sglId),off:req.offset});
   			end
		     endmethod
		  endinterface
		  interface Get readData;
		     method ActionValue#(MemData#(busWidth)) get if (clientSelect.first == fromInteger(i));
			clientSelect.deq;
			let data <- clientData.portB.response.get;
			if (verbose) $display("mkMemReadInternal::comp server %d data %x cycle %d", i, data.data, cycle_cnt-last_comp);
			last_comp <= cycle_cnt;
			return data;
		     endmethod
		  endinterface
	       endinterface);

   interface servers = sv;
   interface PhysMemReadClient client;
      interface Get readReq;
	 method ActionValue#(PhysMemRequest#(addrWidth,dataWidth)) get();
	    let request <- toGet(serverRequest).get;
	    let req = request.req;
	    if (False && request.pa[31:24] != 0)
	       $display("mkMemReadInternal::req_ar: funny physAddr req.sglId=%d req.offset=%h physAddr=%h", req.sglId, req.offset, request.pa);
	    serverProcessing.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(request.rename_tag),
						   datain:DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:request.client, rename_tag:request.rename_tag, last:(req.burstLen == fromInteger(valueOf(busWidthBytes)))}});
	    //$display("mkMemReadInternal::readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", request.client,request.rename_tag,request.pa, req.burstLen, beat_shift, req.burstLen == beat_shift);
	    if (verbose) $display("mkMemReadInternal::read_client.readReq %d", cycle_cnt-last_readReq);
	    last_readReq <= cycle_cnt;
	    return PhysMemRequest{addr:request.pa, burstLen:req.burstLen, tag:request.rename_tag
`ifdef BYTE_ENABLES
				  , firstbe: request.req.firstbe, lastbe: request.req.lastbe
`endif
	       };
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(MemData#(busWidth) response);
	    serverData.enq(response);
	    serverProcessing.portA.request.put(BRAMRequest{write:False, address:truncate(response.tag), datain: ?, responseOnWrite: ?});
	    beatCount <= beatCount+1;
	 endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
	 let tile = tc.tile;
	 let kv = True;
	 let sv = True;
	 if (tc.state == Running || tc.state == Stopped)
	    kv = False;
	 if (tc.state == Running)
	    sv = False;
	 killv[tile] <= kv;
	 stopv[tile] <= sv;
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:0, y:0, z:0, w:0};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return extend(beatCount);
      endmethod
   endinterface
endmodule

module mkMemWriteInternal#(MemServerIndication ind,
			   Vector#(numMMUs,Server#(AddrTransRequest,Bit#(addrWidth))) mmus)
   (MemWriteInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
	    ,Div#(busWidth,8,busWidthBytes)
	    ,Add#(beatShift, a__, 8)
	    ,Add#(b__, TLog#(numTags), 6)
	    ,Add#(beatShift, c__, BurstLenSize)
	    );

   let verbose = False;

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = MMU_PIPELINE_DEPTH)
   FIFO#(LRec#(numServers,addrWidth)) clientRequest <- mkSizedFIFO(valueOf(MMU_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth))  serverRequest <- mkFIFO;
   // stage 2: write commands
   FIFO#(DRec#(numServers, addrWidth)) serverProcessing <- mkSizedFIFO(valueOf(numTags));
   // stage 3: write data
   BRAM2Port#(Bit#(TLog#(numTags)), RResp#(numServers,addrWidth)) respFifos <- mkBRAM2Server(defaultValue);
   TagGen#(numTags) tag_gen <- mkTagGen;
   FIFO#(RResp#(numServers,addrWidth)) clientResponse <- mkFIFO;

   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);
   Reg#(Bool)               lastReg <- mkReg(False);
   Reg#(Bit#(BeatCountSize)) beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_mmuResp <- mkReg(0);

   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

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

   rule checkMmuResp;
      let request <- toGet(clientRequest).get;
      let req = request.req;
      let client = request.client;
      let physAddr <- mmus[req.sglId[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      serverRequest.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //if (verbose) $display("mkMemWriteInternal::checkMmuResp: client=%d, rename_tag=%d", client,rename_tag);
      if (verbose) $display("mkMemWriteInternal::mmuResp %d %d", client, cycle_cnt-last_mmuResp);
      last_mmuResp <= cycle_cnt;
   endrule

   rule writeDoneComp0;
      let tag <- tag_gen.complete;
      respFifos.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
   endrule

   FIFO#(MemData#(busWidth)) memDataFifo <- mkFIFO();
   Vector#(numServers, FIFO#(MemData#(busWidth))) clientWriteData <- replicateM(mkFIFO);

   if(valueOf(numServers) > 0)
      rule memdata;
	 let drq = serverProcessing.first;
	 let req_tag = drq.req_tag;
	 let req_burstLen = drq.req_burstLen;
	 let rename_tag = drq.rename_tag;
	 let client = drq.client;
	 MemData#(busWidth) tagdata = unpack(0);
	 if (killv[req_tag[5:4]] == False) begin
	    tagdata = clientWriteData[client].first;
	    clientWriteData[client].deq;
	 end
	 let burstLen = burstReg;
	 let first    = firstReg;
	 let last     = lastReg;
	 if (first) begin
	    burstLen = req_burstLen >> beat_shift;
	    last     = serverProcessing.first.last;
	    respFifos.portA.request.put(BRAMRequest{write:True,responseOnWrite:False, address:truncate(rename_tag), datain:RResp{orig_tag:req_tag, client:client}});
	 end
	 burstReg <= burstLen-1;
	 firstReg <= (burstLen-1 == 0);
	 lastReg  <= (burstLen-1 == 1);
	 beatCount <= beatCount+1;
	 if (last)
	    serverProcessing.deq();
	 //$display("mkMemWriteInternal::writeData: client=%d, rename_tag=%d", client, rename_tag);
	 memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: last });
      endrule

   rule fill_clientResponse;
      let rv <- respFifos.portB.response.get;
      clientResponse.enq(rv);
   endrule

   Vector#(numServers, MemWriteServer#(busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface MemWriteServer;
		  interface Put writeReq;
		     method Action put(MemRequest req);
      			if (verbose) $display("mkMemWriteInternal::loadClient %d %d", i, cycle_cnt-last_loadClient);
			last_loadClient <= cycle_cnt;
			let mmusel = req.sglId[31:16];
			if (mmusel >= fromInteger(valueOf(numMMUs)))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorMMUOutOfRange_w, pref: req.sglId });
   			else if (sglid_outofrange(req.sglId))
			   dmaErrorFifo.enq(DmaError { errorType: DmaErrorSGLIdOutOfRange_w, pref: req.sglId });
   			else if (stopv[req.tag[5:4]] == False) begin
   			   clientRequest.enq(LRec{req:req, client:fromInteger(i)});
   			   mmus[mmusel].request.put(AddrTransRequest{id:truncate(req.sglId),off:req.offset});
   			end
		     endmethod
		  endinterface
		  interface Put writeData = toPut(clientWriteData[i]);
		  interface Get writeDone;
		     method ActionValue#(Bit#(MemTagSize)) get if (clientResponse.first.client == fromInteger(i));
			clientResponse.deq;
			return clientResponse.first.orig_tag;
		     endmethod
		  endinterface
	       endinterface);

   interface servers = sv;
   interface PhysMemWriteClient client;
      interface Get writeReq;
	 method ActionValue#(PhysMemRequest#(addrWidth,dataWidth)) get();
	    let request <- toGet(serverRequest).get();
	    let req = request.req;
	    let physAddr = request.pa;
	    let client = request.client;
	    let rename_tag = request.rename_tag;
	    serverProcessing.enq(DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:client, rename_tag:rename_tag, last: (req.burstLen == fromInteger(valueOf(busWidthBytes))) });
	    //$display("mkMemWriteInternal::writeReq: client=%d, rename_tag=%d", client,rename_tag);
	    return PhysMemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)
`ifdef BYTE_ENABLES
				  , firstbe: req.firstbe, lastbe: req.lastbe
`endif
};
	 endmethod
      endinterface
      interface Get writeData = toGet(memDataFifo);
      interface Put writeDone;
	 method Action put(Bit#(MemTagSize) resp);
	    tag_gen.returnTag(truncate(resp));
	    if (verbose) $display("mkMemWriteInternal::writeDone: resp=%d", resp);
	 endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
	 let tile = tc.tile;
	 let kv = True;
	 let sv = True;
	 if (tc.state == Running || tc.state == Stopped)
	    kv = False;
	 if (tc.state == Running)
	    sv = False;
	 killv[tile] <= kv;
	 stopv[tile] <= sv;
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:fromInteger(valueOf(numServers)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return extend(beatCount);
      endmethod
   endinterface
endmodule


fixed off by one error in maybeDecrement

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

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

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

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

import GetPut::*;

interface ConfigCounter#(numeric type count_sz);
   method Action decrement(UInt#(count_sz) x);
   method ActionValue#(Bool) maybeDecrement(UInt#(count_sz) x);
   method Action increment(UInt#(count_sz) x);
   method UInt#(count_sz) read();
   method Bool positive();
endinterface

module mkConfigCounter#(UInt#(count_sz) init_val)(ConfigCounter#(count_sz));
   Wire#(UInt#(count_sz)) inc_wire <- mkDWire(0);
   Wire#(UInt#(count_sz)) dec_wire <- mkDWire(0);
   Reg#(UInt#(count_sz)) cnt <- mkReg(init_val);
   Reg#(Bool) positive_reg <- mkReg(False);
   (* fire_when_enabled *)
   rule react;
      let new_count = cnt;
      if (inc_wire > dec_wire)
	 new_count = cnt + (inc_wire - dec_wire);
      else
	 new_count = cnt - (dec_wire - inc_wire);
      cnt <= new_count;
      positive_reg <= (new_count > 0);
   endrule
   method Action increment(UInt#(count_sz) x);
      inc_wire <= x;
   endmethod
   method Action decrement(UInt#(count_sz) x);
      dec_wire <= x;
   endmethod
   method ActionValue#(Bool) maybeDecrement(UInt#(count_sz) x);
      if (cnt + inc_wire >= x) begin
	 dec_wire <= x;
	 return True;
      end
      else
	 return False;
   endmethod
   method UInt#(count_sz) read = cnt._read;
   method Bool positive = positive_reg._read;
endmodule

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

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

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

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

import GetPut::*;

interface ConfigCounter#(numeric type count_sz);
   method Action decrement(UInt#(count_sz) x);
   method ActionValue#(Bool) maybeDecrement(UInt#(count_sz) x);
   method Action increment(UInt#(count_sz) x);
   method UInt#(count_sz) read();
   method Bool positive();
endinterface

module mkConfigCounter#(UInt#(count_sz) init_val)(ConfigCounter#(count_sz));
   Wire#(UInt#(count_sz)) inc_wire <- mkDWire(0);
   Wire#(UInt#(count_sz)) dec_wire <- mkDWire(0);
   Reg#(UInt#(count_sz)) cnt <- mkReg(init_val);
   Reg#(Bool) positive_reg <- mkReg(False);
   (* fire_when_enabled *)
   rule react;
      let new_count = cnt;
      if (inc_wire > dec_wire)
	 new_count = cnt + (inc_wire - dec_wire);
      else
	 new_count = cnt - (dec_wire - inc_wire);
      cnt <= new_count;
      positive_reg <= (new_count > 0);
   endrule
   method Action increment(UInt#(count_sz) x);
      inc_wire <= x;
   endmethod
   method Action decrement(UInt#(count_sz) x);
      dec_wire <= x;
   endmethod
   method ActionValue#(Bool) maybeDecrement(UInt#(count_sz) x);
      if (cnt + inc_wire > x) begin
	 dec_wire <= x;
	 return True;
      end
      else
	 return False;
   endmethod
   method UInt#(count_sz) read = cnt._read;
   method Bool positive = positive_reg._read;
endmodule