added missing methods

added missing methods

/*
   ../scripts/importbvi.py
   -o
   AxiDmaBvi.bsv
   -P
   AxiDmaBvi
   -I
   AxiDmaBvi
   -f
   m_axi_s2mm
   -f
   s_axis_s2mm
   -f
   mm2s
   -f
   s2mm
   -f
   m_axi_mm2s
   -f
   m_axis_mm2s
   ../../out/vc709/axi_dma_0/axi_dma_0_stub.v
*/

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;
import ConnectalConfig::*;
import AxiBits::*;
import AxiStream::*;

(* always_ready, always_enabled *)
interface AxidmabviAxiDma;
    method Bit#(32)     tstvec();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviM_axi_mm2s;
    method Bit#(32)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(8)     arlen();
    method Bit#(3)     arprot();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Action      rdata(Bit#(DataBusWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxidmabviM_axi_s2mm;
    method Bit#(32)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(8)     awlen();
    method Bit#(3)     awprot();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Bit#(DataBusWidth)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(DataBusWidth,8))     wstrb();
    method Bit#(1)     wvalid();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviM_axi_sg;
    method Bit#(32)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(8)     arlen();
    method Bit#(3)     arprot();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(32)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(8)     awlen();
    method Bit#(3)     awprot();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(DataBusWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(DataBusWidth)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(DataBusWidth,8))     wstrb();
    method Bit#(1)     wvalid();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviMm2s;
    method Bit#(1)     cntrl_reset_out_n();
    method Bit#(1)     introut();
    method Bit#(1)     prmry_reset_out_n();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviS2mm;
    method Bit#(1)     introut();
    method Bit#(1)     prmry_reset_out_n();
    method Bit#(1)     sts_reset_out_n();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviS_axi_lite;
    method Action      araddr(Bit#(10) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(10) v);
    method Bit#(1)     awready();
    method Action      awvalid(Bit#(1) v);
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(32)     rdata();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(32) v);
    method Bit#(1)     wready();
    method Action      wvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiDmaBvi;
    interface AxidmabviAxiDma     axi_dma;
    interface AxidmabviM_axi_mm2s     m_axi_mm2s;
    interface AxidmabviM_axi_s2mm     m_axi_s2mm;
    interface AxidmabviM_axi_sg     m_axi_sg;
    interface AxiStreamMaster#(32)     m_axis_mm2s;
    interface AxiStreamMaster#(32)     m_axis_mm2s_cntrl;
    interface AxidmabviMm2s     mm2s;
    interface AxidmabviS2mm     s2mm;
    interface Axi4SlaveLiteBits#(10,32) s_axi_lite;
    interface AxiStreamSlave#(32)     s_axis_s2mm_sts;
    interface AxiStreamSlave#(32)     s_axis_s2mm;
endinterface
import "BVI" axi_dma_0 =
module mkAxiDmaBvi#(Clock m_axi_mm2s_aclk, Clock m_axi_s2mm_aclk, Clock m_axi_sg_aclk, Clock s_axi_lite_aclk, Reset axi_reset)(AxiDmaBvi);
    default_clock clk();
    default_reset rst();
    input_clock (m_axi_mm2s_aclk) = m_axi_mm2s_aclk;
    input_clock (m_axi_s2mm_aclk) = m_axi_s2mm_aclk;
    input_clock (m_axi_sg_aclk) = m_axi_sg_aclk;
   input_clock (s_axi_lite_aclk) = s_axi_lite_aclk;
   input_reset (axi_resetn) = axi_reset;
    interface AxidmabviAxiDma     axi_dma;
        method axi_dma_tstvec tstvec();
    endinterface
    interface AxidmabviM_axi_mm2s     m_axi_mm2s;
        method m_axi_mm2s_araddr araddr();
        method m_axi_mm2s_arburst arburst();
        method m_axi_mm2s_arcache arcache();
        method m_axi_mm2s_arlen arlen();
        method m_axi_mm2s_arprot arprot();
        method arready(m_axi_mm2s_arready) enable((*inhigh*) EN_m_axi_mm2s_arready);
        method m_axi_mm2s_arsize arsize();
        method m_axi_mm2s_arvalid arvalid();
        method rdata(m_axi_mm2s_rdata) enable((*inhigh*) EN_m_axi_mm2s_rdata);
        method rlast(m_axi_mm2s_rlast) enable((*inhigh*) EN_m_axi_mm2s_rlast);
        method m_axi_mm2s_rready rready();
        method rresp(m_axi_mm2s_rresp) enable((*inhigh*) EN_m_axi_mm2s_rresp);
        method rvalid(m_axi_mm2s_rvalid) enable((*inhigh*) EN_m_axi_mm2s_rvalid);
    endinterface
    interface AxidmabviM_axi_s2mm     m_axi_s2mm;
        method m_axi_s2mm_awaddr awaddr();
        method m_axi_s2mm_awburst awburst();
        method m_axi_s2mm_awcache awcache();
        method m_axi_s2mm_awlen awlen();
        method m_axi_s2mm_awprot awprot();
        method awready(m_axi_s2mm_awready) enable((*inhigh*) EN_m_axi_s2mm_awready);
        method m_axi_s2mm_awsize awsize();
        method m_axi_s2mm_awvalid awvalid();
        method m_axi_s2mm_bready bready();
        method bresp(m_axi_s2mm_bresp) enable((*inhigh*) EN_m_axi_s2mm_bresp);
        method bvalid(m_axi_s2mm_bvalid) enable((*inhigh*) EN_m_axi_s2mm_bvalid);
        method m_axi_s2mm_wdata wdata();
        method m_axi_s2mm_wlast wlast();
        method wready(m_axi_s2mm_wready) enable((*inhigh*) EN_m_axi_s2mm_wready);
        method m_axi_s2mm_wstrb wstrb();
        method m_axi_s2mm_wvalid wvalid();
    endinterface
    interface AxidmabviM_axi_sg     m_axi_sg;
        method m_axi_sg_araddr araddr();
        method m_axi_sg_arburst arburst();
        method m_axi_sg_arcache arcache();
        method m_axi_sg_arlen arlen();
        method m_axi_sg_arprot arprot();
        method arready(m_axi_sg_arready) enable((*inhigh*) EN_m_axi_sg_arready);
        method m_axi_sg_arsize arsize();
        method m_axi_sg_arvalid arvalid();
        method m_axi_sg_awaddr awaddr();
        method m_axi_sg_awburst awburst();
        method m_axi_sg_awcache awcache();
        method m_axi_sg_awlen awlen();
        method m_axi_sg_awprot awprot();
        method awready(m_axi_sg_awready) enable((*inhigh*) EN_m_axi_sg_awready);
        method m_axi_sg_awsize awsize();
        method m_axi_sg_awvalid awvalid();
        method m_axi_sg_bready bready();
        method bresp(m_axi_sg_bresp) enable((*inhigh*) EN_m_axi_sg_bresp);
        method bvalid(m_axi_sg_bvalid) enable((*inhigh*) EN_m_axi_sg_bvalid);
        method rdata(m_axi_sg_rdata) enable((*inhigh*) EN_m_axi_sg_rdata);
        method rlast(m_axi_sg_rlast) enable((*inhigh*) EN_m_axi_sg_rlast);
        method m_axi_sg_rready rready();
        method rresp(m_axi_sg_rresp) enable((*inhigh*) EN_m_axi_sg_rresp);
        method rvalid(m_axi_sg_rvalid) enable((*inhigh*) EN_m_axi_sg_rvalid);
        method m_axi_sg_wdata wdata();
        method m_axi_sg_wlast wlast();
        method wready(m_axi_sg_wready) enable((*inhigh*) EN_m_axi_sg_wready);
        method m_axi_sg_wstrb wstrb();
        method m_axi_sg_wvalid wvalid();
    endinterface
    interface AxiStreamMaster     m_axis_mm2s_cntrl;
        method m_axis_mm2s_cntrl_tdata tdata();
        method m_axis_mm2s_cntrl_tkeep tkeep();
        method m_axis_mm2s_cntrl_tlast tlast();
        method tready(m_axis_mm2s_cntrl_tready) enable((*inhigh*) EN_m_axis_mm2s_cntrl_tready);
        method m_axis_mm2s_cntrl_tvalid tvalid();
   endinterface
    interface AxiStreamMaster     m_axis_mm2s;
        method m_axis_mm2s_tdata tdata();
        method m_axis_mm2s_tkeep tkeep();
        method m_axis_mm2s_tlast tlast();
        method tready(m_axis_mm2s_tready) enable((*inhigh*) EN_m_axis_mm2s_tready);
        method m_axis_mm2s_tvalid tvalid();
    endinterface
    interface AxidmabviMm2s     mm2s;
        method mm2s_cntrl_reset_out_n cntrl_reset_out_n();
        method mm2s_introut introut();
        method mm2s_prmry_reset_out_n prmry_reset_out_n();
    endinterface
    interface AxidmabviS2mm     s2mm;
        method s2mm_introut introut();
        method s2mm_prmry_reset_out_n prmry_reset_out_n();
        method s2mm_sts_reset_out_n sts_reset_out_n();
    endinterface
    interface Axi4SlaveLiteBits s_axi_lite;
        method araddr(s_axi_lite_araddr) enable((*inhigh*) EN_s_axi_lite_araddr);
        method s_axi_lite_arready arready();
        method arvalid(s_axi_lite_arvalid) enable((*inhigh*) EN_s_axi_lite_arvalid);
        method awaddr(s_axi_lite_awaddr) enable((*inhigh*) EN_s_axi_lite_awaddr);
        method s_axi_lite_awready awready();
        method awvalid(s_axi_lite_awvalid) enable((*inhigh*) EN_s_axi_lite_awvalid);
        method bready(s_axi_lite_bready) enable((*inhigh*) EN_s_axi_lite_bready);
        method s_axi_lite_bresp bresp();
        method s_axi_lite_bvalid bvalid();
        method s_axi_lite_rdata rdata();
        method rready(s_axi_lite_rready) enable((*inhigh*) EN_s_axi_lite_rready);
        method s_axi_lite_rresp rresp();
        method s_axi_lite_rvalid rvalid();
        method wdata(s_axi_lite_wdata) enable((*inhigh*) EN_s_axi_lite_wdata);
        method s_axi_lite_wready wready();
        method wvalid(s_axi_lite_wvalid) enable((*inhigh*) EN_s_axi_lite_wvalid);
    endinterface
    interface AxiStreamSlave     s_axis_s2mm_sts;
        method tdata(s_axis_s2mm_sts_tdata) enable((*inhigh*) EN_s_axis_s2mm_sts_tdata);
        method tkeep(s_axis_s2mm_sts_tkeep) enable((*inhigh*) EN_s_axis_s2mm_sts_tkeep);
        method tlast(s_axis_s2mm_sts_tlast) enable((*inhigh*) EN_s_axis_s2mm_sts_tlast);
        method s_axis_s2mm_sts_tready tready();
        method tvalid(s_axis_s2mm_sts_tvalid) enable((*inhigh*) EN_s_axis_s2mm_sts_tvalid);
    endinterface
    interface AxiStreamSlave     s_axis_s2mm;
        method tdata(s_axis_s2mm_tdata) enable((*inhigh*) EN_s_axis_s2mm_tdata);
        method tkeep(s_axis_s2mm_tkeep) enable((*inhigh*) EN_s_axis_s2mm_tkeep);
        method tlast(s_axis_s2mm_tlast) enable((*inhigh*) EN_s_axis_s2mm_tlast);
        method s_axis_s2mm_tready tready();
        method tvalid(s_axis_s2mm_tvalid) enable((*inhigh*) EN_s_axis_s2mm_tvalid);
    endinterface
    schedule (axi_dma.tstvec, m_axi_mm2s.araddr, m_axi_mm2s.arburst, m_axi_mm2s.arcache, m_axi_mm2s.arlen, m_axi_mm2s.arprot, m_axi_mm2s.arready, m_axi_mm2s.arsize, m_axi_mm2s.arvalid, m_axi_mm2s.rdata, m_axi_mm2s.rlast, m_axi_mm2s.rready, m_axi_mm2s.rresp, m_axi_mm2s.rvalid, m_axi_s2mm.awaddr, m_axi_s2mm.awburst, m_axi_s2mm.awcache, m_axi_s2mm.awlen, m_axi_s2mm.awprot, m_axi_s2mm.awready, m_axi_s2mm.awsize, m_axi_s2mm.awvalid, m_axi_s2mm.bready, m_axi_s2mm.bresp, m_axi_s2mm.bvalid, m_axi_s2mm.wdata, m_axi_s2mm.wlast, m_axi_s2mm.wready, m_axi_s2mm.wstrb, m_axi_s2mm.wvalid, m_axi_sg.araddr, m_axi_sg.arburst, m_axi_sg.arcache, m_axi_sg.arlen, m_axi_sg.arprot, m_axi_sg.arready, m_axi_sg.arsize, m_axi_sg.arvalid, m_axi_sg.awaddr, m_axi_sg.awburst, m_axi_sg.awcache, m_axi_sg.awlen, m_axi_sg.awprot, m_axi_sg.awready, m_axi_sg.awsize, m_axi_sg.awvalid, m_axi_sg.bready, m_axi_sg.bresp, m_axi_sg.bvalid, m_axi_sg.rdata, m_axi_sg.rlast, m_axi_sg.rready, m_axi_sg.rresp, m_axi_sg.rvalid, m_axi_sg.wdata, m_axi_sg.wlast, m_axi_sg.wready, m_axi_sg.wstrb, m_axi_sg.wvalid, m_axis_mm2s_cntrl.tdata, m_axis_mm2s_cntrl.tkeep, m_axis_mm2s_cntrl.tlast, m_axis_mm2s_cntrl.tready, m_axis_mm2s_cntrl.tvalid, m_axis_mm2s.tdata, m_axis_mm2s.tkeep, m_axis_mm2s.tlast, m_axis_mm2s.tready, m_axis_mm2s.tvalid, mm2s.cntrl_reset_out_n, mm2s.introut, mm2s.prmry_reset_out_n, s2mm.introut, s2mm.prmry_reset_out_n, s2mm.sts_reset_out_n, s_axi_lite.araddr, s_axi_lite.arready, s_axi_lite.arvalid, s_axi_lite.awaddr, s_axi_lite.awready, s_axi_lite.awvalid, s_axi_lite.bready, s_axi_lite.bresp, s_axi_lite.bvalid, s_axi_lite.rdata, s_axi_lite.rready, s_axi_lite.rresp, s_axi_lite.rvalid, s_axi_lite.wdata, s_axi_lite.wready, s_axi_lite.wvalid, s_axis_s2mm_sts.tdata, s_axis_s2mm_sts.tkeep, s_axis_s2mm_sts.tlast, s_axis_s2mm_sts.tready, s_axis_s2mm_sts.tvalid, s_axis_s2mm.tdata, s_axis_s2mm.tkeep, s_axis_s2mm.tlast, s_axis_s2mm.tready, s_axis_s2mm.tvalid) CF (axi_dma.tstvec, m_axi_mm2s.araddr, m_axi_mm2s.arburst, m_axi_mm2s.arcache, m_axi_mm2s.arlen, m_axi_mm2s.arprot, m_axi_mm2s.arready, m_axi_mm2s.arsize, m_axi_mm2s.arvalid, m_axi_mm2s.rdata, m_axi_mm2s.rlast, m_axi_mm2s.rready, m_axi_mm2s.rresp, m_axi_mm2s.rvalid, m_axi_s2mm.awaddr, m_axi_s2mm.awburst, m_axi_s2mm.awcache, m_axi_s2mm.awlen, m_axi_s2mm.awprot, m_axi_s2mm.awready, m_axi_s2mm.awsize, m_axi_s2mm.awvalid, m_axi_s2mm.bready, m_axi_s2mm.bresp, m_axi_s2mm.bvalid, m_axi_s2mm.wdata, m_axi_s2mm.wlast, m_axi_s2mm.wready, m_axi_s2mm.wstrb, m_axi_s2mm.wvalid, m_axi_sg.araddr, m_axi_sg.arburst, m_axi_sg.arcache, m_axi_sg.arlen, m_axi_sg.arprot, m_axi_sg.arready, m_axi_sg.arsize, m_axi_sg.arvalid, m_axi_sg.awaddr, m_axi_sg.awburst, m_axi_sg.awcache, m_axi_sg.awlen, m_axi_sg.awprot, m_axi_sg.awready, m_axi_sg.awsize, m_axi_sg.awvalid, m_axi_sg.bready, m_axi_sg.bresp, m_axi_sg.bvalid, m_axi_sg.rdata, m_axi_sg.rlast, m_axi_sg.rready, m_axi_sg.rresp, m_axi_sg.rvalid, m_axi_sg.wdata, m_axi_sg.wlast, m_axi_sg.wready, m_axi_sg.wstrb, m_axi_sg.wvalid, m_axis_mm2s_cntrl.tdata, m_axis_mm2s_cntrl.tkeep, m_axis_mm2s_cntrl.tlast, m_axis_mm2s_cntrl.tready, m_axis_mm2s_cntrl.tvalid, m_axis_mm2s.tdata, m_axis_mm2s.tkeep, m_axis_mm2s.tlast, m_axis_mm2s.tready, m_axis_mm2s.tvalid, mm2s.cntrl_reset_out_n, mm2s.introut, mm2s.prmry_reset_out_n, s2mm.introut, s2mm.prmry_reset_out_n, s2mm.sts_reset_out_n, s_axi_lite.araddr, s_axi_lite.arready, s_axi_lite.arvalid, s_axi_lite.awaddr, s_axi_lite.awready, s_axi_lite.awvalid, s_axi_lite.bready, s_axi_lite.bresp, s_axi_lite.bvalid, s_axi_lite.rdata, s_axi_lite.rready, s_axi_lite.rresp, s_axi_lite.rvalid, s_axi_lite.wdata, s_axi_lite.wready, s_axi_lite.wvalid, s_axis_s2mm_sts.tdata, s_axis_s2mm_sts.tkeep, s_axis_s2mm_sts.tlast, s_axis_s2mm_sts.tready, s_axis_s2mm_sts.tvalid, s_axis_s2mm.tdata, s_axis_s2mm.tkeep, s_axis_s2mm.tlast, s_axis_s2mm.tready, s_axis_s2mm.tvalid);
endmodule

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AxidmabviM_axi_mm2s);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AxidmabviM_axi_mm2s m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
      method araddr = m.araddr;
	   method arburst = m.arburst;
	   method arcache = m.arcache;
	   method Bit#(1) aresetn(); return 1; endmethod
	   method Bit#(tagWidth)     arid(); return 0; endmethod
	   method arlen = m.arlen;
	   method arlock = 0;
	   method arprot = m.arprot;
	   method arqos = 0;
	   method arready = m.arready;
	   method arsize = m.arsize;
	   method arvalid = m.arvalid;
	   method Bit#(32)     awaddr(); return 0; endmethod
	   method Bit#(2)     awburst(); return 0; endmethod
	   method Bit#(4)     awcache(); return 0; endmethod
	   method Bit#(tagWidth)     awid(); return 0; endmethod
	   method Bit#(8)     awlen(); return 0; endmethod
	   method Bit#(2)     awlock(); return 0; endmethod
	   method Bit#(3)     awprot(); return 0; endmethod
	   method Bit#(4)     awqos(); return 0; endmethod
	   method Action      awready(Bit#(1) v); endmethod
	   method Bit#(3)     awsize(); return 0; endmethod
	   method Bit#(1)     awvalid(); return 0; endmethod
	   method Action      bid(Bit#(tagWidth) v); endmethod
	   method Bit#(1)     bready(); return 0; endmethod
	   method Action      bresp(Bit#(2) v); endmethod
	   method Action      bvalid(Bit#(1) v); endmethod
	   method rdata = m.rdata;
	   method Action      rid(Bit#(tagWidth) v); endmethod
	   method rlast = m.rlast;
	   method rready = m.rready;
	   method rresp = m.rresp;
	   method rvalid = m.rvalid;
	   method Bit#(DataBusWidth)     wdata(); return 0; endmethod
	   method Bit#(tagWidth)     wid(); return 0; endmethod
	   method Bit#(1)     wlast(); return 0; endmethod
	   method Action      wready(Bit#(1) v); endmethod
	   method Bit#(TDiv#(DataBusWidth,8))     wstrb(); return 0; endmethod
	   method Bit#(1)     wvalid(); return 0; endmethod
	 interface extra = ?;
	 endinterface);
   endfunction
endinstance

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AxidmabviM_axi_s2mm);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AxidmabviM_axi_s2mm m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
    method Bit#(32)     araddr(); return 0; endmethod
    method Bit#(2)     arburst(); return 0; endmethod
    method Bit#(4)     arcache(); return 0; endmethod
    method Bit#(8)     arlen(); return 0; endmethod
      method Bit#(2)     arlock(); return 0; endmethod
    method Bit#(3)     arprot(); return 0; endmethod
      method Bit#(4)     arqos(); return 0; endmethod
    method Action      arready(Bit#(1) v); endmethod
    method Bit#(3)     arsize(); return 0; endmethod
    method Bit#(1)     arvalid(); return 0; endmethod
      method awaddr = m.awaddr;
      method awburst = m.awburst;
      method awcache = m.awcache;
      method Bit#(tagWidth)     awid(); return 0; endmethod
      method awlen = m.awlen;
      method awlock = 0;
      method awprot = m.awprot;
      method awqos = 0;
      method awready = m.awready;
      method awsize = m.awsize;
      method awvalid = m.awvalid;
      method Action      bid(Bit#(tagWidth) v); endmethod
      method bready = m.bready;
      method bresp = m.bresp;
      method bvalid = m.bvalid;
    method Action      rdata(Bit#(dataWidth) v); endmethod
    method Action      rlast(Bit#(1) v); endmethod
    method Action      rid(Bit#(tagWidth) tag); endmethod
    method Bit#(1)     rready(); return 0; endmethod
    method Action      rresp(Bit#(2) v); endmethod
    method Action      rvalid(Bit#(1) v); endmethod
      method wdata = m.wdata;
      method Bit#(tagWidth)     wid(); return 0; endmethod
      method wlast = m.wlast;
      method wready = m.wready;
      method wstrb = m.wstrb;
      method wvalid = m.wvalid;
      interface extra = ?;
      endinterface);
endfunction
endinstance

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AxidmabviM_axi_sg);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AxidmabviM_axi_sg m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
    method araddr = m.araddr;
      method arburst = m.arburst;
      method arcache = m.arcache;
      method Bit#(1) aresetn(); return 0; endmethod
      method Bit#(tagWidth)     arid(); return 0; endmethod
      method arlen = m.arlen;
      method arlock = 0;
      method arprot = m.arprot;
      method arqos = 0;
      method arready = m.arready;
      method arsize = m.arsize;
      method arvalid = m.arvalid;
      method awaddr = m.awaddr;
      method awburst = m.awburst;
      method awcache = m.awcache;
      method Bit#(tagWidth)     awid(); return 0; endmethod
      method awlen = m.awlen;
      method awlock = 0;
      method awprot = m.awprot;
      method awqos = 0;
      method awready = m.awready;
      method awsize = m.awsize;
      method awvalid = m.awvalid;
      method Action      bid(Bit#(tagWidth) v); endmethod
      method bready = m.bready;
      method bresp = m.bresp;
      method bvalid = m.bvalid;
      method rdata = m.rdata;
      method Action      rid(Bit#(tagWidth) v); endmethod
      method rlast = m.rlast;
      method rready = m.rready;
      method rresp = m.rresp;
      method rvalid = m.rvalid;
      method wdata = m.wdata;
      method Bit#(tagWidth)     wid(); return 0; endmethod
      method wlast = m.wlast;
      method wready = m.wready;
      method wstrb = m.wstrb;
      method wvalid = m.wvalid;
      interface extra = ?;
      endinterface);
endfunction
endinstance

/*
   ../scripts/importbvi.py
   -o
   AxiDmaBvi.bsv
   -P
   AxiDmaBvi
   -I
   AxiDmaBvi
   -f
   m_axi_s2mm
   -f
   s_axis_s2mm
   -f
   mm2s
   -f
   s2mm
   -f
   m_axi_mm2s
   -f
   m_axis_mm2s
   ../../out/vc709/axi_dma_0/axi_dma_0_stub.v
*/

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;
import ConnectalConfig::*;
import AxiBits::*;
import AxiStream::*;

(* always_ready, always_enabled *)
interface AxidmabviAxiDma;
    method Bit#(32)     tstvec();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviM_axi_mm2s;
    method Bit#(32)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(8)     arlen();
    method Bit#(3)     arprot();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Action      rdata(Bit#(DataBusWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxidmabviM_axi_s2mm;
    method Bit#(32)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(8)     awlen();
    method Bit#(3)     awprot();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Bit#(DataBusWidth)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(DataBusWidth,8))     wstrb();
    method Bit#(1)     wvalid();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviM_axi_sg;
    method Bit#(32)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(8)     arlen();
    method Bit#(3)     arprot();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(32)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(8)     awlen();
    method Bit#(3)     awprot();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(DataBusWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(DataBusWidth)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(DataBusWidth,8))     wstrb();
    method Bit#(1)     wvalid();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviMm2s;
    method Bit#(1)     cntrl_reset_out_n();
    method Bit#(1)     introut();
    method Bit#(1)     prmry_reset_out_n();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviS2mm;
    method Bit#(1)     introut();
    method Bit#(1)     prmry_reset_out_n();
    method Bit#(1)     sts_reset_out_n();
endinterface
(* always_ready, always_enabled *)
interface AxidmabviS_axi_lite;
    method Action      araddr(Bit#(10) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(10) v);
    method Bit#(1)     awready();
    method Action      awvalid(Bit#(1) v);
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(32)     rdata();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(32) v);
    method Bit#(1)     wready();
    method Action      wvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiDmaBvi;
    interface AxidmabviAxiDma     axi_dma;
    interface AxidmabviM_axi_mm2s     m_axi_mm2s;
    interface AxidmabviM_axi_s2mm     m_axi_s2mm;
    interface AxidmabviM_axi_sg     m_axi_sg;
    interface AxiStreamMaster#(32)     m_axis_mm2s;
    interface AxiStreamMaster#(32)     m_axis_mm2s_cntrl;
    interface AxidmabviMm2s     mm2s;
    interface AxidmabviS2mm     s2mm;
    interface Axi4SlaveLiteBits#(10,32) s_axi_lite;
    interface AxiStreamSlave#(32)     s_axis_s2mm_sts;
    interface AxiStreamSlave#(32)     s_axis_s2mm;
endinterface
import "BVI" axi_dma_0 =
module mkAxiDmaBvi#(Clock m_axi_mm2s_aclk, Clock m_axi_s2mm_aclk, Clock m_axi_sg_aclk, Clock s_axi_lite_aclk, Reset axi_reset)(AxiDmaBvi);
    default_clock clk();
    default_reset rst();
    input_clock (m_axi_mm2s_aclk) = m_axi_mm2s_aclk;
    input_clock (m_axi_s2mm_aclk) = m_axi_s2mm_aclk;
    input_clock (m_axi_sg_aclk) = m_axi_sg_aclk;
   input_clock (s_axi_lite_aclk) = s_axi_lite_aclk;
   input_reset (axi_resetn) = axi_reset;
    interface AxidmabviAxiDma     axi_dma;
        method axi_dma_tstvec tstvec();
    endinterface
    interface AxidmabviM_axi_mm2s     m_axi_mm2s;
        method m_axi_mm2s_araddr araddr();
        method m_axi_mm2s_arburst arburst();
        method m_axi_mm2s_arcache arcache();
        method m_axi_mm2s_arlen arlen();
        method m_axi_mm2s_arprot arprot();
        method arready(m_axi_mm2s_arready) enable((*inhigh*) EN_m_axi_mm2s_arready);
        method m_axi_mm2s_arsize arsize();
        method m_axi_mm2s_arvalid arvalid();
        method rdata(m_axi_mm2s_rdata) enable((*inhigh*) EN_m_axi_mm2s_rdata);
        method rlast(m_axi_mm2s_rlast) enable((*inhigh*) EN_m_axi_mm2s_rlast);
        method m_axi_mm2s_rready rready();
        method rresp(m_axi_mm2s_rresp) enable((*inhigh*) EN_m_axi_mm2s_rresp);
        method rvalid(m_axi_mm2s_rvalid) enable((*inhigh*) EN_m_axi_mm2s_rvalid);
    endinterface
    interface AxidmabviM_axi_s2mm     m_axi_s2mm;
        method m_axi_s2mm_awaddr awaddr();
        method m_axi_s2mm_awburst awburst();
        method m_axi_s2mm_awcache awcache();
        method m_axi_s2mm_awlen awlen();
        method m_axi_s2mm_awprot awprot();
        method awready(m_axi_s2mm_awready) enable((*inhigh*) EN_m_axi_s2mm_awready);
        method m_axi_s2mm_awsize awsize();
        method m_axi_s2mm_awvalid awvalid();
        method m_axi_s2mm_bready bready();
        method bresp(m_axi_s2mm_bresp) enable((*inhigh*) EN_m_axi_s2mm_bresp);
        method bvalid(m_axi_s2mm_bvalid) enable((*inhigh*) EN_m_axi_s2mm_bvalid);
        method m_axi_s2mm_wdata wdata();
        method m_axi_s2mm_wlast wlast();
        method wready(m_axi_s2mm_wready) enable((*inhigh*) EN_m_axi_s2mm_wready);
        method m_axi_s2mm_wstrb wstrb();
        method m_axi_s2mm_wvalid wvalid();
    endinterface
    interface AxidmabviM_axi_sg     m_axi_sg;
        method m_axi_sg_araddr araddr();
        method m_axi_sg_arburst arburst();
        method m_axi_sg_arcache arcache();
        method m_axi_sg_arlen arlen();
        method m_axi_sg_arprot arprot();
        method arready(m_axi_sg_arready) enable((*inhigh*) EN_m_axi_sg_arready);
        method m_axi_sg_arsize arsize();
        method m_axi_sg_arvalid arvalid();
        method m_axi_sg_awaddr awaddr();
        method m_axi_sg_awburst awburst();
        method m_axi_sg_awcache awcache();
        method m_axi_sg_awlen awlen();
        method m_axi_sg_awprot awprot();
        method awready(m_axi_sg_awready) enable((*inhigh*) EN_m_axi_sg_awready);
        method m_axi_sg_awsize awsize();
        method m_axi_sg_awvalid awvalid();
        method m_axi_sg_bready bready();
        method bresp(m_axi_sg_bresp) enable((*inhigh*) EN_m_axi_sg_bresp);
        method bvalid(m_axi_sg_bvalid) enable((*inhigh*) EN_m_axi_sg_bvalid);
        method rdata(m_axi_sg_rdata) enable((*inhigh*) EN_m_axi_sg_rdata);
        method rlast(m_axi_sg_rlast) enable((*inhigh*) EN_m_axi_sg_rlast);
        method m_axi_sg_rready rready();
        method rresp(m_axi_sg_rresp) enable((*inhigh*) EN_m_axi_sg_rresp);
        method rvalid(m_axi_sg_rvalid) enable((*inhigh*) EN_m_axi_sg_rvalid);
        method m_axi_sg_wdata wdata();
        method m_axi_sg_wlast wlast();
        method wready(m_axi_sg_wready) enable((*inhigh*) EN_m_axi_sg_wready);
        method m_axi_sg_wstrb wstrb();
        method m_axi_sg_wvalid wvalid();
    endinterface
    interface AxiStreamMaster     m_axis_mm2s_cntrl;
        method m_axis_mm2s_cntrl_tdata tdata();
        method m_axis_mm2s_cntrl_tkeep tkeep();
        method m_axis_mm2s_cntrl_tlast tlast();
        method tready(m_axis_mm2s_cntrl_tready) enable((*inhigh*) EN_m_axis_mm2s_cntrl_tready);
        method m_axis_mm2s_cntrl_tvalid tvalid();
   endinterface
    interface AxiStreamMaster     m_axis_mm2s;
        method m_axis_mm2s_tdata tdata();
        method m_axis_mm2s_tkeep tkeep();
        method m_axis_mm2s_tlast tlast();
        method tready(m_axis_mm2s_tready) enable((*inhigh*) EN_m_axis_mm2s_tready);
        method m_axis_mm2s_tvalid tvalid();
    endinterface
    interface AxidmabviMm2s     mm2s;
        method mm2s_cntrl_reset_out_n cntrl_reset_out_n();
        method mm2s_introut introut();
        method mm2s_prmry_reset_out_n prmry_reset_out_n();
    endinterface
    interface AxidmabviS2mm     s2mm;
        method s2mm_introut introut();
        method s2mm_prmry_reset_out_n prmry_reset_out_n();
        method s2mm_sts_reset_out_n sts_reset_out_n();
    endinterface
    interface Axi4SlaveLiteBits s_axi_lite;
        method araddr(s_axi_lite_araddr) enable((*inhigh*) EN_s_axi_lite_araddr);
        method s_axi_lite_arready arready();
        method arvalid(s_axi_lite_arvalid) enable((*inhigh*) EN_s_axi_lite_arvalid);
        method awaddr(s_axi_lite_awaddr) enable((*inhigh*) EN_s_axi_lite_awaddr);
        method s_axi_lite_awready awready();
        method awvalid(s_axi_lite_awvalid) enable((*inhigh*) EN_s_axi_lite_awvalid);
        method bready(s_axi_lite_bready) enable((*inhigh*) EN_s_axi_lite_bready);
        method s_axi_lite_bresp bresp();
        method s_axi_lite_bvalid bvalid();
        method s_axi_lite_rdata rdata();
        method rready(s_axi_lite_rready) enable((*inhigh*) EN_s_axi_lite_rready);
        method s_axi_lite_rresp rresp();
        method s_axi_lite_rvalid rvalid();
        method wdata(s_axi_lite_wdata) enable((*inhigh*) EN_s_axi_lite_wdata);
        method s_axi_lite_wready wready();
        method wvalid(s_axi_lite_wvalid) enable((*inhigh*) EN_s_axi_lite_wvalid);
    endinterface
    interface AxiStreamSlave     s_axis_s2mm_sts;
        method tdata(s_axis_s2mm_sts_tdata) enable((*inhigh*) EN_s_axis_s2mm_sts_tdata);
        method tkeep(s_axis_s2mm_sts_tkeep) enable((*inhigh*) EN_s_axis_s2mm_sts_tkeep);
        method tlast(s_axis_s2mm_sts_tlast) enable((*inhigh*) EN_s_axis_s2mm_sts_tlast);
        method s_axis_s2mm_sts_tready tready();
        method tvalid(s_axis_s2mm_sts_tvalid) enable((*inhigh*) EN_s_axis_s2mm_sts_tvalid);
    endinterface
    interface AxiStreamSlave     s_axis_s2mm;
        method tdata(s_axis_s2mm_tdata) enable((*inhigh*) EN_s_axis_s2mm_tdata);
        method tkeep(s_axis_s2mm_tkeep) enable((*inhigh*) EN_s_axis_s2mm_tkeep);
        method tlast(s_axis_s2mm_tlast) enable((*inhigh*) EN_s_axis_s2mm_tlast);
        method s_axis_s2mm_tready tready();
        method tvalid(s_axis_s2mm_tvalid) enable((*inhigh*) EN_s_axis_s2mm_tvalid);
    endinterface
    schedule (axi_dma.tstvec, m_axi_mm2s.araddr, m_axi_mm2s.arburst, m_axi_mm2s.arcache, m_axi_mm2s.arlen, m_axi_mm2s.arprot, m_axi_mm2s.arready, m_axi_mm2s.arsize, m_axi_mm2s.arvalid, m_axi_mm2s.rdata, m_axi_mm2s.rlast, m_axi_mm2s.rready, m_axi_mm2s.rresp, m_axi_mm2s.rvalid, m_axi_s2mm.awaddr, m_axi_s2mm.awburst, m_axi_s2mm.awcache, m_axi_s2mm.awlen, m_axi_s2mm.awprot, m_axi_s2mm.awready, m_axi_s2mm.awsize, m_axi_s2mm.awvalid, m_axi_s2mm.bready, m_axi_s2mm.bresp, m_axi_s2mm.bvalid, m_axi_s2mm.wdata, m_axi_s2mm.wlast, m_axi_s2mm.wready, m_axi_s2mm.wstrb, m_axi_s2mm.wvalid, m_axi_sg.araddr, m_axi_sg.arburst, m_axi_sg.arcache, m_axi_sg.arlen, m_axi_sg.arprot, m_axi_sg.arready, m_axi_sg.arsize, m_axi_sg.arvalid, m_axi_sg.awaddr, m_axi_sg.awburst, m_axi_sg.awcache, m_axi_sg.awlen, m_axi_sg.awprot, m_axi_sg.awready, m_axi_sg.awsize, m_axi_sg.awvalid, m_axi_sg.bready, m_axi_sg.bresp, m_axi_sg.bvalid, m_axi_sg.rdata, m_axi_sg.rlast, m_axi_sg.rready, m_axi_sg.rresp, m_axi_sg.rvalid, m_axi_sg.wdata, m_axi_sg.wlast, m_axi_sg.wready, m_axi_sg.wstrb, m_axi_sg.wvalid, m_axis_mm2s_cntrl.tdata, m_axis_mm2s_cntrl.tkeep, m_axis_mm2s_cntrl.tlast, m_axis_mm2s_cntrl.tready, m_axis_mm2s_cntrl.tvalid, m_axis_mm2s.tdata, m_axis_mm2s.tkeep, m_axis_mm2s.tlast, m_axis_mm2s.tready, m_axis_mm2s.tvalid, mm2s.cntrl_reset_out_n, mm2s.introut, mm2s.prmry_reset_out_n, s2mm.introut, s2mm.prmry_reset_out_n, s2mm.sts_reset_out_n, s_axi_lite.araddr, s_axi_lite.arready, s_axi_lite.arvalid, s_axi_lite.awaddr, s_axi_lite.awready, s_axi_lite.awvalid, s_axi_lite.bready, s_axi_lite.bresp, s_axi_lite.bvalid, s_axi_lite.rdata, s_axi_lite.rready, s_axi_lite.rresp, s_axi_lite.rvalid, s_axi_lite.wdata, s_axi_lite.wready, s_axi_lite.wvalid, s_axis_s2mm_sts.tdata, s_axis_s2mm_sts.tkeep, s_axis_s2mm_sts.tlast, s_axis_s2mm_sts.tready, s_axis_s2mm_sts.tvalid, s_axis_s2mm.tdata, s_axis_s2mm.tkeep, s_axis_s2mm.tlast, s_axis_s2mm.tready, s_axis_s2mm.tvalid) CF (axi_dma.tstvec, m_axi_mm2s.araddr, m_axi_mm2s.arburst, m_axi_mm2s.arcache, m_axi_mm2s.arlen, m_axi_mm2s.arprot, m_axi_mm2s.arready, m_axi_mm2s.arsize, m_axi_mm2s.arvalid, m_axi_mm2s.rdata, m_axi_mm2s.rlast, m_axi_mm2s.rready, m_axi_mm2s.rresp, m_axi_mm2s.rvalid, m_axi_s2mm.awaddr, m_axi_s2mm.awburst, m_axi_s2mm.awcache, m_axi_s2mm.awlen, m_axi_s2mm.awprot, m_axi_s2mm.awready, m_axi_s2mm.awsize, m_axi_s2mm.awvalid, m_axi_s2mm.bready, m_axi_s2mm.bresp, m_axi_s2mm.bvalid, m_axi_s2mm.wdata, m_axi_s2mm.wlast, m_axi_s2mm.wready, m_axi_s2mm.wstrb, m_axi_s2mm.wvalid, m_axi_sg.araddr, m_axi_sg.arburst, m_axi_sg.arcache, m_axi_sg.arlen, m_axi_sg.arprot, m_axi_sg.arready, m_axi_sg.arsize, m_axi_sg.arvalid, m_axi_sg.awaddr, m_axi_sg.awburst, m_axi_sg.awcache, m_axi_sg.awlen, m_axi_sg.awprot, m_axi_sg.awready, m_axi_sg.awsize, m_axi_sg.awvalid, m_axi_sg.bready, m_axi_sg.bresp, m_axi_sg.bvalid, m_axi_sg.rdata, m_axi_sg.rlast, m_axi_sg.rready, m_axi_sg.rresp, m_axi_sg.rvalid, m_axi_sg.wdata, m_axi_sg.wlast, m_axi_sg.wready, m_axi_sg.wstrb, m_axi_sg.wvalid, m_axis_mm2s_cntrl.tdata, m_axis_mm2s_cntrl.tkeep, m_axis_mm2s_cntrl.tlast, m_axis_mm2s_cntrl.tready, m_axis_mm2s_cntrl.tvalid, m_axis_mm2s.tdata, m_axis_mm2s.tkeep, m_axis_mm2s.tlast, m_axis_mm2s.tready, m_axis_mm2s.tvalid, mm2s.cntrl_reset_out_n, mm2s.introut, mm2s.prmry_reset_out_n, s2mm.introut, s2mm.prmry_reset_out_n, s2mm.sts_reset_out_n, s_axi_lite.araddr, s_axi_lite.arready, s_axi_lite.arvalid, s_axi_lite.awaddr, s_axi_lite.awready, s_axi_lite.awvalid, s_axi_lite.bready, s_axi_lite.bresp, s_axi_lite.bvalid, s_axi_lite.rdata, s_axi_lite.rready, s_axi_lite.rresp, s_axi_lite.rvalid, s_axi_lite.wdata, s_axi_lite.wready, s_axi_lite.wvalid, s_axis_s2mm_sts.tdata, s_axis_s2mm_sts.tkeep, s_axis_s2mm_sts.tlast, s_axis_s2mm_sts.tready, s_axis_s2mm_sts.tvalid, s_axis_s2mm.tdata, s_axis_s2mm.tkeep, s_axis_s2mm.tlast, s_axis_s2mm.tready, s_axis_s2mm.tvalid);
endmodule

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AxidmabviM_axi_mm2s);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AxidmabviM_axi_mm2s m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
      method araddr = m.araddr;
	   method arburst = m.arburst;
	   method arcache = m.arcache;
	   method Bit#(1) aresetn(); return 1; endmethod
	   method Bit#(tagWidth)     arid(); return 0; endmethod
	   method arlen = m.arlen;
	 //method arlock = m.arlock;
	   method arprot = m.arprot;
	 //method arqos = m.arqos;
	   method arready = m.arready;
	   method arsize = m.arsize;
	   method arvalid = m.arvalid;
	   method Bit#(32)     awaddr(); return 0; endmethod
	   method Bit#(2)     awburst(); return 0; endmethod
	   method Bit#(4)     awcache(); return 0; endmethod
	   method Bit#(tagWidth)     awid(); return 0; endmethod
	   method Bit#(8)     awlen(); return 0; endmethod
	   method Bit#(2)     awlock(); return 0; endmethod
	   method Bit#(3)     awprot(); return 0; endmethod
	   method Bit#(4)     awqos(); return 0; endmethod
	   method Action      awready(Bit#(1) v); endmethod
	   method Bit#(3)     awsize(); return 0; endmethod
	   method Bit#(1)     awvalid(); return 0; endmethod
	   method Action      bid(Bit#(tagWidth) v); endmethod
	   method Bit#(1)     bready(); return 0; endmethod
	   method Action      bresp(Bit#(2) v); endmethod
	   method Action      bvalid(Bit#(1) v); endmethod
	   method rdata = m.rdata;
	   method Action      rid(Bit#(tagWidth) v); endmethod
	   method rlast = m.rlast;
	   method rready = m.rready;
	   method rresp = m.rresp;
	   method rvalid = m.rvalid;
	   method Bit#(DataBusWidth)     wdata(); return 0; endmethod
	   method Bit#(tagWidth)     wid(); return 0; endmethod
	   method Bit#(1)     wlast(); return 0; endmethod
	   method Action      wready(Bit#(1) v); endmethod
	   method Bit#(TDiv#(DataBusWidth,8))     wstrb(); return 0; endmethod
	   method Bit#(1)     wvalid(); return 0; endmethod
	 interface extra = ?;
	 endinterface);
   endfunction
endinstance

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AxidmabviM_axi_s2mm);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AxidmabviM_axi_s2mm m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
    method Bit#(32)     araddr(); return 0; endmethod
    method Bit#(2)     arburst(); return 0; endmethod
    method Bit#(4)     arcache(); return 0; endmethod
    method Bit#(8)     arlen(); return 0; endmethod
      method Bit#(2)     arlock(); return 0; endmethod
    method Bit#(3)     arprot(); return 0; endmethod
      method Bit#(4)     arqos(); return 0; endmethod
    method Action      arready(Bit#(1) v); endmethod
    method Bit#(3)     arsize(); return 0; endmethod
    method Bit#(1)     arvalid(); return 0; endmethod
      method awaddr = m.awaddr;
      method awburst = m.awburst;
      method awcache = m.awcache;
      method Bit#(tagWidth)     awid(); return 0; endmethod
      method awlen = m.awlen;
      //method awlock = m.awlock;
      method awprot = m.awprot;
      //method awqos = m.awqos;
      method awready = m.awready;
      method awsize = m.awsize;
      method awvalid = m.awvalid;
      method Action      bid(Bit#(tagWidth) v); endmethod
      method bready = m.bready;
      method bresp = m.bresp;
      method bvalid = m.bvalid;
    method Action      rdata(Bit#(dataWidth) v); endmethod
    method Action      rlast(Bit#(1) v); endmethod
    method Bit#(1)     rready(); return 0; endmethod
    method Action      rresp(Bit#(2) v); endmethod
    method Action      rvalid(Bit#(1) v); endmethod
      method wdata = m.wdata;
      method Bit#(tagWidth)     wid(); return 0; endmethod
      method wlast = m.wlast;
      method wready = m.wready;
      method wstrb = m.wstrb;
      method wvalid = m.wvalid;
      interface extra = ?;
      endinterface);
endfunction
endinstance

instance ToAxi4MasterBits#(Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty), AxidmabviM_axi_sg);
function Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty) toAxi4MasterBits(AxidmabviM_axi_sg m);
   return (interface Axi4MasterBits#(32,DataBusWidth,tagWidth,Empty);
    method araddr = m.araddr;
      method arburst = m.arburst;
      method arcache = m.arcache;
      method Bit#(1) aresetn(); return 0; endmethod
      method Bit#(tagWidth)     arid(); return 0; endmethod
      method arlen = m.arlen;
      //method arlock = m.arlock;
      method arprot = m.arprot;
      //method arqos = m.arqos;
      method arready = m.arready;
      method arsize = m.arsize;
      method arvalid = m.arvalid;
      method awaddr = m.awaddr;
      method awburst = m.awburst;
      method awcache = m.awcache;
      method Bit#(tagWidth)     awid(); return 0; endmethod
      method awlen = m.awlen;
      //method awlock = m.awlock;
      method awprot = m.awprot;
      //method awqos = m.awqos;
      method awready = m.awready;
      method awsize = m.awsize;
      method awvalid = m.awvalid;
      method Action      bid(Bit#(tagWidth) v); endmethod
      method bready = m.bready;
      method bresp = m.bresp;
      method bvalid = m.bvalid;
      method rdata = m.rdata;
      method Action      rid(Bit#(tagWidth) v); endmethod
      method rlast = m.rlast;
      method rready = m.rready;
      method rresp = m.rresp;
      method rvalid = m.rvalid;
      method wdata = m.wdata;
      method Bit#(tagWidth)     wid(); return 0; endmethod
      method wlast = m.wlast;
      method wready = m.wready;
      method wstrb = m.wstrb;
      method wvalid = m.wvalid;
      interface extra = ?;
      endinterface);
endfunction
endinstance


add unspecified fields in BRAMRequest

add unspecified fields in BRAMRequest

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

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

typedef 9 SGL_PIPELINE_DEPTH;

interface TagGen#(numeric type numTags);
   method ActionValue#(Bit#(TLog#(numTags))) getTag;
   method Action returnTag(Bit#(TLog#(numTags)) tag);
   method ActionValue#(Bit#(TLog#(numTags))) complete;
endinterface

module mkTagGen(TagGen#(numTags))
   provisos(Log#(numTags,tsz));

   BRAM_Configure cfg = defaultValue;
   cfg.outFIFODepth = 1;
   BRAM2Port#(Bit#(tsz),Bool) tags <- mkBRAM2Server(cfg);
   Reg#(Bit#(tsz))        head_ptr <- mkReg(0);
   Reg#(Bit#(tsz))        tail_ptr <- mkReg(0);
   Reg#(Bool)               inited <- mkReg(False);
   FIFO#(Bit#(tsz))      comp_fifo <- mkFIFO;
   Reg#(Bit#(numTags))  comp_state <- mkReg(0);

   let retFifo <- mkFIFO;

   rule complete_rule0 (comp_state[0] != 0);
      tags.portB.request.put(BRAMRequest{write:False, address:tail_ptr, responseOnWrite: ?, datain: ?});
   endrule

   rule complete_rule1 (comp_state[0] != 0);
      let rv <- tags.portB.response.get;
      if (!rv) begin
	 tail_ptr <= tail_ptr+1;
	 comp_state <= comp_state >> 1;
	 comp_fifo.enq(tail_ptr);
      end
   endrule

   // this used to be in the body of returnTag, but form some reason bsc does not
   // consider access to portA and portB to be conflict free **sigh**
   rule ret;
      let tag <- toGet(retFifo).get;
      tags.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tag, datain:False, responseOnWrite: ?, datain: ?});
      comp_state <= 1 | (comp_state << 1);
   endrule

   rule init(!inited);
      tags.portA.request.put(BRAMRequest{write:True,address:head_ptr,responseOnWrite:False,datain:False, responseOnWrite: ?, datain: ?});
      head_ptr <= head_ptr+1;
      inited <= head_ptr+1==0;
   endrule

   method ActionValue#(Bit#(tsz)) getTag() if (inited && (head_ptr+1 != tail_ptr));
      tags.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head_ptr, datain:True, responseOnWrite: ?, datain: ?});
      head_ptr <= head_ptr+1;
      return head_ptr;
   endmethod

   method Action returnTag(Bit#(tsz) tag) if (inited);
      retFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(tsz)) complete;
      comp_fifo.deq;
      return comp_fifo.first;
   endmethod

endmodule

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

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

function Bool bad_pointer(ObjectPointer p);
   return ((p[15:0] >>8) > fromInteger(valueOf(MaxNumSGLists)));
endfunction

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

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

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

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

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

typedef 32 NumTags;

module mkMemReadInternal#(Vector#(numClients, ObjectReadClient#(dataWidth)) readClients,
			  DmaDebugIndication dmaIndication,
			  Vector#(numSGLs,Server#(ReqTup,Bit#(addrWidth))) sgls)
   (MemReadInternal#(addrWidth, dataWidth))

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

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: read commands
   BRAM2Port#(Bit#(TLog#(NumTags)), DRec#(numClients,addrWidth)) dreqFifos <- mkBRAM2Server(defaultValue);
   BRAM2Port#(Bit#(TAdd#(TLog#(NumTags),TSub#(8,beatShift))), ObjectData#(dataWidth)) read_buffer <- mkBRAM2Server(defaultValue);
   // stage 3: read data
   FIFO#(MemData#(dataWidth)) readDataPipelineFifo <- mkFIFO;

   let debug = False;

   Reg#(Bit#(8))           burstReg <- mkReg(0);
   Reg#(Bool)              firstReg <- mkReg(True);
   Reg#(Bool)               lastReg <- mkReg(False);
   Reg#(Bit#(64))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   TagGen#(NumTags) tag_gen <- mkTagGen;

   Reg#(Bit#(8))                 compReg0 <- mkReg(0);
   Reg#(Bit#(TLog#(NumTags)))    compReg1 <- mkReg(0);
   Reg#(Bit#(TLog#(numClients))) compReg2 <- mkReg(0);
   FIFO#(Bit#(TLog#(numClients)))compFifo0 <- mkFIFO;
   FIFO#(Bit#(TLog#(NumTags)))   compFifo1 <- mkFIFO;

   // performance analytics
   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_sglResp <- mkReg(0);
   Reg#(Bit#(64)) last_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();
      dmaIndication.error(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

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

   rule complete_burst0;
      let tag <- tag_gen.complete;
      dreqFifos.portB.request.put(BRAMRequest{write:False, address:tag});
      compFifo1.enq(tag);
   endrule

   rule complete_burst1a if (compReg0==0);
      let drq <- dreqFifos.portB.response.get;
      let cnt = drq.req.burstLen >> beat_shift;
      let cli = drq.client;
      let tag <- toGet(compFifo1).get;
      compFifo0.enq(cli);
      read_buffer.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}});
      compReg0 <= cnt-1;
      compReg1 <= tag;
      compReg2 <= cli;
   endrule

   rule complete_burst1b if (compReg0 > 0);
      let cnt = compReg0;
      let tag = compReg1;
      let cli = compReg2;
      compFifo0.enq(cli);
      read_buffer.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}});
      compReg0 <= cnt-1;
   endrule

   rule complete_burst2;
      let client <- toGet(compFifo0).get;
      let data <- read_buffer.portB.response.get;
      readClients[client].readData.put(data);
      if (debug) $display("mkMemReadInternal::comp %d  %x %d", client, data.data, cycle_cnt-last_comp);
      last_comp <= cycle_cnt;
   endrule

   rule checkSglResp;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let physAddr <- sgls[req.pointer[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      if (debug) $display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      if (debug) $display("mkMemReadInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      last_sglResp <= cycle_cnt;
   endrule

   rule read_data;
      let response <- toGet(readDataPipelineFifo).get();
      Bit#(6) response_tag = response.tag;
      let drq <- dreqFifos.portA.response.get;
      let req = drq.req;
      let burstLen = burstReg;
      let first =    firstReg;
      let last  =    lastReg;
      if (first) begin
	 burstLen = drq.req.burstLen >> beat_shift;
	 last = drq.last;
	 dynamicAssert(last == (burstLen==1), "Last incorrect");
	 //$display("burstLen=%d dreqFifo.first.last=%d last=%d\n", burstLen, dreqFifo.first.last, last);
      end
      Bit#(TLog#(NumTags)) tt = truncate(response_tag);
      read_buffer.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, datain:ObjectData{data: response.data, tag: req.tag, last: last}, address:{tt,truncate(burstLen)}});
      if (last) begin
	 tag_gen.returnTag(truncate(response_tag));
      end
      last_readData <= cycle_cnt;
      if (debug) $display("read_data %d", cycle_cnt-last_readData);
      burstReg <= burstLen-1;
      firstReg <= (burstLen-1 == 0);
      lastReg <= (burstLen-1 == 1);
   endrule

   interface MemReadClient read_client;
      interface Get readReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    reqFifo.deq;
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    if (False && physAddr[31:24] != 0)
	       $display("req_ar: funny physAddr req.pointer=%d req.offset=%h physAddr=%h", req.pointer, req.offset, physAddr);
	    dreqFifos.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(rename_tag), datain:DRec{req:req, client:client, rename_tag:rename_tag, last:(req.burstLen == fromInteger(valueOf(dataWidthBytes)))}});
	    //$display("readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", client,rename_tag,physAddr, req.burstLen, beat_shift, req.burstLen == beat_shift);
	    if (debug) $display("read_client.readReq %d", cycle_cnt-last_readReq);
	    last_readReq <= cycle_cnt;
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:rename_tag};
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(MemData#(dataWidth) response);
	    readDataPipelineFifo.enq(response);
	    dreqFifos.portA.request.put(BRAMRequest{write:False, address:truncate(response.tag)});
	    beatCount <= beatCount+1;
	 endmethod
      endinterface
   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 beatCount;
      endmethod
   endinterface
endmodule

typedef 64 NumTagsW;

module mkMemWriteInternal#(Vector#(numClients, ObjectWriteClient#(dataWidth)) writeClients,
			   DmaDebugIndication dmaIndication,
			   Vector#(numSGLs,Server#(ReqTup,Bit#(addrWidth))) sgls)
   (MemWriteInternal#(addrWidth, dataWidth))

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

   let debug = False;

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: write commands
   FIFO#(DRec#(numClients, addrWidth)) dreqFifo <- mkSizedBRAMFIFO(valueOf(NumTagsW));
   // stage 3: write data
   BRAM2Port#(Bit#(TLog#(NumTagsW)), RResp#(numClients,addrWidth)) respFifos <- mkBRAM2Server(defaultValue);
   TagGen#(NumTagsW) tag_gen <- mkTagGen;

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

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

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

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

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

   rule checkSglResp;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let physAddr <- sgls[req.pointer[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //if (debug) $display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      if (debug) $display("mkMemWriteInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      last_sglResp <= cycle_cnt;
   endrule

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

   rule writeDoneComp1;
      let rv <- respFifos.portB.response.get;
      let client = rv.client;
      let orig_tag = rv.orig_tag;
      writeClients[client].writeDone.put(orig_tag);
   endrule

   FIFO#(MemData#(dataWidth)) memDataFifo <- mkFIFO();
   Vector#(numClients, FIFO#(ObjectData#(dataWidth))) clientWriteData <- replicateM(mkFIFO);
   // Pipeline client data:
   // The .get() operation seems to be long latency, so get it into a local FIFO
   for (Integer client = 0; client < valueOf(numClients); client = client + 1)
      rule clientdata;
	 let d <- writeClients[client].writeData.get();
	 clientWriteData[client].enq(d);
      endrule

   rule memdata;
      let client = dreqFifo.first.client;
      let req = dreqFifo.first.req;
      let rename_tag = dreqFifo.first.rename_tag;
      ObjectData#(dataWidth) tagdata <- toGet(clientWriteData[client]).get();
      let burstLen = burstReg;
      let first    = firstReg;
      let last     = lastReg;
      if (first) begin
	 burstLen = req.burstLen >> beat_shift;
	 last     = dreqFifo.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)
	 dreqFifo.deq();
      //$display("writeData: client=%d, rename_tag=%d", client, rename_tag);
      memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: last });
   endrule

   interface MemWriteClient write_client;
      interface Get writeReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    reqFifo.deq;
	    dreqFifo.enq(DRec{req:req, client:client, rename_tag:rename_tag, last: (req.burstLen == fromInteger(valueOf(dataWidthBytes))) });
	    //$display("writeReq: client=%d, rename_tag=%d", client,rename_tag);
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)};
	 endmethod
      endinterface
      interface Get writeData = toGet(memDataFifo);
      interface Put writeDone;
	 method Action put(Bit#(6) resp);
	    tag_gen.returnTag(truncate(resp));
	    if (debug) $display("writeDone: resp=%d", resp);
	 endmethod
      endinterface
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:fromInteger(valueOf(numClients)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return beatCount;
      endmethod
   endinterface
endmodule

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

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

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

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

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

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

typedef 9 SGL_PIPELINE_DEPTH;

interface TagGen#(numeric type numTags);
   method ActionValue#(Bit#(TLog#(numTags))) getTag;
   method Action returnTag(Bit#(TLog#(numTags)) tag);
   method ActionValue#(Bit#(TLog#(numTags))) complete;
endinterface

module mkTagGen(TagGen#(numTags))
   provisos(Log#(numTags,tsz));

   BRAM_Configure cfg = defaultValue;
   cfg.outFIFODepth = 1;
   BRAM2Port#(Bit#(tsz),Bool) tags <- mkBRAM2Server(cfg);
   Reg#(Bit#(tsz))        head_ptr <- mkReg(0);
   Reg#(Bit#(tsz))        tail_ptr <- mkReg(0);
   Reg#(Bool)               inited <- mkReg(False);
   FIFO#(Bit#(tsz))      comp_fifo <- mkFIFO;
   Reg#(Bit#(numTags))  comp_state <- mkReg(0);

   let retFifo <- mkFIFO;

   rule complete_rule0 (comp_state[0] != 0);
      tags.portB.request.put(BRAMRequest{write:False, address:tail_ptr});
   endrule

   rule complete_rule1 (comp_state[0] != 0);
      let rv <- tags.portB.response.get;
      if (!rv) begin
	 tail_ptr <= tail_ptr+1;
	 comp_state <= comp_state >> 1;
	 comp_fifo.enq(tail_ptr);
      end
   endrule

   // this used to be in the body of returnTag, but form some reason bsc does not
   // consider access to portA and portB to be conflict free **sigh**
   rule ret;
      let tag <- toGet(retFifo).get;
      tags.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tag, datain:False});
      comp_state <= 1 | (comp_state << 1);
   endrule

   rule init(!inited);
      tags.portA.request.put(BRAMRequest{write:True,address:head_ptr,responseOnWrite:False,datain:False});
      head_ptr <= head_ptr+1;
      inited <= head_ptr+1==0;
   endrule

   method ActionValue#(Bit#(tsz)) getTag() if (inited && (head_ptr+1 != tail_ptr));
      tags.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head_ptr, datain:True});
      head_ptr <= head_ptr+1;
      return head_ptr;
   endmethod

   method Action returnTag(Bit#(tsz) tag) if (inited);
      retFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(tsz)) complete;
      comp_fifo.deq;
      return comp_fifo.first;
   endmethod

endmodule

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

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

function Bool bad_pointer(ObjectPointer p);
   return ((p[15:0] >>8) > fromInteger(valueOf(MaxNumSGLists)));
endfunction

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

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

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

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

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

typedef 32 NumTags;

module mkMemReadInternal#(Vector#(numClients, ObjectReadClient#(dataWidth)) readClients,
			  DmaDebugIndication dmaIndication,
			  Vector#(numSGLs,Server#(ReqTup,Bit#(addrWidth))) sgls)
   (MemReadInternal#(addrWidth, dataWidth))

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

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: read commands
   BRAM2Port#(Bit#(TLog#(NumTags)), DRec#(numClients,addrWidth)) dreqFifos <- mkBRAM2Server(defaultValue);
   BRAM2Port#(Bit#(TAdd#(TLog#(NumTags),TSub#(8,beatShift))), ObjectData#(dataWidth)) read_buffer <- mkBRAM2Server(defaultValue);
   // stage 3: read data
   FIFO#(MemData#(dataWidth)) readDataPipelineFifo <- mkFIFO;

   let debug = False;

   Reg#(Bit#(8))           burstReg <- mkReg(0);
   Reg#(Bool)              firstReg <- mkReg(True);
   Reg#(Bool)               lastReg <- mkReg(False);
   Reg#(Bit#(64))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   TagGen#(NumTags) tag_gen <- mkTagGen;

   Reg#(Bit#(8))                 compReg0 <- mkReg(0);
   Reg#(Bit#(TLog#(NumTags)))    compReg1 <- mkReg(0);
   Reg#(Bit#(TLog#(numClients))) compReg2 <- mkReg(0);
   FIFO#(Bit#(TLog#(numClients)))compFifo0 <- mkFIFO;
   FIFO#(Bit#(TLog#(NumTags)))   compFifo1 <- mkFIFO;

   // performance analytics
   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_sglResp <- mkReg(0);
   Reg#(Bit#(64)) last_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();
      dmaIndication.error(extend(pack(error.errorType)), error.pref, 0, 0);
   endrule

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

   rule complete_burst0;
      let tag <- tag_gen.complete;
      dreqFifos.portB.request.put(BRAMRequest{write:False, address:tag});
      compFifo1.enq(tag);
   endrule

   rule complete_burst1a if (compReg0==0);
      let drq <- dreqFifos.portB.response.get;
      let cnt = drq.req.burstLen >> beat_shift;
      let cli = drq.client;
      let tag <- toGet(compFifo1).get;
      compFifo0.enq(cli);
      read_buffer.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}});
      compReg0 <= cnt-1;
      compReg1 <= tag;
      compReg2 <= cli;
   endrule

   rule complete_burst1b if (compReg0 > 0);
      let cnt = compReg0;
      let tag = compReg1;
      let cli = compReg2;
      compFifo0.enq(cli);
      read_buffer.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}});
      compReg0 <= cnt-1;
   endrule

   rule complete_burst2;
      let client <- toGet(compFifo0).get;
      let data <- read_buffer.portB.response.get;
      readClients[client].readData.put(data);
      if (debug) $display("mkMemReadInternal::comp %d  %x %d", client, data.data, cycle_cnt-last_comp);
      last_comp <= cycle_cnt;
   endrule

   rule checkSglResp;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let physAddr <- sgls[req.pointer[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      if (debug) $display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      if (debug) $display("mkMemReadInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      last_sglResp <= cycle_cnt;
   endrule

   rule read_data;
      let response <- toGet(readDataPipelineFifo).get();
      Bit#(6) response_tag = response.tag;
      let drq <- dreqFifos.portA.response.get;
      let req = drq.req;
      let burstLen = burstReg;
      let first =    firstReg;
      let last  =    lastReg;
      if (first) begin
	 burstLen = drq.req.burstLen >> beat_shift;
	 last = drq.last;
	 dynamicAssert(last == (burstLen==1), "Last incorrect");
	 //$display("burstLen=%d dreqFifo.first.last=%d last=%d\n", burstLen, dreqFifo.first.last, last);
      end
      Bit#(TLog#(NumTags)) tt = truncate(response_tag);
      read_buffer.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, datain:ObjectData{data: response.data, tag: req.tag, last: last}, address:{tt,truncate(burstLen)}});
      if (last) begin
	 tag_gen.returnTag(truncate(response_tag));
      end
      last_readData <= cycle_cnt;
      if (debug) $display("read_data %d", cycle_cnt-last_readData);
      burstReg <= burstLen-1;
      firstReg <= (burstLen-1 == 0);
      lastReg <= (burstLen-1 == 1);
   endrule

   interface MemReadClient read_client;
      interface Get readReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    reqFifo.deq;
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    if (False && physAddr[31:24] != 0)
	       $display("req_ar: funny physAddr req.pointer=%d req.offset=%h physAddr=%h", req.pointer, req.offset, physAddr);
	    dreqFifos.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(rename_tag), datain:DRec{req:req, client:client, rename_tag:rename_tag, last:(req.burstLen == fromInteger(valueOf(dataWidthBytes)))}});
	    //$display("readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", client,rename_tag,physAddr, req.burstLen, beat_shift, req.burstLen == beat_shift);
	    if (debug) $display("read_client.readReq %d", cycle_cnt-last_readReq);
	    last_readReq <= cycle_cnt;
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:rename_tag};
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(MemData#(dataWidth) response);
	    readDataPipelineFifo.enq(response);
	    dreqFifos.portA.request.put(BRAMRequest{write:False, address:truncate(response.tag)});
	    beatCount <= beatCount+1;
	 endmethod
      endinterface
   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 beatCount;
      endmethod
   endinterface
endmodule

typedef 64 NumTagsW;

module mkMemWriteInternal#(Vector#(numClients, ObjectWriteClient#(dataWidth)) writeClients,
			   DmaDebugIndication dmaIndication,
			   Vector#(numSGLs,Server#(ReqTup,Bit#(addrWidth))) sgls)
   (MemWriteInternal#(addrWidth, dataWidth))

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

   let debug = False;

   // stage 0: address translation (latency = SGL_PIPELINE_DEPTH)
   FIFO#(LRec#(numClients,addrWidth)) lreqFifo <- mkSizedFIFO(valueOf(SGL_PIPELINE_DEPTH));
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numClients,addrWidth))  reqFifo <- mkFIFO;
   // stage 2: write commands
   FIFO#(DRec#(numClients, addrWidth)) dreqFifo <- mkSizedBRAMFIFO(valueOf(NumTagsW));
   // stage 3: write data
   BRAM2Port#(Bit#(TLog#(NumTagsW)), RResp#(numClients,addrWidth)) respFifos <- mkBRAM2Server(defaultValue);
   TagGen#(NumTagsW) tag_gen <- mkTagGen;

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

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

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

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

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

   rule checkSglResp;
      let req = lreqFifo.first.req;
      let client = lreqFifo.first.client;
      let physAddr <- sgls[req.pointer[31:16]].response.get;
      let rename_tag <- tag_gen.getTag;
      lreqFifo.deq();
      reqFifo.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //if (debug) $display("checkSglResp: client=%d, rename_tag=%d", client,rename_tag);
      if (debug) $display("mkMemWriteInternal::sglResp %d %d", client, cycle_cnt-last_sglResp);
      last_sglResp <= cycle_cnt;
   endrule

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

   rule writeDoneComp1;
      let rv <- respFifos.portB.response.get;
      let client = rv.client;
      let orig_tag = rv.orig_tag;
      writeClients[client].writeDone.put(orig_tag);
   endrule

   FIFO#(MemData#(dataWidth)) memDataFifo <- mkFIFO();
   Vector#(numClients, FIFO#(ObjectData#(dataWidth))) clientWriteData <- replicateM(mkFIFO);
   // Pipeline client data:
   // The .get() operation seems to be long latency, so get it into a local FIFO
   for (Integer client = 0; client < valueOf(numClients); client = client + 1)
      rule clientdata;
	 let d <- writeClients[client].writeData.get();
	 clientWriteData[client].enq(d);
      endrule

   rule memdata;
      let client = dreqFifo.first.client;
      let req = dreqFifo.first.req;
      let rename_tag = dreqFifo.first.rename_tag;
      ObjectData#(dataWidth) tagdata <- toGet(clientWriteData[client]).get();
      let burstLen = burstReg;
      let first    = firstReg;
      let last     = lastReg;
      if (first) begin
	 burstLen = req.burstLen >> beat_shift;
	 last     = dreqFifo.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)
	 dreqFifo.deq();
      //$display("writeData: client=%d, rename_tag=%d", client, rename_tag);
      memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: last });
   endrule

   interface MemWriteClient write_client;
      interface Get writeReq;
	 method ActionValue#(MemRequest#(addrWidth)) get();
	    let req = reqFifo.first.req;
	    let physAddr = reqFifo.first.pa;
	    let client = reqFifo.first.client;
	    let rename_tag = reqFifo.first.rename_tag;
	    reqFifo.deq;
	    dreqFifo.enq(DRec{req:req, client:client, rename_tag:rename_tag, last: (req.burstLen == fromInteger(valueOf(dataWidthBytes))) });
	    //$display("writeReq: client=%d, rename_tag=%d", client,rename_tag);
	    return MemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)};
	 endmethod
      endinterface
      interface Get writeData = toGet(memDataFifo);
      interface Put writeDone;
	 method Action put(Bit#(6) resp);
	    tag_gen.returnTag(truncate(resp));
	    if (debug) $display("writeDone: resp=%d", resp);
	 endmethod
      endinterface
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
	 return DmaDbgRec{x:fromInteger(valueOf(numClients)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
	 return beatCount;
      endmethod
   endinterface
endmodule


use DmaAddrSize everywhere

use DmaAddrSize everywhere

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

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

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

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

import PortalMemory::*;
import PortalRMemory::*;
import GetPutF::*;

import RingTypes::*;
import RingBuffer::*;
import CopyEngine::*;
import EchoEngine::*;
import NopEngine::*;

interface RingRequest;
   method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(DmaAddrSize) addr);
   method Action get(Bit#(1) cmd, Bit#(2) regist);
   method Action hwenable(Bit#(1) en);
   method Action doCommandIndirect(Bit#(DmaAddrSize) addr);
   method Action doCommandImmediate(Bit#(64) data);
endinterface

interface RingIndication;
   method Action setResult(Bit#(1) cmd, Bit#(2) regist, Bit#(DmaAddrSize) addr);
   method Action getResult(Bit#(1) cmd, Bit#(2) regist, Bit#(DmaAddrSize) addr);
   method Action completion(Bit#(32) command, Bit#(32) tag);
endinterface

module mkRingRequest#(RingIndication indication,
		      DMAReadServer#(64) dma_read_chan,
		      DMAWriteServer#(64) dma_write_chan,
		      DMAReadServer#(64) cmd_read_chan,
		      DMAWriteServer#(64) status_write_chan )(RingRequest);
   DMAReadBuffer#(64,8) copy_read_chan <- mkDMAReadBuffer();
   DMAWriteBuffer#(64,8) copy_write_chan <- mkDMAWriteBuffer();

   ServerF#(Bit#(64), Bit#(64)) copyEngine <- mkCopyEngine(dma_read_chan, dma_write_chan);
   ServerF#(Bit#(64), Bit#(64)) nopEngine <- mkNopEngine();
   ServerF#(Bit#(64), Bit#(64)) echoEngine <- mkEchoEngine();

   RingBuffer cmdRing <- mkRingBuffer;
   RingBuffer statusRing <- mkRingBuffer;
   Reg#(Bool) hwenabled <- mkReg(False);
   Reg#(Bool) cmdBusy <- mkReg(False);
   Reg#(UInt#(64)) cmd <- mkReg(0);

   let engineselect = cmd[63:56];
   function Server#(Bit#(64), Bit#(64)) cmdifc();
      if (engineselect == cmdNOP)
	 return nopEngine;
      else if (engineselect == cmdCOPY)
	 return copyEngine;
      else if (engineselect == cmdECHO)
	 return echoServer;
      else
	 return nopEngine;
   endfunction

   Stmt cmdFetch =   seq
      while (True) seq
	 while(!(hwenabled && cmdRing.notEmpty())) noAction;
	 cmd_read_chan.readReq.put(cmdRing.expBufferLast);
	 cmdRing.pop();
      endseq
		     endseq;

   let fn = cmd[63:56];

   Stmt cmdDispatch =
   seq
      while (True) seq
	 cmd <= cmd_read_chan.readData.get();
	 cmdifc.put(cmd);
	 for (ii <= 1; ii < 8; ii <= ii + 1)
	    cmdifc.put(cmd_read_chan.readData.get());
      endseq
   endseq;

   Stmt cmdCompletion =
   seq
      while(True) seq
	 while(!(hwenabled && statusRing.notFull())) noAction;
      endseq
   endseq;

   Stmt responseArbiter =
   seq
      while(True) seq
	 if (statusRing.notFull() && copyEngine.response.notEmpty())
	    for (ii <= 1; ii < 8; ii <= ii + 1)
	       action
		  status_write_chan.writeReq.put(statusRing.expBufferFirst);
		  status_write_chan.writeData.put(copyEngine.get());
		  statusRing.push(8);
	       endaction
	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    for (ii <= 1; ii < 8; ii <= ii + 1)
	       action
		  status_write_chan.writeReq.put(statusRing.expBufferFirst);
		  status_write_chan.writeData.put(echoEngine.get());
		  statusRing.push(8);
	       endaction
      endseq
   endseq;

   rule copyCompletion;
      let v <- ce.response.get();
      indication.ringIndication.completion(1, v);
   endrule

   mkAutoFSM (cmdFetch);
   mkAutoFSM (cmdDispatch);
   mkAutoFSM (cmdCompletion);

   interface RingRequest ringRequest;

      // to start a command, doCommand fires off a memory read to the
      // specified address. when it comes back, the doCommandRule will
      // handle it
      method Action doCommandIndirect(Bit#(DmaAddrSize) addr);
	 //cmd_read_chan.readReq.put(addr);
      endmethod

      method Action doCommandImmediate(Bit#(64) data);
      	 $display("doCommandImmediate %h", data);
      endmethod

      method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(DmaAddrSize) addr);
	 if (cmd == 1)
	    cmdRing.set(regist, addr);
	 else
	    statusRing.set(regist, addr);
	 indication.ringIndication.setResult(cmd, regist, addr);
      endmethod

      method Action get(Bit#(1) cmd, Bit#(2) regist);
	 if (cmd == 1)
	    indication.ringIndication.getResult(1, regist, cmdRing.get(regist));
	 else
	    indication.ringIndication.getResult(0, regist,
	       statusRing.get(regist));
      endmethod

      method Action hwenable(Bit#(1) en);
	 hwenabled <= en == 1;
      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.

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

import PortalMemory::*;
import PortalRMemory::*;
import GetPutF::*;

import RingTypes::*;
import RingBuffer::*;
import CopyEngine::*;
import EchoEngine::*;
import NopEngine::*;

interface RingRequest;
   method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(40) addr);
   method Action get(Bit#(1) cmd, Bit#(2) regist);
   method Action hwenable(Bit#(1) en);
   method Action doCommandIndirect(Bit#(40) addr);
   method Action doCommandImmediate(Bit#(64) data);
endinterface

interface RingIndication;
   method Action setResult(Bit#(1) cmd, Bit#(2) regist, Bit#(40) addr);
   method Action getResult(Bit#(1) cmd, Bit#(2) regist, Bit#(40) addr);
   method Action completion(Bit#(32) command, Bit#(32) tag);
endinterface

module mkRingRequest#(RingIndication indication,
		      DMAReadServer#(64) dma_read_chan,
		      DMAWriteServer#(64) dma_write_chan,
		      DMAReadServer#(64) cmd_read_chan,
		      DMAWriteServer#(64) status_write_chan )(RingRequest);
   DMAReadBuffer#(64,8) copy_read_chan <- mkDMAReadBuffer();
   DMAWriteBuffer#(64,8) copy_write_chan <- mkDMAWriteBuffer();

   ServerF#(Bit#(64), Bit#(64)) copyEngine <- mkCopyEngine(dma_read_chan, dma_write_chan);
   ServerF#(Bit#(64), Bit#(64)) nopEngine <- mkNopEngine();
   ServerF#(Bit#(64), Bit#(64)) echoEngine <- mkEchoEngine();

   RingBuffer cmdRing <- mkRingBuffer;
   RingBuffer statusRing <- mkRingBuffer;
   Reg#(Bool) hwenabled <- mkReg(False);
   Reg#(Bool) cmdBusy <- mkReg(False);
   Reg#(UInt#(64)) cmd <- mkReg(0);

   let engineselect = cmd[63:56];
   function Server#(Bit#(64), Bit#(64)) cmdifc();
      if (engineselect == cmdNOP)
	 return nopEngine;
      else if (engineselect == cmdCOPY)
	 return copyEngine;
      else if (engineselect == cmdECHO)
	 return echoServer;
      else
	 return nopEngine;
   endfunction

   Stmt cmdFetch =   seq
      while (True) seq
	 while(!(hwenabled && cmdRing.notEmpty())) noAction;
	 cmd_read_chan.readReq.put(cmdRing.expBufferLast);
	 cmdRing.pop();
      endseq
		     endseq;

   let fn = cmd[63:56];

   Stmt cmdDispatch =
   seq
      while (True) seq
	 cmd <= cmd_read_chan.readData.get();
	 cmdifc.put(cmd);
	 for (ii <= 1; ii < 8; ii <= ii + 1)
	    cmdifc.put(cmd_read_chan.readData.get());
      endseq
   endseq;

   Stmt cmdCompletion =
   seq
      while(True) seq
	 while(!(hwenabled && statusRing.notFull())) noAction;
      endseq
   endseq;

   Stmt responseArbiter =
   seq
      while(True) seq
	 if (statusRing.notFull() && copyEngine.response.notEmpty())
	    for (ii <= 1; ii < 8; ii <= ii + 1)
	       action
		  status_write_chan.writeReq.put(statusRing.expBufferFirst);
		  status_write_chan.writeData.put(copyEngine.get());
		  statusRing.push(8);
	       endaction
	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    for (ii <= 1; ii < 8; ii <= ii + 1)
	       action
		  status_write_chan.writeReq.put(statusRing.expBufferFirst);
		  status_write_chan.writeData.put(echoEngine.get());
		  statusRing.push(8);
	       endaction
      endseq
   endseq;

   rule copyCompletion;
      let v <- ce.response.get();
      indication.ringIndication.completion(1, v);
   endrule

   mkAutoFSM (cmdFetch);
   mkAutoFSM (cmdDispatch);
   mkAutoFSM (cmdCompletion);

   interface RingRequest ringRequest;

      // to start a command, doCommand fires off a memory read to the
      // specified address. when it comes back, the doCommandRule will
      // handle it
      method Action doCommandIndirect(Bit#(40) addr);
	 //cmd_read_chan.readReq.put(addr);
      endmethod

      method Action doCommandImmediate(Bit#(64) data);
      	 $display("doCommandImmediate %h", data);
      endmethod

      method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(40) addr);
	 if (cmd == 1)
	    cmdRing.set(regist, addr);
	 else
	    statusRing.set(regist, addr);
	 indication.ringIndication.setResult(cmd, regist, addr);
      endmethod

      method Action get(Bit#(1) cmd, Bit#(2) regist);
	 if (cmd == 1)
	    indication.ringIndication.getResult(1, regist, cmdRing.get(regist));
	 else
	    indication.ringIndication.getResult(0, regist,
	       statusRing.get(regist));
      endmethod

      method Action hwenable(Bit#(1) en);
	 hwenabled <= en == 1;
      endmethod

   endinterface

endmodule